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 bucket
= omfs_hash(name
, namelen
, nbuckets
);
30 *ofs
= OMFS_DIR_START
+ bucket
* 8;
31 return omfs_bread(dir
->i_sb
, dir
->i_ino
);
34 static struct buffer_head
*omfs_scan_list(struct inode
*dir
, u64 block
,
35 const char *name
, int namelen
,
38 struct buffer_head
*bh
;
39 struct omfs_inode
*oi
;
44 bh
= omfs_bread(dir
->i_sb
, block
);
50 oi
= (struct omfs_inode
*) bh
->b_data
;
51 if (omfs_is_bad(OMFS_SB(dir
->i_sb
), &oi
->i_head
, block
)) {
56 if (strncmp(oi
->i_name
, name
, namelen
) == 0)
60 block
= be64_to_cpu(oi
->i_sibling
);
67 static struct buffer_head
*omfs_find_entry(struct inode
*dir
,
68 const char *name
, int namelen
)
70 struct buffer_head
*bh
;
74 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
78 block
= be64_to_cpu(*((__be64
*) &bh
->b_data
[ofs
]));
81 return omfs_scan_list(dir
, block
, name
, namelen
, &dummy
);
84 int omfs_make_empty(struct inode
*inode
, struct super_block
*sb
)
86 struct omfs_sb_info
*sbi
= OMFS_SB(sb
);
87 struct buffer_head
*bh
;
88 struct omfs_inode
*oi
;
90 bh
= omfs_bread(sb
, inode
->i_ino
);
94 memset(bh
->b_data
, 0, sizeof(struct omfs_inode
));
96 if (inode
->i_mode
& S_IFDIR
) {
97 memset(&bh
->b_data
[OMFS_DIR_START
], 0xff,
98 sbi
->s_sys_blocksize
- OMFS_DIR_START
);
100 omfs_make_empty_table(bh
, OMFS_EXTENT_START
);
102 oi
= (struct omfs_inode
*) bh
->b_data
;
103 oi
->i_head
.h_self
= cpu_to_be64(inode
->i_ino
);
104 oi
->i_sibling
= ~cpu_to_be64(0ULL);
106 mark_buffer_dirty(bh
);
111 static int omfs_add_link(struct dentry
*dentry
, struct inode
*inode
)
113 struct inode
*dir
= dentry
->d_parent
->d_inode
;
114 const char *name
= dentry
->d_name
.name
;
115 int namelen
= dentry
->d_name
.len
;
116 struct omfs_inode
*oi
;
117 struct buffer_head
*bh
;
122 /* just prepend to head of queue in proper bucket */
123 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
127 entry
= (__be64
*) &bh
->b_data
[ofs
];
128 block
= be64_to_cpu(*entry
);
129 *entry
= cpu_to_be64(inode
->i_ino
);
130 mark_buffer_dirty(bh
);
133 /* now set the sibling and parent pointers on the new inode */
134 bh
= omfs_bread(dir
->i_sb
, inode
->i_ino
);
138 oi
= (struct omfs_inode
*) bh
->b_data
;
139 memcpy(oi
->i_name
, name
, namelen
);
140 memset(oi
->i_name
+ namelen
, 0, OMFS_NAMELEN
- namelen
);
141 oi
->i_sibling
= cpu_to_be64(block
);
142 oi
->i_parent
= cpu_to_be64(dir
->i_ino
);
143 mark_buffer_dirty(bh
);
146 dir
->i_ctime
= CURRENT_TIME_SEC
;
148 /* mark affected inodes dirty to rebuild checksums */
149 mark_inode_dirty(dir
);
150 mark_inode_dirty(inode
);
156 static int omfs_delete_entry(struct dentry
*dentry
)
158 struct inode
*dir
= dentry
->d_parent
->d_inode
;
160 const char *name
= dentry
->d_name
.name
;
161 int namelen
= dentry
->d_name
.len
;
162 struct omfs_inode
*oi
;
163 struct buffer_head
*bh
, *bh2
;
169 /* delete the proper node in the bucket's linked list */
170 bh
= omfs_get_bucket(dir
, name
, namelen
, &ofs
);
174 entry
= (__be64
*) &bh
->b_data
[ofs
];
175 block
= be64_to_cpu(*entry
);
177 bh2
= omfs_scan_list(dir
, block
, name
, namelen
, &prev
);
183 oi
= (struct omfs_inode
*) bh2
->b_data
;
184 next
= oi
->i_sibling
;
188 /* found in middle of list, get list ptr */
190 bh
= omfs_bread(dir
->i_sb
, prev
);
194 oi
= (struct omfs_inode
*) bh
->b_data
;
195 entry
= &oi
->i_sibling
;
199 mark_buffer_dirty(bh
);
202 dirty
= omfs_iget(dir
->i_sb
, prev
);
203 if (!IS_ERR(dirty
)) {
204 mark_inode_dirty(dirty
);
216 static int omfs_dir_is_empty(struct inode
*inode
)
218 int nbuckets
= (inode
->i_size
- OMFS_DIR_START
) / 8;
219 struct buffer_head
*bh
;
223 bh
= omfs_bread(inode
->i_sb
, inode
->i_ino
);
228 ptr
= (u64
*) &bh
->b_data
[OMFS_DIR_START
];
230 for (i
= 0; i
< nbuckets
; i
++, ptr
++)
238 static int omfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
241 struct inode
*inode
= dentry
->d_inode
;
243 ret
= omfs_delete_entry(dentry
);
247 inode_dec_link_count(inode
);
248 mark_inode_dirty(dir
);
254 static int omfs_rmdir(struct inode
*dir
, struct dentry
*dentry
)
256 int err
= -ENOTEMPTY
;
257 struct inode
*inode
= dentry
->d_inode
;
259 if (omfs_dir_is_empty(inode
)) {
260 err
= omfs_unlink(dir
, dentry
);
262 inode_dec_link_count(inode
);
267 static int omfs_add_node(struct inode
*dir
, struct dentry
*dentry
, int mode
)
270 struct inode
*inode
= omfs_new_inode(dir
, mode
);
273 return PTR_ERR(inode
);
275 err
= omfs_make_empty(inode
, dir
->i_sb
);
279 err
= omfs_add_link(dentry
, inode
);
283 d_instantiate(dentry
, inode
);
291 static int omfs_mkdir(struct inode
*dir
, struct dentry
*dentry
, int mode
)
293 return omfs_add_node(dir
, dentry
, mode
| S_IFDIR
);
296 static int omfs_create(struct inode
*dir
, struct dentry
*dentry
, int mode
,
297 struct nameidata
*nd
)
299 return omfs_add_node(dir
, dentry
, mode
| S_IFREG
);
302 static struct dentry
*omfs_lookup(struct inode
*dir
, struct dentry
*dentry
,
303 struct nameidata
*nd
)
305 struct buffer_head
*bh
;
306 struct inode
*inode
= NULL
;
308 if (dentry
->d_name
.len
> OMFS_NAMELEN
)
309 return ERR_PTR(-ENAMETOOLONG
);
311 bh
= omfs_find_entry(dir
, dentry
->d_name
.name
, dentry
->d_name
.len
);
313 struct omfs_inode
*oi
= (struct omfs_inode
*)bh
->b_data
;
314 ino_t ino
= be64_to_cpu(oi
->i_head
.h_self
);
316 inode
= omfs_iget(dir
->i_sb
, ino
);
318 return ERR_CAST(inode
);
320 d_add(dentry
, inode
);
324 /* sanity check block's self pointer */
325 int omfs_is_bad(struct omfs_sb_info
*sbi
, struct omfs_header
*header
,
329 u64 ino
= be64_to_cpu(header
->h_self
);
330 is_bad
= ((ino
!= fsblock
) || (ino
< sbi
->s_root_ino
) ||
331 (ino
> sbi
->s_num_blocks
));
334 printk(KERN_WARNING
"omfs: bad hash chain detected\n");
339 static int omfs_fill_chain(struct file
*filp
, void *dirent
, filldir_t filldir
,
340 u64 fsblock
, int hindex
)
342 struct inode
*dir
= filp
->f_dentry
->d_inode
;
343 struct buffer_head
*bh
;
344 struct omfs_inode
*oi
;
347 unsigned char d_type
;
349 /* follow chain in this bucket */
350 while (fsblock
!= ~0) {
351 bh
= omfs_bread(dir
->i_sb
, fsblock
);
355 oi
= (struct omfs_inode
*) bh
->b_data
;
356 if (omfs_is_bad(OMFS_SB(dir
->i_sb
), &oi
->i_head
, fsblock
)) {
362 fsblock
= be64_to_cpu(oi
->i_sibling
);
364 /* skip visited nodes */
371 d_type
= (oi
->i_type
== OMFS_DIR
) ? DT_DIR
: DT_REG
;
373 res
= filldir(dirent
, oi
->i_name
, strnlen(oi
->i_name
,
374 OMFS_NAMELEN
), filp
->f_pos
, self
, d_type
);
383 static int omfs_rename(struct inode
*old_dir
, struct dentry
*old_dentry
,
384 struct inode
*new_dir
, struct dentry
*new_dentry
)
386 struct inode
*new_inode
= new_dentry
->d_inode
;
387 struct inode
*old_inode
= old_dentry
->d_inode
;
388 struct buffer_head
*bh
;
392 is_dir
= S_ISDIR(old_inode
->i_mode
);
395 /* overwriting existing file/dir */
397 if (is_dir
&& !omfs_dir_is_empty(new_inode
))
401 bh
= omfs_find_entry(new_dir
, new_dentry
->d_name
.name
,
402 new_dentry
->d_name
.len
);
407 err
= omfs_unlink(new_dir
, new_dentry
);
412 /* since omfs locates files by name, we need to unlink _before_
413 * adding the new link or we won't find the old one */
414 inode_inc_link_count(old_inode
);
415 err
= omfs_unlink(old_dir
, old_dentry
);
417 inode_dec_link_count(old_inode
);
421 err
= omfs_add_link(new_dentry
, old_inode
);
425 old_inode
->i_ctime
= CURRENT_TIME_SEC
;
430 static int omfs_readdir(struct file
*filp
, void *dirent
, filldir_t filldir
)
432 struct inode
*dir
= filp
->f_dentry
->d_inode
;
433 struct buffer_head
*bh
;
435 unsigned int hchain
, hindex
;
440 if (filp
->f_pos
>> 32)
443 switch ((unsigned long) filp
->f_pos
) {
445 if (filldir(dirent
, ".", 1, 0, dir
->i_ino
, DT_DIR
) < 0)
450 if (filldir(dirent
, "..", 2, 1,
451 parent_ino(filp
->f_dentry
), DT_DIR
) < 0)
453 filp
->f_pos
= 1 << 20;
457 nbuckets
= (dir
->i_size
- OMFS_DIR_START
) / 8;
459 /* high 12 bits store bucket + 1 and low 20 bits store hash index */
460 hchain
= (filp
->f_pos
>> 20) - 1;
461 hindex
= filp
->f_pos
& 0xfffff;
463 bh
= omfs_bread(dir
->i_sb
, dir
->i_ino
);
467 offset
= OMFS_DIR_START
+ hchain
* 8;
469 for (; hchain
< nbuckets
; hchain
++, offset
+= 8) {
470 fsblock
= be64_to_cpu(*((__be64
*) &bh
->b_data
[offset
]));
472 res
= omfs_fill_chain(filp
, dirent
, filldir
, fsblock
, hindex
);
477 filp
->f_pos
= (hchain
+2) << 20;
486 const struct inode_operations omfs_dir_inops
= {
487 .lookup
= omfs_lookup
,
489 .rename
= omfs_rename
,
490 .create
= omfs_create
,
491 .unlink
= omfs_unlink
,
495 const struct file_operations omfs_dir_operations
= {
496 .read
= generic_read_dir
,
497 .readdir
= omfs_readdir
,
498 .llseek
= generic_file_llseek
,