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 block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino); 29a3ab7155SBob Copeland int bucket = omfs_hash(name, namelen, nbuckets); 30a3ab7155SBob Copeland 31a3ab7155SBob Copeland *ofs = OMFS_DIR_START + bucket * 8; 32a3ab7155SBob Copeland return sb_bread(dir->i_sb, block); 33a3ab7155SBob Copeland } 34a3ab7155SBob Copeland 35a3ab7155SBob Copeland static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, 36a3ab7155SBob Copeland const char *name, int namelen, 37a3ab7155SBob Copeland u64 *prev_block) 38a3ab7155SBob Copeland { 39a3ab7155SBob Copeland struct buffer_head *bh; 40a3ab7155SBob Copeland struct omfs_inode *oi; 41a3ab7155SBob Copeland int err = -ENOENT; 42a3ab7155SBob Copeland *prev_block = ~0; 43a3ab7155SBob Copeland 44a3ab7155SBob Copeland while (block != ~0) { 45a3ab7155SBob Copeland bh = sb_bread(dir->i_sb, 46a3ab7155SBob Copeland clus_to_blk(OMFS_SB(dir->i_sb), block)); 47a3ab7155SBob Copeland if (!bh) { 48a3ab7155SBob Copeland err = -EIO; 49a3ab7155SBob Copeland goto err; 50a3ab7155SBob Copeland } 51a3ab7155SBob Copeland 52a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 53a3ab7155SBob Copeland if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) { 54a3ab7155SBob Copeland brelse(bh); 55a3ab7155SBob Copeland goto err; 56a3ab7155SBob Copeland } 57a3ab7155SBob Copeland 58a3ab7155SBob Copeland if (strncmp(oi->i_name, name, namelen) == 0) 59a3ab7155SBob Copeland return bh; 60a3ab7155SBob Copeland 61a3ab7155SBob Copeland *prev_block = block; 62a3ab7155SBob Copeland block = be64_to_cpu(oi->i_sibling); 63a3ab7155SBob Copeland brelse(bh); 64a3ab7155SBob Copeland } 65a3ab7155SBob Copeland err: 66a3ab7155SBob Copeland return ERR_PTR(err); 67a3ab7155SBob Copeland } 68a3ab7155SBob Copeland 69a3ab7155SBob Copeland static struct buffer_head *omfs_find_entry(struct inode *dir, 70a3ab7155SBob Copeland const char *name, int namelen) 71a3ab7155SBob Copeland { 72a3ab7155SBob Copeland struct buffer_head *bh; 73a3ab7155SBob Copeland int ofs; 74a3ab7155SBob Copeland u64 block, dummy; 75a3ab7155SBob Copeland 76a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 77a3ab7155SBob Copeland if (!bh) 78a3ab7155SBob Copeland return ERR_PTR(-EIO); 79a3ab7155SBob Copeland 80a3ab7155SBob Copeland block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs])); 81a3ab7155SBob Copeland brelse(bh); 82a3ab7155SBob Copeland 83a3ab7155SBob Copeland return omfs_scan_list(dir, block, name, namelen, &dummy); 84a3ab7155SBob Copeland } 85a3ab7155SBob Copeland 86a3ab7155SBob Copeland int omfs_make_empty(struct inode *inode, struct super_block *sb) 87a3ab7155SBob Copeland { 88a3ab7155SBob Copeland struct omfs_sb_info *sbi = OMFS_SB(sb); 89a3ab7155SBob Copeland int block = clus_to_blk(sbi, inode->i_ino); 90a3ab7155SBob Copeland struct buffer_head *bh; 91a3ab7155SBob Copeland struct omfs_inode *oi; 92a3ab7155SBob Copeland 93a3ab7155SBob Copeland bh = sb_bread(sb, block); 94a3ab7155SBob Copeland if (!bh) 95a3ab7155SBob Copeland return -ENOMEM; 96a3ab7155SBob Copeland 97a3ab7155SBob Copeland memset(bh->b_data, 0, sizeof(struct omfs_inode)); 98a3ab7155SBob Copeland 99a3ab7155SBob Copeland if (inode->i_mode & S_IFDIR) { 100a3ab7155SBob Copeland memset(&bh->b_data[OMFS_DIR_START], 0xff, 101a3ab7155SBob Copeland sbi->s_sys_blocksize - OMFS_DIR_START); 102a3ab7155SBob Copeland } else 103a3ab7155SBob Copeland omfs_make_empty_table(bh, OMFS_EXTENT_START); 104a3ab7155SBob Copeland 105a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 106a3ab7155SBob Copeland oi->i_head.h_self = cpu_to_be64(inode->i_ino); 107d406f66dSHarvey Harrison oi->i_sibling = ~cpu_to_be64(0ULL); 108a3ab7155SBob Copeland 109a3ab7155SBob Copeland mark_buffer_dirty(bh); 110a3ab7155SBob Copeland brelse(bh); 111a3ab7155SBob Copeland return 0; 112a3ab7155SBob Copeland } 113a3ab7155SBob Copeland 114a3ab7155SBob Copeland static int omfs_add_link(struct dentry *dentry, struct inode *inode) 115a3ab7155SBob Copeland { 116a3ab7155SBob Copeland struct inode *dir = dentry->d_parent->d_inode; 117a3ab7155SBob Copeland const char *name = dentry->d_name.name; 118a3ab7155SBob Copeland int namelen = dentry->d_name.len; 119a3ab7155SBob Copeland struct omfs_inode *oi; 120a3ab7155SBob Copeland struct buffer_head *bh; 121a3ab7155SBob Copeland u64 block; 122a3ab7155SBob Copeland __be64 *entry; 123a3ab7155SBob Copeland int ofs; 124a3ab7155SBob Copeland 125a3ab7155SBob Copeland /* just prepend to head of queue in proper bucket */ 126a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 127a3ab7155SBob Copeland if (!bh) 128a3ab7155SBob Copeland goto out; 129a3ab7155SBob Copeland 130a3ab7155SBob Copeland entry = (__be64 *) &bh->b_data[ofs]; 131a3ab7155SBob Copeland block = be64_to_cpu(*entry); 132a3ab7155SBob Copeland *entry = cpu_to_be64(inode->i_ino); 133a3ab7155SBob Copeland mark_buffer_dirty(bh); 134a3ab7155SBob Copeland brelse(bh); 135a3ab7155SBob Copeland 136a3ab7155SBob Copeland /* now set the sibling and parent pointers on the new inode */ 137a3ab7155SBob Copeland bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino)); 138a3ab7155SBob Copeland if (!bh) 139a3ab7155SBob Copeland goto out; 140a3ab7155SBob Copeland 141a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 142a3ab7155SBob Copeland memcpy(oi->i_name, name, namelen); 143a3ab7155SBob Copeland memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen); 144a3ab7155SBob Copeland oi->i_sibling = cpu_to_be64(block); 145a3ab7155SBob Copeland oi->i_parent = cpu_to_be64(dir->i_ino); 146a3ab7155SBob Copeland mark_buffer_dirty(bh); 147a3ab7155SBob Copeland brelse(bh); 148a3ab7155SBob Copeland 149a3ab7155SBob Copeland dir->i_ctime = CURRENT_TIME_SEC; 150a3ab7155SBob Copeland 151a3ab7155SBob Copeland /* mark affected inodes dirty to rebuild checksums */ 152a3ab7155SBob Copeland mark_inode_dirty(dir); 153a3ab7155SBob Copeland mark_inode_dirty(inode); 154a3ab7155SBob Copeland return 0; 155a3ab7155SBob Copeland out: 156a3ab7155SBob Copeland return -ENOMEM; 157a3ab7155SBob Copeland } 158a3ab7155SBob Copeland 159a3ab7155SBob Copeland static int omfs_delete_entry(struct dentry *dentry) 160a3ab7155SBob Copeland { 161a3ab7155SBob Copeland struct inode *dir = dentry->d_parent->d_inode; 162a3ab7155SBob Copeland struct inode *dirty; 163a3ab7155SBob Copeland const char *name = dentry->d_name.name; 164a3ab7155SBob Copeland int namelen = dentry->d_name.len; 165a3ab7155SBob Copeland struct omfs_inode *oi; 166a3ab7155SBob Copeland struct buffer_head *bh, *bh2; 167a3ab7155SBob Copeland __be64 *entry, next; 168a3ab7155SBob Copeland u64 block, prev; 169a3ab7155SBob Copeland int ofs; 170a3ab7155SBob Copeland int err = -ENOMEM; 171a3ab7155SBob Copeland 172a3ab7155SBob Copeland /* delete the proper node in the bucket's linked list */ 173a3ab7155SBob Copeland bh = omfs_get_bucket(dir, name, namelen, &ofs); 174a3ab7155SBob Copeland if (!bh) 175a3ab7155SBob Copeland goto out; 176a3ab7155SBob Copeland 177a3ab7155SBob Copeland entry = (__be64 *) &bh->b_data[ofs]; 178a3ab7155SBob Copeland block = be64_to_cpu(*entry); 179a3ab7155SBob Copeland 180a3ab7155SBob Copeland bh2 = omfs_scan_list(dir, block, name, namelen, &prev); 181a3ab7155SBob Copeland if (IS_ERR(bh2)) { 182a3ab7155SBob Copeland err = PTR_ERR(bh2); 183a3ab7155SBob Copeland goto out_free_bh; 184a3ab7155SBob Copeland } 185a3ab7155SBob Copeland 186a3ab7155SBob Copeland oi = (struct omfs_inode *) bh2->b_data; 187a3ab7155SBob Copeland next = oi->i_sibling; 188a3ab7155SBob Copeland brelse(bh2); 189a3ab7155SBob Copeland 190a3ab7155SBob Copeland if (prev != ~0) { 191a3ab7155SBob Copeland /* found in middle of list, get list ptr */ 192a3ab7155SBob Copeland brelse(bh); 193a3ab7155SBob Copeland bh = sb_bread(dir->i_sb, 194a3ab7155SBob Copeland clus_to_blk(OMFS_SB(dir->i_sb), prev)); 195a3ab7155SBob Copeland if (!bh) 196a3ab7155SBob Copeland goto out; 197a3ab7155SBob Copeland 198a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 199a3ab7155SBob Copeland entry = &oi->i_sibling; 200a3ab7155SBob Copeland } 201a3ab7155SBob Copeland 202a3ab7155SBob Copeland *entry = next; 203a3ab7155SBob Copeland mark_buffer_dirty(bh); 204a3ab7155SBob Copeland 205a3ab7155SBob Copeland if (prev != ~0) { 206a3ab7155SBob Copeland dirty = omfs_iget(dir->i_sb, prev); 207a3ab7155SBob Copeland if (!IS_ERR(dirty)) { 208a3ab7155SBob Copeland mark_inode_dirty(dirty); 209a3ab7155SBob Copeland iput(dirty); 210a3ab7155SBob Copeland } 211a3ab7155SBob Copeland } 212a3ab7155SBob Copeland 213a3ab7155SBob Copeland err = 0; 214a3ab7155SBob Copeland out_free_bh: 215a3ab7155SBob Copeland brelse(bh); 216a3ab7155SBob Copeland out: 217a3ab7155SBob Copeland return err; 218a3ab7155SBob Copeland } 219a3ab7155SBob Copeland 220a3ab7155SBob Copeland static int omfs_dir_is_empty(struct inode *inode) 221a3ab7155SBob Copeland { 222a3ab7155SBob Copeland int nbuckets = (inode->i_size - OMFS_DIR_START) / 8; 223a3ab7155SBob Copeland struct buffer_head *bh; 224a3ab7155SBob Copeland u64 *ptr; 225a3ab7155SBob Copeland int i; 226a3ab7155SBob Copeland 227a3ab7155SBob Copeland bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb), 228a3ab7155SBob Copeland inode->i_ino)); 229a3ab7155SBob Copeland 230a3ab7155SBob Copeland if (!bh) 231a3ab7155SBob Copeland return 0; 232a3ab7155SBob Copeland 233a3ab7155SBob Copeland ptr = (u64 *) &bh->b_data[OMFS_DIR_START]; 234a3ab7155SBob Copeland 235a3ab7155SBob Copeland for (i = 0; i < nbuckets; i++, ptr++) 236a3ab7155SBob Copeland if (*ptr != ~0) 237a3ab7155SBob Copeland break; 238a3ab7155SBob Copeland 239a3ab7155SBob Copeland brelse(bh); 240a3ab7155SBob Copeland return *ptr != ~0; 241a3ab7155SBob Copeland } 242a3ab7155SBob Copeland 243a3ab7155SBob Copeland static int omfs_unlink(struct inode *dir, struct dentry *dentry) 244a3ab7155SBob Copeland { 245a3ab7155SBob Copeland int ret; 246a3ab7155SBob Copeland struct inode *inode = dentry->d_inode; 247a3ab7155SBob Copeland 248a3ab7155SBob Copeland ret = omfs_delete_entry(dentry); 249a3ab7155SBob Copeland if (ret) 250a3ab7155SBob Copeland goto end_unlink; 251a3ab7155SBob Copeland 252a3ab7155SBob Copeland inode_dec_link_count(inode); 253a3ab7155SBob Copeland mark_inode_dirty(dir); 254a3ab7155SBob Copeland 255a3ab7155SBob Copeland end_unlink: 256a3ab7155SBob Copeland return ret; 257a3ab7155SBob Copeland } 258a3ab7155SBob Copeland 259a3ab7155SBob Copeland static int omfs_rmdir(struct inode *dir, struct dentry *dentry) 260a3ab7155SBob Copeland { 261a3ab7155SBob Copeland int err = -ENOTEMPTY; 262a3ab7155SBob Copeland struct inode *inode = dentry->d_inode; 263a3ab7155SBob Copeland 264a3ab7155SBob Copeland if (omfs_dir_is_empty(inode)) { 265a3ab7155SBob Copeland err = omfs_unlink(dir, dentry); 266a3ab7155SBob Copeland if (!err) 267a3ab7155SBob Copeland inode_dec_link_count(inode); 268a3ab7155SBob Copeland } 269a3ab7155SBob Copeland return err; 270a3ab7155SBob Copeland } 271a3ab7155SBob Copeland 272a3ab7155SBob Copeland static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode) 273a3ab7155SBob Copeland { 274a3ab7155SBob Copeland int err; 275a3ab7155SBob Copeland struct inode *inode = omfs_new_inode(dir, mode); 276a3ab7155SBob Copeland 277a3ab7155SBob Copeland if (IS_ERR(inode)) 278a3ab7155SBob Copeland return PTR_ERR(inode); 279a3ab7155SBob Copeland 280a3ab7155SBob Copeland err = omfs_make_empty(inode, dir->i_sb); 281a3ab7155SBob Copeland if (err) 282a3ab7155SBob Copeland goto out_free_inode; 283a3ab7155SBob Copeland 284a3ab7155SBob Copeland err = omfs_add_link(dentry, inode); 285a3ab7155SBob Copeland if (err) 286a3ab7155SBob Copeland goto out_free_inode; 287a3ab7155SBob Copeland 288a3ab7155SBob Copeland d_instantiate(dentry, inode); 289a3ab7155SBob Copeland return 0; 290a3ab7155SBob Copeland 291a3ab7155SBob Copeland out_free_inode: 292a3ab7155SBob Copeland iput(inode); 293a3ab7155SBob Copeland return err; 294a3ab7155SBob Copeland } 295a3ab7155SBob Copeland 296a3ab7155SBob Copeland static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 297a3ab7155SBob Copeland { 298a3ab7155SBob Copeland return omfs_add_node(dir, dentry, mode | S_IFDIR); 299a3ab7155SBob Copeland } 300a3ab7155SBob Copeland 301a3ab7155SBob Copeland static int omfs_create(struct inode *dir, struct dentry *dentry, int mode, 302a3ab7155SBob Copeland struct nameidata *nd) 303a3ab7155SBob Copeland { 304a3ab7155SBob Copeland return omfs_add_node(dir, dentry, mode | S_IFREG); 305a3ab7155SBob Copeland } 306a3ab7155SBob Copeland 307a3ab7155SBob Copeland static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, 308a3ab7155SBob Copeland struct nameidata *nd) 309a3ab7155SBob Copeland { 310a3ab7155SBob Copeland struct buffer_head *bh; 311a3ab7155SBob Copeland struct inode *inode = NULL; 312a3ab7155SBob Copeland 313a3ab7155SBob Copeland if (dentry->d_name.len > OMFS_NAMELEN) 314a3ab7155SBob Copeland return ERR_PTR(-ENAMETOOLONG); 315a3ab7155SBob Copeland 316a3ab7155SBob Copeland bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 317a3ab7155SBob Copeland if (!IS_ERR(bh)) { 318a3ab7155SBob Copeland struct omfs_inode *oi = (struct omfs_inode *)bh->b_data; 319a3ab7155SBob Copeland ino_t ino = be64_to_cpu(oi->i_head.h_self); 320a3ab7155SBob Copeland brelse(bh); 321a3ab7155SBob Copeland inode = omfs_iget(dir->i_sb, ino); 322a3ab7155SBob Copeland if (IS_ERR(inode)) 323a3ab7155SBob Copeland return ERR_CAST(inode); 324a3ab7155SBob Copeland } 325a3ab7155SBob Copeland d_add(dentry, inode); 326a3ab7155SBob Copeland return NULL; 327a3ab7155SBob Copeland } 328a3ab7155SBob Copeland 329a3ab7155SBob Copeland /* sanity check block's self pointer */ 330a3ab7155SBob Copeland int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, 331a3ab7155SBob Copeland u64 fsblock) 332a3ab7155SBob Copeland { 333a3ab7155SBob Copeland int is_bad; 334a3ab7155SBob Copeland u64 ino = be64_to_cpu(header->h_self); 335a3ab7155SBob Copeland is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) || 336a3ab7155SBob Copeland (ino > sbi->s_num_blocks)); 337a3ab7155SBob Copeland 338a3ab7155SBob Copeland if (is_bad) 339a3ab7155SBob Copeland printk(KERN_WARNING "omfs: bad hash chain detected\n"); 340a3ab7155SBob Copeland 341a3ab7155SBob Copeland return is_bad; 342a3ab7155SBob Copeland } 343a3ab7155SBob Copeland 344a3ab7155SBob Copeland static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, 345a3ab7155SBob Copeland u64 fsblock, int hindex) 346a3ab7155SBob Copeland { 347a3ab7155SBob Copeland struct inode *dir = filp->f_dentry->d_inode; 348a3ab7155SBob Copeland struct buffer_head *bh; 349a3ab7155SBob Copeland struct omfs_inode *oi; 350a3ab7155SBob Copeland u64 self; 351a3ab7155SBob Copeland int res = 0; 352a3ab7155SBob Copeland unsigned char d_type; 353a3ab7155SBob Copeland 354a3ab7155SBob Copeland /* follow chain in this bucket */ 355a3ab7155SBob Copeland while (fsblock != ~0) { 356a3ab7155SBob Copeland bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), 357a3ab7155SBob Copeland fsblock)); 358a3ab7155SBob Copeland if (!bh) 359a3ab7155SBob Copeland goto out; 360a3ab7155SBob Copeland 361a3ab7155SBob Copeland oi = (struct omfs_inode *) bh->b_data; 362a3ab7155SBob Copeland if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { 363a3ab7155SBob Copeland brelse(bh); 364a3ab7155SBob Copeland goto out; 365a3ab7155SBob Copeland } 366a3ab7155SBob Copeland 367a3ab7155SBob Copeland self = fsblock; 368a3ab7155SBob Copeland fsblock = be64_to_cpu(oi->i_sibling); 369a3ab7155SBob Copeland 370a3ab7155SBob Copeland /* skip visited nodes */ 371a3ab7155SBob Copeland if (hindex) { 372a3ab7155SBob Copeland hindex--; 373a3ab7155SBob Copeland brelse(bh); 374a3ab7155SBob Copeland continue; 375a3ab7155SBob Copeland } 376a3ab7155SBob Copeland 377a3ab7155SBob Copeland d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; 378a3ab7155SBob Copeland 379a3ab7155SBob Copeland res = filldir(dirent, oi->i_name, strnlen(oi->i_name, 380a3ab7155SBob Copeland OMFS_NAMELEN), filp->f_pos, self, d_type); 381a3ab7155SBob Copeland if (res == 0) 382a3ab7155SBob Copeland filp->f_pos++; 383a3ab7155SBob Copeland brelse(bh); 384a3ab7155SBob Copeland } 385a3ab7155SBob Copeland out: 386a3ab7155SBob Copeland return res; 387a3ab7155SBob Copeland } 388a3ab7155SBob Copeland 389a3ab7155SBob Copeland static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, 390a3ab7155SBob Copeland struct inode *new_dir, struct dentry *new_dentry) 391a3ab7155SBob Copeland { 392a3ab7155SBob Copeland struct inode *new_inode = new_dentry->d_inode; 393a3ab7155SBob Copeland struct inode *old_inode = old_dentry->d_inode; 394a3ab7155SBob Copeland struct buffer_head *bh; 395a3ab7155SBob Copeland int is_dir; 396a3ab7155SBob Copeland int err; 397a3ab7155SBob Copeland 398a3ab7155SBob Copeland is_dir = S_ISDIR(old_inode->i_mode); 399a3ab7155SBob Copeland 400a3ab7155SBob Copeland if (new_inode) { 401a3ab7155SBob Copeland /* overwriting existing file/dir */ 402a3ab7155SBob Copeland err = -ENOTEMPTY; 403a3ab7155SBob Copeland if (is_dir && !omfs_dir_is_empty(new_inode)) 404a3ab7155SBob Copeland goto out; 405a3ab7155SBob Copeland 406a3ab7155SBob Copeland err = -ENOENT; 407a3ab7155SBob Copeland bh = omfs_find_entry(new_dir, new_dentry->d_name.name, 408a3ab7155SBob Copeland new_dentry->d_name.len); 409a3ab7155SBob Copeland if (IS_ERR(bh)) 410a3ab7155SBob Copeland goto out; 411a3ab7155SBob Copeland brelse(bh); 412a3ab7155SBob Copeland 413a3ab7155SBob Copeland err = omfs_unlink(new_dir, new_dentry); 414a3ab7155SBob Copeland if (err) 415a3ab7155SBob Copeland goto out; 416a3ab7155SBob Copeland } 417a3ab7155SBob Copeland 418a3ab7155SBob Copeland /* since omfs locates files by name, we need to unlink _before_ 419a3ab7155SBob Copeland * adding the new link or we won't find the old one */ 420a3ab7155SBob Copeland inode_inc_link_count(old_inode); 421a3ab7155SBob Copeland err = omfs_unlink(old_dir, old_dentry); 422a3ab7155SBob Copeland if (err) { 423a3ab7155SBob Copeland inode_dec_link_count(old_inode); 424a3ab7155SBob Copeland goto out; 425a3ab7155SBob Copeland } 426a3ab7155SBob Copeland 427a3ab7155SBob Copeland err = omfs_add_link(new_dentry, old_inode); 428a3ab7155SBob Copeland if (err) 429a3ab7155SBob Copeland goto out; 430a3ab7155SBob Copeland 431a3ab7155SBob Copeland old_inode->i_ctime = CURRENT_TIME_SEC; 432a3ab7155SBob Copeland out: 433a3ab7155SBob Copeland return err; 434a3ab7155SBob Copeland } 435a3ab7155SBob Copeland 436a3ab7155SBob Copeland static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) 437a3ab7155SBob Copeland { 438a3ab7155SBob Copeland struct inode *dir = filp->f_dentry->d_inode; 439a3ab7155SBob Copeland struct buffer_head *bh; 440a3ab7155SBob Copeland loff_t offset, res; 441a3ab7155SBob Copeland unsigned int hchain, hindex; 442a3ab7155SBob Copeland int nbuckets; 443a3ab7155SBob Copeland u64 fsblock; 444a3ab7155SBob Copeland int ret = -EINVAL; 445a3ab7155SBob Copeland 446a3ab7155SBob Copeland if (filp->f_pos >> 32) 447a3ab7155SBob Copeland goto success; 448a3ab7155SBob Copeland 449a3ab7155SBob Copeland switch ((unsigned long) filp->f_pos) { 450a3ab7155SBob Copeland case 0: 451a3ab7155SBob Copeland if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) 452a3ab7155SBob Copeland goto success; 453a3ab7155SBob Copeland filp->f_pos++; 454a3ab7155SBob Copeland /* fall through */ 455a3ab7155SBob Copeland case 1: 456a3ab7155SBob Copeland if (filldir(dirent, "..", 2, 1, 457a3ab7155SBob Copeland parent_ino(filp->f_dentry), DT_DIR) < 0) 458a3ab7155SBob Copeland goto success; 459a3ab7155SBob Copeland filp->f_pos = 1 << 20; 460a3ab7155SBob Copeland /* fall through */ 461a3ab7155SBob Copeland } 462a3ab7155SBob Copeland 463a3ab7155SBob Copeland nbuckets = (dir->i_size - OMFS_DIR_START) / 8; 464a3ab7155SBob Copeland 465a3ab7155SBob Copeland /* high 12 bits store bucket + 1 and low 20 bits store hash index */ 466a3ab7155SBob Copeland hchain = (filp->f_pos >> 20) - 1; 467a3ab7155SBob Copeland hindex = filp->f_pos & 0xfffff; 468a3ab7155SBob Copeland 469a3ab7155SBob Copeland bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino)); 470a3ab7155SBob Copeland if (!bh) 471a3ab7155SBob Copeland goto out; 472a3ab7155SBob Copeland 473a3ab7155SBob Copeland offset = OMFS_DIR_START + hchain * 8; 474a3ab7155SBob Copeland 475a3ab7155SBob Copeland for (; hchain < nbuckets; hchain++, offset += 8) { 476a3ab7155SBob Copeland fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset])); 477a3ab7155SBob Copeland 478a3ab7155SBob Copeland res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex); 479a3ab7155SBob Copeland hindex = 0; 480a3ab7155SBob Copeland if (res < 0) 481a3ab7155SBob Copeland break; 482a3ab7155SBob Copeland 483a3ab7155SBob Copeland filp->f_pos = (hchain+2) << 20; 484a3ab7155SBob Copeland } 485a3ab7155SBob Copeland brelse(bh); 486a3ab7155SBob Copeland success: 487a3ab7155SBob Copeland ret = 0; 488a3ab7155SBob Copeland out: 489a3ab7155SBob Copeland return ret; 490a3ab7155SBob Copeland } 491a3ab7155SBob Copeland 4926e1d5dccSAlexey Dobriyan const struct inode_operations omfs_dir_inops = { 493a3ab7155SBob Copeland .lookup = omfs_lookup, 494a3ab7155SBob Copeland .mkdir = omfs_mkdir, 495a3ab7155SBob Copeland .rename = omfs_rename, 496a3ab7155SBob Copeland .create = omfs_create, 497a3ab7155SBob Copeland .unlink = omfs_unlink, 498a3ab7155SBob Copeland .rmdir = omfs_rmdir, 499a3ab7155SBob Copeland }; 500a3ab7155SBob Copeland 501*828c0950SAlexey Dobriyan const struct file_operations omfs_dir_operations = { 502a3ab7155SBob Copeland .read = generic_read_dir, 503a3ab7155SBob Copeland .readdir = omfs_readdir, 5043222a3e5SChristoph Hellwig .llseek = generic_file_llseek, 505a3ab7155SBob Copeland }; 506