2 * OMFS (as used by RIO Karma) directory operations.
3 * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
4 * Released under GPL v2.
8 #include <linux/ctype.h>
9 #include <linux/buffer_head.h>
12 static int omfs_hash(const char *name
, int namelen
, int mod
)
15 for (i
= 0; i
< namelen
; i
++)
16 hash
^= tolower(name
[i
]) << (i
% 24);
21 * Finds the bucket for a given name and reads the containing block;
22 * *ofs is set to the offset of the first list entry.
24 static struct buffer_head
*omfs_get_bucket(struct inode
*dir
,
25 const char *name
, int namelen
, int *ofs
)
27 int nbuckets
= (dir
->i_size
- OMFS_DIR_START
)/8;
28 int block
= clus_to_blk(OMFS_SB(dir
->i_sb
), dir
->i_ino
);
29 int bucket
= omfs_hash(name
, namelen
, nbuckets
);
31 *ofs
= OMFS_DIR_START
+ bucket
* 8;
32 return sb_bread(dir
->i_sb
, block
);
35 static struct buffer_head
*omfs_scan_list(struct inode
*dir
, u64 block
,
36 const char *name
, int namelen
,
39 struct buffer_head
*bh
;
40 struct omfs_inode
*oi
;
45 bh
= sb_bread(dir
->i_sb
,
46 clus_to_blk(OMFS_SB(dir
->i_sb
), block
));
52 oi
= (struct omfs_inode
*) bh
->b_data
;
53 if (omfs_is_bad(OMFS_SB(dir
->i_sb
), &oi
->i_head
, block
)) {
58 if (strncmp(oi
->i_name
, name
, namelen
) == 0)
62 block
= be64_to_cpu(oi
->i_sibling
);
69 static struct buffer_head
*omfs_find_entry(struct inode
*dir
,
70 const char *name
, int namelen
)
72 struct buffer_head
*bh
;
76 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
80 block
= be64_to_cpu(*((__be64
*) &bh
->b_data
[ofs
]));
83 return omfs_scan_list(dir
, block
, name
, namelen
, &dummy
);
86 int omfs_make_empty(struct inode
*inode
, struct super_block
*sb
)
88 struct omfs_sb_info
*sbi
= OMFS_SB(sb
);
89 int block
= clus_to_blk(sbi
, inode
->i_ino
);
90 struct buffer_head
*bh
;
91 struct omfs_inode
*oi
;
93 bh
= sb_bread(sb
, block
);
97 memset(bh
->b_data
, 0, sizeof(struct omfs_inode
));
99 if (inode
->i_mode
& S_IFDIR
) {
100 memset(&bh
->b_data
[OMFS_DIR_START
], 0xff,
101 sbi
->s_sys_blocksize
- OMFS_DIR_START
);
103 omfs_make_empty_table(bh
, OMFS_EXTENT_START
);
105 oi
= (struct omfs_inode
*) bh
->b_data
;
106 oi
->i_head
.h_self
= cpu_to_be64(inode
->i_ino
);
107 oi
->i_sibling
= ~cpu_to_be64(0ULL);
109 mark_buffer_dirty(bh
);
114 static int omfs_add_link(struct dentry
*dentry
, struct inode
*inode
)
116 struct inode
*dir
= dentry
->d_parent
->d_inode
;
117 const char *name
= dentry
->d_name
.name
;
118 int namelen
= dentry
->d_name
.len
;
119 struct omfs_inode
*oi
;
120 struct buffer_head
*bh
;
125 /* just prepend to head of queue in proper bucket */
126 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
130 entry
= (__be64
*) &bh
->b_data
[ofs
];
131 block
= be64_to_cpu(*entry
);
132 *entry
= cpu_to_be64(inode
->i_ino
);
133 mark_buffer_dirty(bh
);
136 /* now set the sibling and parent pointers on the new inode */
137 bh
= sb_bread(dir
->i_sb
, clus_to_blk(OMFS_SB(dir
->i_sb
), inode
->i_ino
));
141 oi
= (struct omfs_inode
*) bh
->b_data
;
142 memcpy(oi
->i_name
, name
, namelen
);
143 memset(oi
->i_name
+ namelen
, 0, OMFS_NAMELEN
- namelen
);
144 oi
->i_sibling
= cpu_to_be64(block
);
145 oi
->i_parent
= cpu_to_be64(dir
->i_ino
);
146 mark_buffer_dirty(bh
);
149 dir
->i_ctime
= CURRENT_TIME_SEC
;
151 /* mark affected inodes dirty to rebuild checksums */
152 mark_inode_dirty(dir
);
153 mark_inode_dirty(inode
);
159 static int omfs_delete_entry(struct dentry
*dentry
)
161 struct inode
*dir
= dentry
->d_parent
->d_inode
;
163 const char *name
= dentry
->d_name
.name
;
164 int namelen
= dentry
->d_name
.len
;
165 struct omfs_inode
*oi
;
166 struct buffer_head
*bh
, *bh2
;
172 /* delete the proper node in the bucket's linked list */
173 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
177 entry
= (__be64
*) &bh
->b_data
[ofs
];
178 block
= be64_to_cpu(*entry
);
180 bh2
= omfs_scan_list(dir
, block
, name
, namelen
, &prev
);
186 oi
= (struct omfs_inode
*) bh2
->b_data
;
187 next
= oi
->i_sibling
;
191 /* found in middle of list, get list ptr */
193 bh
= sb_bread(dir
->i_sb
,
194 clus_to_blk(OMFS_SB(dir
->i_sb
), prev
));
198 oi
= (struct omfs_inode
*) bh
->b_data
;
199 entry
= &oi
->i_sibling
;
203 mark_buffer_dirty(bh
);
206 dirty
= omfs_iget(dir
->i_sb
, prev
);
207 if (!IS_ERR(dirty
)) {
208 mark_inode_dirty(dirty
);
220 static int omfs_dir_is_empty(struct inode
*inode
)
222 int nbuckets
= (inode
->i_size
- OMFS_DIR_START
) / 8;
223 struct buffer_head
*bh
;
227 bh
= sb_bread(inode
->i_sb
, clus_to_blk(OMFS_SB(inode
->i_sb
),
233 ptr
= (u64
*) &bh
->b_data
[OMFS_DIR_START
];
235 for (i
= 0; i
< nbuckets
; i
++, ptr
++)
243 static int omfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
246 struct inode
*inode
= dentry
->d_inode
;
248 ret
= omfs_delete_entry(dentry
);
252 inode_dec_link_count(inode
);
253 mark_inode_dirty(dir
);
259 static int omfs_rmdir(struct inode
*dir
, struct dentry
*dentry
)
261 int err
= -ENOTEMPTY
;
262 struct inode
*inode
= dentry
->d_inode
;
264 if (omfs_dir_is_empty(inode
)) {
265 err
= omfs_unlink(dir
, dentry
);
267 inode_dec_link_count(inode
);
272 static int omfs_add_node(struct inode
*dir
, struct dentry
*dentry
, int mode
)
275 struct inode
*inode
= omfs_new_inode(dir
, mode
);
278 return PTR_ERR(inode
);
280 err
= omfs_make_empty(inode
, dir
->i_sb
);
284 err
= omfs_add_link(dentry
, inode
);
288 d_instantiate(dentry
, inode
);
296 static int omfs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
)
298 return omfs_add_node(dir
, dentry
, mode
| S_IFDIR
);
301 static int omfs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
302 struct nameidata
*nd
)
304 return omfs_add_node(dir
, dentry
, mode
| S_IFREG
);
307 static struct dentry
*omfs_lookup(struct inode
*dir
, struct dentry
*dentry
,
308 struct nameidata
*nd
)
310 struct buffer_head
*bh
;
311 struct inode
*inode
= NULL
;
313 if (dentry
->d_name
.len
> OMFS_NAMELEN
)
314 return ERR_PTR(-ENAMETOOLONG
);
316 bh
= omfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
);
318 struct omfs_inode
*oi
= (struct omfs_inode
*)bh
->b_data
;
319 ino_t ino
= be64_to_cpu(oi
->i_head
.h_self
);
321 inode
= omfs_iget(dir
->i_sb
, ino
);
323 return ERR_CAST(inode
);
325 d_add(dentry
, inode
);
329 /* sanity check block's self pointer */
330 int omfs_is_bad(struct omfs_sb_info
*sbi
, struct omfs_header
*header
,
334 u64 ino
= be64_to_cpu(header
->h_self
);
335 is_bad
= ((ino
!= fsblock
) || (ino
< sbi
->s_root_ino
) ||
336 (ino
> sbi
->s_num_blocks
));
339 printk(KERN_WARNING
"omfs: bad hash chain detected\n");
344 static int omfs_fill_chain(struct file
*filp
, void *dirent
, filldir_t filldir
,
345 u64 fsblock
, int hindex
)
347 struct inode
*dir
= filp
->f_dentry
->d_inode
;
348 struct buffer_head
*bh
;
349 struct omfs_inode
*oi
;
352 unsigned char d_type
;
354 /* follow chain in this bucket */
355 while (fsblock
!= ~0) {
356 bh
= sb_bread(dir
->i_sb
, clus_to_blk(OMFS_SB(dir
->i_sb
),
361 oi
= (struct omfs_inode
*) bh
->b_data
;
362 if (omfs_is_bad(OMFS_SB(dir
->i_sb
), &oi
->i_head
, fsblock
)) {
368 fsblock
= be64_to_cpu(oi
->i_sibling
);
370 /* skip visited nodes */
377 d_type
= (oi
->i_type
== OMFS_DIR
) ? DT_DIR
: DT_REG
;
379 res
= filldir(dirent
, oi
->i_name
, strnlen(oi
->i_name
,
380 OMFS_NAMELEN
), filp
->f_pos
, self
, d_type
);
389 static int omfs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
390 struct inode
*new_dir
, struct dentry
*new_dentry
)
392 struct inode
*new_inode
= new_dentry
->d_inode
;
393 struct inode
*old_inode
= old_dentry
->d_inode
;
394 struct buffer_head
*bh
;
398 is_dir
= S_ISDIR(old_inode
->i_mode
);
401 /* overwriting existing file/dir */
403 if (is_dir
&& !omfs_dir_is_empty(new_inode
))
407 bh
= omfs_find_entry(new_dir
, new_dentry
->d_name
.name
,
408 new_dentry
->d_name
.len
);
413 err
= omfs_unlink(new_dir
, new_dentry
);
418 /* since omfs locates files by name, we need to unlink _before_
419 * adding the new link or we won't find the old one */
420 inode_inc_link_count(old_inode
);
421 err
= omfs_unlink(old_dir
, old_dentry
);
423 inode_dec_link_count(old_inode
);
427 err
= omfs_add_link(new_dentry
, old_inode
);
431 old_inode
->i_ctime
= CURRENT_TIME_SEC
;
436 static int omfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
438 struct inode
*dir
= filp
->f_dentry
->d_inode
;
439 struct buffer_head
*bh
;
441 unsigned int hchain
, hindex
;
446 if (filp
->f_pos
>> 32)
449 switch ((unsigned long) filp
->f_pos
) {
451 if (filldir(dirent
, ".", 1, 0, dir
->i_ino
, DT_DIR
) < 0)
456 if (filldir(dirent
, "..", 2, 1,
457 parent_ino(filp
->f_dentry
), DT_DIR
) < 0)
459 filp
->f_pos
= 1 << 20;
463 nbuckets
= (dir
->i_size
- OMFS_DIR_START
) / 8;
465 /* high 12 bits store bucket + 1 and low 20 bits store hash index */
466 hchain
= (filp
->f_pos
>> 20) - 1;
467 hindex
= filp
->f_pos
& 0xfffff;
469 bh
= sb_bread(dir
->i_sb
, clus_to_blk(OMFS_SB(dir
->i_sb
), dir
->i_ino
));
473 offset
= OMFS_DIR_START
+ hchain
* 8;
475 for (; hchain
< nbuckets
; hchain
++, offset
+= 8) {
476 fsblock
= be64_to_cpu(*((__be64
*) &bh
->b_data
[offset
]));
478 res
= omfs_fill_chain(filp
, dirent
, filldir
, fsblock
, hindex
);
483 filp
->f_pos
= (hchain
+2) << 20;
492 const struct inode_operations omfs_dir_inops
= {
493 .lookup
= omfs_lookup
,
495 .rename
= omfs_rename
,
496 .create
= omfs_create
,
497 .unlink
= omfs_unlink
,
501 const struct file_operations omfs_dir_operations
= {
502 .read
= generic_read_dir
,
503 .readdir
= omfs_readdir
,
504 .llseek
= generic_file_llseek
,