1a3ab7155SBob Copeland /* 2a3ab7155SBob Copeland * OMFS (as used by RIO Karma) directory operations. 3a3ab7155SBob Copeland * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com> 4a3ab7155SBob Copeland * Released under GPL v2. 5a3ab7155SBob Copeland */ 6a3ab7155SBob Copeland 7a3ab7155SBob Copeland #include <linux/fs.h> 8a3ab7155SBob Copeland #include <linux/ctype.h> 9a3ab7155SBob Copeland #include <linux/buffer_head.h> 10a3ab7155SBob Copeland #include "omfs.h" 11a3ab7155SBob Copeland 12a3ab7155SBob Copeland static int omfs_hash(const char *name, int namelen, int mod) 13a3ab7155SBob Copeland { 14a3ab7155SBob Copeland int i, hash = 0; 15a3ab7155SBob Copeland for (i = 0; i < namelen; i++) 16a3ab7155SBob Copeland hash ^= tolower(name[i]) << (i % 24); 17a3ab7155SBob Copeland return hash % mod; 18a3ab7155SBob Copeland } 19a3ab7155SBob Copeland 20a3ab7155SBob Copeland /* 21a3ab7155SBob Copeland * Finds the bucket for a given name and reads the containing block; 22a3ab7155SBob Copeland * *ofs is set to the offset of the first list entry. 23a3ab7155SBob Copeland */ 24a3ab7155SBob Copeland static struct buffer_head *omfs_get_bucket(struct inode *dir, 25a3ab7155SBob Copeland const char *name, int namelen, int *ofs) 26a3ab7155SBob Copeland { 27a3ab7155SBob Copeland int nbuckets = (dir->i_size - OMFS_DIR_START)/8; 28a3ab7155SBob Copeland int bucket = omfs_hash(name, namelen, nbuckets); 29a3ab7155SBob Copeland 30a3ab7155SBob Copeland *ofs = OMFS_DIR_START + bucket * 8; 31f068272cSBob Copeland return omfs_bread(dir->i_sb, dir->i_ino); 32a3ab7155SBob Copeland } 33a3ab7155SBob Copeland 34a3ab7155SBob Copeland static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, 35a3ab7155SBob Copeland const char *name, int namelen, 36a3ab7155SBob Copeland u64 *prev_block) 37a3ab7155SBob Copeland { 38a3ab7155SBob Copeland struct buffer_head *bh; 39a3ab7155SBob Copeland struct omfs_inode *oi; 40a3ab7155SBob Copeland int err = -ENOENT; 41a3ab7155SBob Copeland *prev_block = ~0; 42a3ab7155SBob Copeland 43a3ab7155SBob Copeland while (block != ~0) { 44f068272cSBob Copeland bh = omfs_bread(dir->i_sb, block); 45a3ab7155SBob Copeland if (!bh) { 46a3ab7155SBob Copeland err = -EIO; 47a3ab7155SBob Copeland goto err; 48a3ab7155SBob Copeland } 49a3ab7155SBob Copeland 50a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 51a3ab7155SBob Copeland if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) { 52a3ab7155SBob Copeland brelse(bh); 53a3ab7155SBob Copeland goto err; 54a3ab7155SBob Copeland } 55a3ab7155SBob Copeland 56a3ab7155SBob Copeland if (strncmp(oi->i_name, name, namelen) == 0) 57a3ab7155SBob Copeland return bh; 58a3ab7155SBob Copeland 59a3ab7155SBob Copeland *prev_block = block; 60a3ab7155SBob Copeland block = be64_to_cpu(oi->i_sibling); 61a3ab7155SBob Copeland brelse(bh); 62a3ab7155SBob Copeland } 63a3ab7155SBob Copeland err: 64a3ab7155SBob Copeland return ERR_PTR(err); 65a3ab7155SBob Copeland } 66a3ab7155SBob Copeland 67a3ab7155SBob Copeland static struct buffer_head *omfs_find_entry(struct inode *dir, 68a3ab7155SBob Copeland const char *name, int namelen) 69a3ab7155SBob Copeland { 70a3ab7155SBob Copeland struct buffer_head *bh; 71a3ab7155SBob Copeland int ofs; 72a3ab7155SBob Copeland u64 block, dummy; 73a3ab7155SBob Copeland 74a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 75a3ab7155SBob Copeland if (!bh) 76a3ab7155SBob Copeland return ERR_PTR(-EIO); 77a3ab7155SBob Copeland 78a3ab7155SBob Copeland block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs])); 79a3ab7155SBob Copeland brelse(bh); 80a3ab7155SBob Copeland 81a3ab7155SBob Copeland return omfs_scan_list(dir, block, name, namelen, &dummy); 82a3ab7155SBob Copeland } 83a3ab7155SBob Copeland 84a3ab7155SBob Copeland int omfs_make_empty(struct inode *inode, struct super_block *sb) 85a3ab7155SBob Copeland { 86a3ab7155SBob Copeland struct omfs_sb_info *sbi = OMFS_SB(sb); 87a3ab7155SBob Copeland struct buffer_head *bh; 88a3ab7155SBob Copeland struct omfs_inode *oi; 89a3ab7155SBob Copeland 90f068272cSBob Copeland bh = omfs_bread(sb, inode->i_ino); 91a3ab7155SBob Copeland if (!bh) 92a3ab7155SBob Copeland return -ENOMEM; 93a3ab7155SBob Copeland 94a3ab7155SBob Copeland memset(bh->b_data, 0, sizeof(struct omfs_inode)); 95a3ab7155SBob Copeland 9641c96486SAl Viro if (S_ISDIR(inode->i_mode)) { 97a3ab7155SBob Copeland memset(&bh->b_data[OMFS_DIR_START], 0xff, 98a3ab7155SBob Copeland sbi->s_sys_blocksize - OMFS_DIR_START); 99a3ab7155SBob Copeland } else 100a3ab7155SBob Copeland omfs_make_empty_table(bh, OMFS_EXTENT_START); 101a3ab7155SBob Copeland 102a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 103a3ab7155SBob Copeland oi->i_head.h_self = cpu_to_be64(inode->i_ino); 104d406f66dSHarvey Harrison oi->i_sibling = ~cpu_to_be64(0ULL); 105a3ab7155SBob Copeland 106a3ab7155SBob Copeland mark_buffer_dirty(bh); 107a3ab7155SBob Copeland brelse(bh); 108a3ab7155SBob Copeland return 0; 109a3ab7155SBob Copeland } 110a3ab7155SBob Copeland 111a3ab7155SBob Copeland static int omfs_add_link(struct dentry *dentry, struct inode *inode) 112a3ab7155SBob Copeland { 1132b0143b5SDavid Howells struct inode *dir = d_inode(dentry->d_parent); 114a3ab7155SBob Copeland const char *name = dentry->d_name.name; 115a3ab7155SBob Copeland int namelen = dentry->d_name.len; 116a3ab7155SBob Copeland struct omfs_inode *oi; 117a3ab7155SBob Copeland struct buffer_head *bh; 118a3ab7155SBob Copeland u64 block; 119a3ab7155SBob Copeland __be64 *entry; 120a3ab7155SBob Copeland int ofs; 121a3ab7155SBob Copeland 122a3ab7155SBob Copeland /* just prepend to head of queue in proper bucket */ 123a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 124a3ab7155SBob Copeland if (!bh) 125a3ab7155SBob Copeland goto out; 126a3ab7155SBob Copeland 127a3ab7155SBob Copeland entry = (__be64 *) &bh->b_data[ofs]; 128a3ab7155SBob Copeland block = be64_to_cpu(*entry); 129a3ab7155SBob Copeland *entry = cpu_to_be64(inode->i_ino); 130a3ab7155SBob Copeland mark_buffer_dirty(bh); 131a3ab7155SBob Copeland brelse(bh); 132a3ab7155SBob Copeland 133a3ab7155SBob Copeland /* now set the sibling and parent pointers on the new inode */ 134f068272cSBob Copeland bh = omfs_bread(dir->i_sb, inode->i_ino); 135a3ab7155SBob Copeland if (!bh) 136a3ab7155SBob Copeland goto out; 137a3ab7155SBob Copeland 138a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 139a3ab7155SBob Copeland memcpy(oi->i_name, name, namelen); 140a3ab7155SBob Copeland memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen); 141a3ab7155SBob Copeland oi->i_sibling = cpu_to_be64(block); 142a3ab7155SBob Copeland oi->i_parent = cpu_to_be64(dir->i_ino); 143a3ab7155SBob Copeland mark_buffer_dirty(bh); 144a3ab7155SBob Copeland brelse(bh); 145a3ab7155SBob Copeland 14602027d42SDeepa Dinamani dir->i_ctime = current_time(dir); 147a3ab7155SBob Copeland 148a3ab7155SBob Copeland /* mark affected inodes dirty to rebuild checksums */ 149a3ab7155SBob Copeland mark_inode_dirty(dir); 150a3ab7155SBob Copeland mark_inode_dirty(inode); 151a3ab7155SBob Copeland return 0; 152a3ab7155SBob Copeland out: 153a3ab7155SBob Copeland return -ENOMEM; 154a3ab7155SBob Copeland } 155a3ab7155SBob Copeland 156a3ab7155SBob Copeland static int omfs_delete_entry(struct dentry *dentry) 157a3ab7155SBob Copeland { 1582b0143b5SDavid Howells struct inode *dir = d_inode(dentry->d_parent); 159a3ab7155SBob Copeland struct inode *dirty; 160a3ab7155SBob Copeland const char *name = dentry->d_name.name; 161a3ab7155SBob Copeland int namelen = dentry->d_name.len; 162a3ab7155SBob Copeland struct omfs_inode *oi; 163a3ab7155SBob Copeland struct buffer_head *bh, *bh2; 164a3ab7155SBob Copeland __be64 *entry, next; 165a3ab7155SBob Copeland u64 block, prev; 166a3ab7155SBob Copeland int ofs; 167a3ab7155SBob Copeland int err = -ENOMEM; 168a3ab7155SBob Copeland 169a3ab7155SBob Copeland /* delete the proper node in the bucket's linked list */ 170a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 171a3ab7155SBob Copeland if (!bh) 172a3ab7155SBob Copeland goto out; 173a3ab7155SBob Copeland 174a3ab7155SBob Copeland entry = (__be64 *) &bh->b_data[ofs]; 175a3ab7155SBob Copeland block = be64_to_cpu(*entry); 176a3ab7155SBob Copeland 177a3ab7155SBob Copeland bh2 = omfs_scan_list(dir, block, name, namelen, &prev); 178a3ab7155SBob Copeland if (IS_ERR(bh2)) { 179a3ab7155SBob Copeland err = PTR_ERR(bh2); 180a3ab7155SBob Copeland goto out_free_bh; 181a3ab7155SBob Copeland } 182a3ab7155SBob Copeland 183a3ab7155SBob Copeland oi = (struct omfs_inode *) bh2->b_data; 184a3ab7155SBob Copeland next = oi->i_sibling; 185a3ab7155SBob Copeland brelse(bh2); 186a3ab7155SBob Copeland 187a3ab7155SBob Copeland if (prev != ~0) { 188a3ab7155SBob Copeland /* found in middle of list, get list ptr */ 189a3ab7155SBob Copeland brelse(bh); 190f068272cSBob Copeland bh = omfs_bread(dir->i_sb, prev); 191a3ab7155SBob Copeland if (!bh) 192a3ab7155SBob Copeland goto out; 193a3ab7155SBob Copeland 194a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 195a3ab7155SBob Copeland entry = &oi->i_sibling; 196a3ab7155SBob Copeland } 197a3ab7155SBob Copeland 198a3ab7155SBob Copeland *entry = next; 199a3ab7155SBob Copeland mark_buffer_dirty(bh); 200a3ab7155SBob Copeland 201a3ab7155SBob Copeland if (prev != ~0) { 202a3ab7155SBob Copeland dirty = omfs_iget(dir->i_sb, prev); 203a3ab7155SBob Copeland if (!IS_ERR(dirty)) { 204a3ab7155SBob Copeland mark_inode_dirty(dirty); 205a3ab7155SBob Copeland iput(dirty); 206a3ab7155SBob Copeland } 207a3ab7155SBob Copeland } 208a3ab7155SBob Copeland 209a3ab7155SBob Copeland err = 0; 210a3ab7155SBob Copeland out_free_bh: 211a3ab7155SBob Copeland brelse(bh); 212a3ab7155SBob Copeland out: 213a3ab7155SBob Copeland return err; 214a3ab7155SBob Copeland } 215a3ab7155SBob Copeland 216a3ab7155SBob Copeland static int omfs_dir_is_empty(struct inode *inode) 217a3ab7155SBob Copeland { 218a3ab7155SBob Copeland int nbuckets = (inode->i_size - OMFS_DIR_START) / 8; 219a3ab7155SBob Copeland struct buffer_head *bh; 220a3ab7155SBob Copeland u64 *ptr; 221a3ab7155SBob Copeland int i; 222a3ab7155SBob Copeland 223f068272cSBob Copeland bh = omfs_bread(inode->i_sb, inode->i_ino); 224a3ab7155SBob Copeland 225a3ab7155SBob Copeland if (!bh) 226a3ab7155SBob Copeland return 0; 227a3ab7155SBob Copeland 228a3ab7155SBob Copeland ptr = (u64 *) &bh->b_data[OMFS_DIR_START]; 229a3ab7155SBob Copeland 230a3ab7155SBob Copeland for (i = 0; i < nbuckets; i++, ptr++) 231a3ab7155SBob Copeland if (*ptr != ~0) 232a3ab7155SBob Copeland break; 233a3ab7155SBob Copeland 234a3ab7155SBob Copeland brelse(bh); 235a3ab7155SBob Copeland return *ptr != ~0; 236a3ab7155SBob Copeland } 237a3ab7155SBob Copeland 238d932805bSAl Viro static int omfs_remove(struct inode *dir, struct dentry *dentry) 239a3ab7155SBob Copeland { 2402b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 241d932805bSAl Viro int ret; 242d932805bSAl Viro 24379bf7c73SSage Weil 2448aaa0f54SSage Weil if (S_ISDIR(inode->i_mode) && 2458aaa0f54SSage Weil !omfs_dir_is_empty(inode)) 246d932805bSAl Viro return -ENOTEMPTY; 247a3ab7155SBob Copeland 248a3ab7155SBob Copeland ret = omfs_delete_entry(dentry); 249a3ab7155SBob Copeland if (ret) 250a3ab7155SBob Copeland return ret; 251a3ab7155SBob Copeland 252d932805bSAl Viro clear_nlink(inode); 253d932805bSAl Viro mark_inode_dirty(inode); 254d932805bSAl Viro mark_inode_dirty(dir); 255d932805bSAl Viro return 0; 256a3ab7155SBob Copeland } 257a3ab7155SBob Copeland 258587228beSAl Viro static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode) 259a3ab7155SBob Copeland { 260a3ab7155SBob Copeland int err; 261a3ab7155SBob Copeland struct inode *inode = omfs_new_inode(dir, mode); 262a3ab7155SBob Copeland 263a3ab7155SBob Copeland if (IS_ERR(inode)) 264a3ab7155SBob Copeland return PTR_ERR(inode); 265a3ab7155SBob Copeland 266a3ab7155SBob Copeland err = omfs_make_empty(inode, dir->i_sb); 267a3ab7155SBob Copeland if (err) 268a3ab7155SBob Copeland goto out_free_inode; 269a3ab7155SBob Copeland 270a3ab7155SBob Copeland err = omfs_add_link(dentry, inode); 271a3ab7155SBob Copeland if (err) 272a3ab7155SBob Copeland goto out_free_inode; 273a3ab7155SBob Copeland 274a3ab7155SBob Copeland d_instantiate(dentry, inode); 275a3ab7155SBob Copeland return 0; 276a3ab7155SBob Copeland 277a3ab7155SBob Copeland out_free_inode: 278a3ab7155SBob Copeland iput(inode); 279a3ab7155SBob Copeland return err; 280a3ab7155SBob Copeland } 281a3ab7155SBob Copeland 28218bb1db3SAl Viro static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 283a3ab7155SBob Copeland { 284a3ab7155SBob Copeland return omfs_add_node(dir, dentry, mode | S_IFDIR); 285a3ab7155SBob Copeland } 286a3ab7155SBob Copeland 2874acdaf27SAl Viro static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 288ebfc3b49SAl Viro bool excl) 289a3ab7155SBob Copeland { 290a3ab7155SBob Copeland return omfs_add_node(dir, dentry, mode | S_IFREG); 291a3ab7155SBob Copeland } 292a3ab7155SBob Copeland 293a3ab7155SBob Copeland static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, 29400cd8dd3SAl Viro unsigned int flags) 295a3ab7155SBob Copeland { 296a3ab7155SBob Copeland struct buffer_head *bh; 297a3ab7155SBob Copeland struct inode *inode = NULL; 298a3ab7155SBob Copeland 299a3ab7155SBob Copeland if (dentry->d_name.len > OMFS_NAMELEN) 300a3ab7155SBob Copeland return ERR_PTR(-ENAMETOOLONG); 301a3ab7155SBob Copeland 302a3ab7155SBob Copeland bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 303a3ab7155SBob Copeland if (!IS_ERR(bh)) { 304a3ab7155SBob Copeland struct omfs_inode *oi = (struct omfs_inode *)bh->b_data; 305a3ab7155SBob Copeland ino_t ino = be64_to_cpu(oi->i_head.h_self); 306a3ab7155SBob Copeland brelse(bh); 307a3ab7155SBob Copeland inode = omfs_iget(dir->i_sb, ino); 30818fbbfc2SAl Viro } else if (bh != ERR_PTR(-ENOENT)) { 30918fbbfc2SAl Viro inode = ERR_CAST(bh); 310a3ab7155SBob Copeland } 31118fbbfc2SAl Viro return d_splice_alias(inode, dentry); 312a3ab7155SBob Copeland } 313a3ab7155SBob Copeland 314a3ab7155SBob Copeland /* sanity check block's self pointer */ 315a3ab7155SBob Copeland int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, 316a3ab7155SBob Copeland u64 fsblock) 317a3ab7155SBob Copeland { 318a3ab7155SBob Copeland int is_bad; 319a3ab7155SBob Copeland u64 ino = be64_to_cpu(header->h_self); 320a3ab7155SBob Copeland is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) || 321a3ab7155SBob Copeland (ino > sbi->s_num_blocks)); 322a3ab7155SBob Copeland 323a3ab7155SBob Copeland if (is_bad) 324a3ab7155SBob Copeland printk(KERN_WARNING "omfs: bad hash chain detected\n"); 325a3ab7155SBob Copeland 326a3ab7155SBob Copeland return is_bad; 327a3ab7155SBob Copeland } 328a3ab7155SBob Copeland 3299fd4d059SAl Viro static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx, 330a3ab7155SBob Copeland u64 fsblock, int hindex) 331a3ab7155SBob Copeland { 332a3ab7155SBob Copeland /* follow chain in this bucket */ 333a3ab7155SBob Copeland while (fsblock != ~0) { 3349fd4d059SAl Viro struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock); 3359fd4d059SAl Viro struct omfs_inode *oi; 3369fd4d059SAl Viro u64 self; 3379fd4d059SAl Viro unsigned char d_type; 3389fd4d059SAl Viro 339a3ab7155SBob Copeland if (!bh) 3409fd4d059SAl Viro return true; 341a3ab7155SBob Copeland 342a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 343a3ab7155SBob Copeland if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { 344a3ab7155SBob Copeland brelse(bh); 3459fd4d059SAl Viro return true; 346a3ab7155SBob Copeland } 347a3ab7155SBob Copeland 348a3ab7155SBob Copeland self = fsblock; 349a3ab7155SBob Copeland fsblock = be64_to_cpu(oi->i_sibling); 350a3ab7155SBob Copeland 351a3ab7155SBob Copeland /* skip visited nodes */ 352a3ab7155SBob Copeland if (hindex) { 353a3ab7155SBob Copeland hindex--; 354a3ab7155SBob Copeland brelse(bh); 355a3ab7155SBob Copeland continue; 356a3ab7155SBob Copeland } 357a3ab7155SBob Copeland 358a3ab7155SBob Copeland d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; 359a3ab7155SBob Copeland 3609fd4d059SAl Viro if (!dir_emit(ctx, oi->i_name, 3619fd4d059SAl Viro strnlen(oi->i_name, OMFS_NAMELEN), 3629fd4d059SAl Viro self, d_type)) { 363a3ab7155SBob Copeland brelse(bh); 3649fd4d059SAl Viro return false; 365a3ab7155SBob Copeland } 3669fd4d059SAl Viro brelse(bh); 3679fd4d059SAl Viro ctx->pos++; 3689fd4d059SAl Viro } 3699fd4d059SAl Viro return true; 370a3ab7155SBob Copeland } 371a3ab7155SBob Copeland 372a3ab7155SBob Copeland static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, 373f03b8ad8SMiklos Szeredi struct inode *new_dir, struct dentry *new_dentry, 374f03b8ad8SMiklos Szeredi unsigned int flags) 375a3ab7155SBob Copeland { 3762b0143b5SDavid Howells struct inode *new_inode = d_inode(new_dentry); 3772b0143b5SDavid Howells struct inode *old_inode = d_inode(old_dentry); 378a3ab7155SBob Copeland int err; 379a3ab7155SBob Copeland 380f03b8ad8SMiklos Szeredi if (flags & ~RENAME_NOREPLACE) 381f03b8ad8SMiklos Szeredi return -EINVAL; 382f03b8ad8SMiklos Szeredi 383a3ab7155SBob Copeland if (new_inode) { 384a3ab7155SBob Copeland /* overwriting existing file/dir */ 385d932805bSAl Viro err = omfs_remove(new_dir, new_dentry); 386a3ab7155SBob Copeland if (err) 387a3ab7155SBob Copeland goto out; 388a3ab7155SBob Copeland } 389a3ab7155SBob Copeland 390a3ab7155SBob Copeland /* since omfs locates files by name, we need to unlink _before_ 391a3ab7155SBob Copeland * adding the new link or we won't find the old one */ 392cdb26496SAl Viro err = omfs_delete_entry(old_dentry); 393cdb26496SAl Viro if (err) 394a3ab7155SBob Copeland goto out; 395a3ab7155SBob Copeland 396cdb26496SAl Viro mark_inode_dirty(old_dir); 397a3ab7155SBob Copeland err = omfs_add_link(new_dentry, old_inode); 398a3ab7155SBob Copeland if (err) 399a3ab7155SBob Copeland goto out; 400a3ab7155SBob Copeland 40102027d42SDeepa Dinamani old_inode->i_ctime = current_time(old_inode); 402013e4f4aSAl Viro mark_inode_dirty(old_inode); 403a3ab7155SBob Copeland out: 404a3ab7155SBob Copeland return err; 405a3ab7155SBob Copeland } 406a3ab7155SBob Copeland 4079fd4d059SAl Viro static int omfs_readdir(struct file *file, struct dir_context *ctx) 408a3ab7155SBob Copeland { 4099fd4d059SAl Viro struct inode *dir = file_inode(file); 410a3ab7155SBob Copeland struct buffer_head *bh; 4119fd4d059SAl Viro __be64 *p; 412a3ab7155SBob Copeland unsigned int hchain, hindex; 413a3ab7155SBob Copeland int nbuckets; 414a3ab7155SBob Copeland 4159fd4d059SAl Viro if (ctx->pos >> 32) 4169fd4d059SAl Viro return -EINVAL; 417a3ab7155SBob Copeland 4189fd4d059SAl Viro if (ctx->pos < 1 << 20) { 4199fd4d059SAl Viro if (!dir_emit_dots(file, ctx)) 4209fd4d059SAl Viro return 0; 4219fd4d059SAl Viro ctx->pos = 1 << 20; 422a3ab7155SBob Copeland } 423a3ab7155SBob Copeland 424a3ab7155SBob Copeland nbuckets = (dir->i_size - OMFS_DIR_START) / 8; 425a3ab7155SBob Copeland 426a3ab7155SBob Copeland /* high 12 bits store bucket + 1 and low 20 bits store hash index */ 4279fd4d059SAl Viro hchain = (ctx->pos >> 20) - 1; 4289fd4d059SAl Viro hindex = ctx->pos & 0xfffff; 429a3ab7155SBob Copeland 430f068272cSBob Copeland bh = omfs_bread(dir->i_sb, dir->i_ino); 431a3ab7155SBob Copeland if (!bh) 4329fd4d059SAl Viro return -EINVAL; 433a3ab7155SBob Copeland 4349fd4d059SAl Viro p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain; 435a3ab7155SBob Copeland 4369fd4d059SAl Viro for (; hchain < nbuckets; hchain++) { 4379fd4d059SAl Viro __u64 fsblock = be64_to_cpu(*p++); 4389fd4d059SAl Viro if (!omfs_fill_chain(dir, ctx, fsblock, hindex)) 439a3ab7155SBob Copeland break; 4409fd4d059SAl Viro hindex = 0; 4419fd4d059SAl Viro ctx->pos = (hchain+2) << 20; 442a3ab7155SBob Copeland } 443a3ab7155SBob Copeland brelse(bh); 4449fd4d059SAl Viro return 0; 445a3ab7155SBob Copeland } 446a3ab7155SBob Copeland 4476e1d5dccSAlexey Dobriyan const struct inode_operations omfs_dir_inops = { 448a3ab7155SBob Copeland .lookup = omfs_lookup, 449a3ab7155SBob Copeland .mkdir = omfs_mkdir, 450a3ab7155SBob Copeland .rename = omfs_rename, 451a3ab7155SBob Copeland .create = omfs_create, 452d932805bSAl Viro .unlink = omfs_remove, 453d932805bSAl Viro .rmdir = omfs_remove, 454a3ab7155SBob Copeland }; 455a3ab7155SBob Copeland 456828c0950SAlexey Dobriyan const struct file_operations omfs_dir_operations = { 457a3ab7155SBob Copeland .read = generic_read_dir, 458c51da20cSAl Viro .iterate_shared = omfs_readdir, 4593222a3e5SChristoph Hellwig .llseek = generic_file_llseek, 460a3ab7155SBob Copeland }; 461