On Thu, 30 Nov 2000, Theodore Y. Ts'o wrote:

> If you could send me the split up, I'd appreciate it, as it'll make it
> easier to find any subtle bugs.  I certainly like the general way you've
> cleaned up the interfaces and factored out the code.

See attachments. Order of patches is alphabetical ;-)
                                                        Cheers,
                                                                Al
diff -urN ext2/fs/ext2/ialloc.c ext2-1/fs/ext2/ialloc.c
--- ext2/fs/ext2/ialloc.c       Thu Nov 30 11:23:18 2000
+++ ext2-1/fs/ext2/ialloc.c     Fri Dec  1 10:35:24 2000
@@ -256,7 +256,7 @@
  * For other inodes, search forward from the parent directory\'s block
  * group to find a free inode.
  */
-struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
+struct inode * ext2_new_inode (const struct inode * dir, int mode)
 {
        struct super_block * sb;
        struct buffer_head * bh;
@@ -267,26 +267,22 @@
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * tmp;
        struct ext2_super_block * es;
+       int err;
 
        /* Cannot create files in a deleted directory */
-       if (!dir || !dir->i_nlink) {
-               *err = -EPERM;
-               return NULL;
-       }
+       if (!dir || !dir->i_nlink)
+               return ERR_PTR(-EPERM);
 
        sb = dir->i_sb;
        inode = new_inode(sb);
-       if (!inode) {
-               *err = -ENOMEM;
-               return NULL;
-       }
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
 
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
 repeat:
        gdp = NULL; i=0;
        
-       *err = -ENOSPC;
        if (S_ISDIR(mode)) {
                avefreei = le32_to_cpu(es->s_free_inodes_count) /
                        sb->u.ext2_sb.s_groups_count;
@@ -365,18 +361,14 @@
                }
        }
 
-       if (!gdp) {
-               unlock_super (sb);
-               iput(inode);
-               return NULL;
-       }
+       err = -ENOSPC;
+       if (!gdp)
+               goto fail;
+
+       err = -EIO;
        bitmap_nr = load_inode_bitmap (sb, i);
-       if (bitmap_nr < 0) {
-               unlock_super (sb);
-               iput(inode);
-               *err = -EIO;
-               return NULL;
-       }
+       if (bitmap_nr < 0)
+               goto fail;
 
        bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
@@ -397,11 +389,11 @@
                        ext2_error (sb, "ext2_new_inode",
                                    "Free inodes count corrupted in group %d",
                                    i);
-                       if (sb->s_flags & MS_RDONLY) {
-                               unlock_super (sb);
-                               iput (inode);
-                               return NULL;
-                       }
+                       /* Is it really ENOSPC? */
+                       err = -ENOSPC;
+                       if (sb->s_flags & MS_RDONLY)
+                               goto fail;
+
                        gdp->bg_free_inodes_count = 0;
                        mark_buffer_dirty(bh2);
                }
@@ -412,10 +404,8 @@
                ext2_error (sb, "ext2_new_inode",
                            "reserved inode or inode > inodes count - "
                            "block_group = %d,inode=%d", i, j);
-               unlock_super (sb);
-               iput (inode);
-               *err = -EIO;
-               return NULL;
+               err = -EIO;
+               goto fail;
        }
        gdp->bg_free_inodes_count =
                cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
@@ -464,13 +454,15 @@
                sb->dq_op->drop(inode);
                inode->i_nlink = 0;
                iput(inode);
-               *err = -EDQUOT;
-               return NULL;
+               return ERR_PTR(-EDQUOT);
        }
        ext2_debug ("allocating inode %lu\n", inode->i_ino);
-
-       *err = 0;
        return inode;
+
+fail:
+       unlock_super(sb);
+       iput(inode);
+       return ERR_PTR(err);
 }
 
 unsigned long ext2_count_free_inodes (struct super_block * sb)
diff -urN ext2/fs/ext2/namei.c ext2-1/fs/ext2/namei.c
--- ext2/fs/ext2/namei.c        Thu Nov 30 11:23:18 2000
+++ ext2-1/fs/ext2/namei.c      Fri Dec  1 10:35:24 2000
@@ -361,11 +361,9 @@
  */
 static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
 {
-       struct inode * inode;
-       int err;
-
-       inode = ext2_new_inode (dir, mode, &err);
-       if (!inode)
+       struct inode * inode = ext2_new_inode (dir, mode);
+       int err = PTR_ERR(inode);
+       if (IS_ERR(inode))
                return err;
 
        inode->i_op = &ext2_file_inode_operations;
@@ -387,11 +385,10 @@
 
 static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
-       struct inode * inode;
-       int err;
+       struct inode * inode = ext2_new_inode (dir, mode);
+       int err = PTR_ERR(inode);
 
-       inode = ext2_new_inode (dir, mode, &err);
-       if (!inode)
+       if (IS_ERR(inode))
                return err;
 
        inode->i_uid = current->fsuid;
@@ -421,8 +418,9 @@
        if (dir->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
 
-       inode = ext2_new_inode (dir, S_IFDIR, &err);
-       if (!inode)
+       inode = ext2_new_inode (dir, S_IFDIR);
+       err = PTR_ERR(inode);
+       if (IS_ERR(inode))
                return err;
 
        inode->i_op = &ext2_dir_inode_operations;
@@ -628,7 +626,9 @@
        if (l > dir->i_sb->s_blocksize)
                return -ENAMETOOLONG;
 
-       if (!(inode = ext2_new_inode (dir, S_IFLNK, &err)))
+       inode = ext2_new_inode (dir, S_IFLNK);
+       err = PTR_ERR(inode);
+       if (IS_ERR(inode))
                return err;
 
        inode->i_mode = S_IFLNK | S_IRWXUGO;
diff -urN ext2/include/linux/ext2_fs.h ext2-1/include/linux/ext2_fs.h
--- ext2/include/linux/ext2_fs.h        Thu Nov 30 11:23:18 2000
+++ ext2-1/include/linux/ext2_fs.h      Fri Dec  1 10:35:24 2000
@@ -552,7 +552,7 @@
 extern int ext2_fsync_inode (struct inode *, int);
 
 /* ialloc.c */
-extern struct inode * ext2_new_inode (const struct inode *, int, int *);
+extern struct inode * ext2_new_inode (const struct inode *, int);
 extern void ext2_free_inode (struct inode *);
 extern unsigned long ext2_count_free_inodes (struct super_block *);
 extern void ext2_check_inodes_bitmap (struct super_block *);
diff -urN ext2-1/fs/ext2/namei.c ext2-2/fs/ext2/namei.c
--- ext2-1/fs/ext2/namei.c      Fri Dec  1 10:35:24 2000
+++ ext2-2/fs/ext2/namei.c      Fri Dec  1 10:37:32 2000
@@ -369,7 +369,6 @@
        inode->i_op = &ext2_file_inode_operations;
        inode->i_fop = &ext2_file_operations;
        inode->i_mapping->a_ops = &ext2_aops;
-       inode->i_mode = mode;
        mark_inode_dirty(inode);
        err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
                             inode);
@@ -418,7 +417,10 @@
        if (dir->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
 
-       inode = ext2_new_inode (dir, S_IFDIR);
+       if (dir->i_mode & S_ISGID)
+               mode |= S_ISGID;
+
+       inode = ext2_new_inode (dir, S_IFDIR | mode);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                return err;
@@ -426,7 +428,6 @@
        inode->i_op = &ext2_dir_inode_operations;
        inode->i_fop = &ext2_dir_operations;
        inode->i_size = inode->i_sb->s_blocksize;
-       inode->i_blocks = 0;    
        dir_block = ext2_bread (inode, 0, 1, &err);
        if (!dir_block) {
                inode->i_nlink--; /* is this nlink == 0? */
@@ -449,9 +450,6 @@
        inode->i_nlink = 2;
        mark_buffer_dirty_inode(dir_block, dir);
        brelse (dir_block);
-       inode->i_mode = S_IFDIR | mode;
-       if (dir->i_mode & S_ISGID)
-               inode->i_mode |= S_ISGID;
        mark_inode_dirty(inode);
        err = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, 
                             inode);
@@ -626,12 +624,10 @@
        if (l > dir->i_sb->s_blocksize)
                return -ENAMETOOLONG;
 
-       inode = ext2_new_inode (dir, S_IFLNK);
+       inode = ext2_new_inode (dir, S_IFLNK|S_IRWXUGO);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                return err;
-
-       inode->i_mode = S_IFLNK | S_IRWXUGO;
 
        if (l > sizeof (inode->u.ext2_i.i_data)) {
                inode->i_op = &page_symlink_inode_operations;
diff -urN ext2-2/fs/ext2/ialloc.c ext2-3/fs/ext2/ialloc.c
--- ext2-2/fs/ext2/ialloc.c     Fri Dec  1 10:35:24 2000
+++ ext2-3/fs/ext2/ialloc.c     Fri Dec  1 10:40:41 2000
@@ -91,19 +91,20 @@
        int i, j, retval = 0;
        unsigned long inode_bitmap_number;
        struct buffer_head * inode_bitmap;
+       struct ext2_sb_info *sbi = &sb->u.ext2_sb;
 
-       if (block_group >= sb->u.ext2_sb.s_groups_count)
+       if (block_group >= sbi->s_groups_count)
                ext2_panic (sb, "load_inode_bitmap",
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
-                            block_group, sb->u.ext2_sb.s_groups_count);
-       if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 &&
-           sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group &&
-           sb->u.ext2_sb.s_inode_bitmap[0] != NULL)
+                            block_group, sbi->s_groups_count);
+       if (sbi->s_loaded_inode_bitmaps > 0 &&
+           sbi->s_inode_bitmap_number[0] == block_group &&
+           sbi->s_inode_bitmap[0] != NULL)
                return 0;
-       if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-               if (sb->u.ext2_sb.s_inode_bitmap[block_group]) {
-                       if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != 
block_group)
+       if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
+               if (sbi->s_inode_bitmap[block_group]) {
+                       if (sbi->s_inode_bitmap_number[block_group] != block_group)
                                ext2_panic (sb, "load_inode_bitmap",
                                            "block_group != inode_bitmap_number");
                        else
@@ -117,22 +118,22 @@
                }
        }
 
-       for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
-                   sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group;
+       for (i = 0; i < sbi->s_loaded_inode_bitmaps &&
+                   sbi->s_inode_bitmap_number[i] != block_group;
             i++)
                ;
-       if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
-           sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) {
-               inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i];
-               inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i];
+       if (i < sbi->s_loaded_inode_bitmaps &&
+           sbi->s_inode_bitmap_number[i] == block_group) {
+               inode_bitmap_number = sbi->s_inode_bitmap_number[i];
+               inode_bitmap = sbi->s_inode_bitmap[i];
                for (j = i; j > 0; j--) {
-                       sb->u.ext2_sb.s_inode_bitmap_number[j] =
-                               sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
-                       sb->u.ext2_sb.s_inode_bitmap[j] =
-                               sb->u.ext2_sb.s_inode_bitmap[j - 1];
+                       sbi->s_inode_bitmap_number[j] =
+                               sbi->s_inode_bitmap_number[j - 1];
+                       sbi->s_inode_bitmap[j] =
+                               sbi->s_inode_bitmap[j - 1];
                }
-               sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
-               sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
+               sbi->s_inode_bitmap_number[0] = inode_bitmap_number;
+               sbi->s_inode_bitmap[0] = inode_bitmap;
 
                /*
                 * There's still one special case here --- if inode_bitmap == 0
@@ -143,15 +144,15 @@
                        retval = read_inode_bitmap (sb, block_group, 0);
                
        } else {
-               if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
-                       sb->u.ext2_sb.s_loaded_inode_bitmaps++;
+               if (sbi->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
+                       sbi->s_loaded_inode_bitmaps++;
                else
-                       brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 
1]);
-               for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) {
-                       sb->u.ext2_sb.s_inode_bitmap_number[j] =
-                               sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
-                       sb->u.ext2_sb.s_inode_bitmap[j] =
-                               sb->u.ext2_sb.s_inode_bitmap[j - 1];
+                       brelse (sbi->s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
+               for (j = sbi->s_loaded_inode_bitmaps - 1; j > 0; j--) {
+                       sbi->s_inode_bitmap_number[j] =
+                               sbi->s_inode_bitmap_number[j - 1];
+                       sbi->s_inode_bitmap[j] =
+                               sbi->s_inode_bitmap[j - 1];
                }
                retval = read_inode_bitmap (sb, block_group, 0);
        }
diff -urN ext2-3/fs/ext2/ialloc.c ext2-4/fs/ext2/ialloc.c
--- ext2-3/fs/ext2/ialloc.c     Fri Dec  1 10:40:41 2000
+++ ext2-4/fs/ext2/ialloc.c     Fri Dec  1 11:00:19 2000
@@ -88,44 +88,39 @@
 static int load_inode_bitmap (struct super_block * sb,
                              unsigned int block_group)
 {
-       int i, j, retval = 0;
+       int i, j, retval = 0, slot = 0;
        unsigned long inode_bitmap_number;
-       struct buffer_head * inode_bitmap;
        struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+       struct buffer_head *bh = sbi->s_inode_bitmap[0];
 
        if (block_group >= sbi->s_groups_count)
                ext2_panic (sb, "load_inode_bitmap",
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
                             block_group, sbi->s_groups_count);
+
        if (sbi->s_loaded_inode_bitmaps > 0 &&
-           sbi->s_inode_bitmap_number[0] == block_group &&
-           sbi->s_inode_bitmap[0] != NULL)
-               return 0;
+           sbi->s_inode_bitmap_number[0] == block_group && bh)
+               goto found;
+
        if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-               if (sbi->s_inode_bitmap[block_group]) {
-                       if (sbi->s_inode_bitmap_number[block_group] != block_group)
-                               ext2_panic (sb, "load_inode_bitmap",
-                                           "block_group != inode_bitmap_number");
-                       else
-                               return block_group;
-               } else {
-                       retval = read_inode_bitmap (sb, block_group,
-                                                   block_group);
-                       if (retval < 0)
-                               return retval;
-                       return block_group;
-               }
+               slot = block_group;
+               bh = sbi->s_inode_bitmap[slot];
+               if (!bh)
+                       goto read_it;
+               if (sbi->s_inode_bitmap_number[slot] == slot)
+                       goto found;
+               ext2_panic (sb, "load_inode_bitmap",
+                           "block_group != inode_bitmap_number");
        }
 
        for (i = 0; i < sbi->s_loaded_inode_bitmaps &&
                    sbi->s_inode_bitmap_number[i] != block_group;
             i++)
                ;
-       if (i < sbi->s_loaded_inode_bitmaps &&
-           sbi->s_inode_bitmap_number[i] == block_group) {
+       if (i < sbi->s_loaded_inode_bitmaps) {
                inode_bitmap_number = sbi->s_inode_bitmap_number[i];
-               inode_bitmap = sbi->s_inode_bitmap[i];
+               bh = sbi->s_inode_bitmap[i];
                for (j = i; j > 0; j--) {
                        sbi->s_inode_bitmap_number[j] =
                                sbi->s_inode_bitmap_number[j - 1];
@@ -133,15 +128,15 @@
                                sbi->s_inode_bitmap[j - 1];
                }
                sbi->s_inode_bitmap_number[0] = inode_bitmap_number;
-               sbi->s_inode_bitmap[0] = inode_bitmap;
+               sbi->s_inode_bitmap[0] = bh;
 
                /*
                 * There's still one special case here --- if inode_bitmap == 0
                 * then our last attempt to read the bitmap failed and we have
                 * just ended up caching that failure.  Try again to read it.
                 */
-               if (!inode_bitmap)
-                       retval = read_inode_bitmap (sb, block_group, 0);
+               if (bh)
+                       goto found;
                
        } else {
                if (sbi->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
@@ -154,9 +149,14 @@
                        sbi->s_inode_bitmap[j] =
                                sbi->s_inode_bitmap[j - 1];
                }
-               retval = read_inode_bitmap (sb, block_group, 0);
        }
-       return retval;
+
+read_it:
+       retval = read_inode_bitmap (sb, block_group, slot);
+       if (retval < 0)
+               return retval;
+found:
+       return slot;
 }
 
 /*
diff -urN ext2-4/fs/ext2/ialloc.c ext2-5/fs/ext2/ialloc.c
--- ext2-4/fs/ext2/ialloc.c     Fri Dec  1 11:00:19 2000
+++ ext2-5/fs/ext2/ialloc.c     Fri Dec  1 11:00:49 2000
@@ -88,8 +88,7 @@
 static int load_inode_bitmap (struct super_block * sb,
                              unsigned int block_group)
 {
-       int i, j, retval = 0, slot = 0;
-       unsigned long inode_bitmap_number;
+       int i, retval = 0, slot = 0;
        struct ext2_sb_info *sbi = &sb->u.ext2_sb;
        struct buffer_head *bh = sbi->s_inode_bitmap[0];
 
@@ -119,7 +118,8 @@
             i++)
                ;
        if (i < sbi->s_loaded_inode_bitmaps) {
-               inode_bitmap_number = sbi->s_inode_bitmap_number[i];
+               int j;
+               unsigned long nr = sbi->s_inode_bitmap_number[i];
                bh = sbi->s_inode_bitmap[i];
                for (j = i; j > 0; j--) {
                        sbi->s_inode_bitmap_number[j] =
@@ -127,18 +127,17 @@
                        sbi->s_inode_bitmap[j] =
                                sbi->s_inode_bitmap[j - 1];
                }
-               sbi->s_inode_bitmap_number[0] = inode_bitmap_number;
+               sbi->s_inode_bitmap_number[0] = nr;
                sbi->s_inode_bitmap[0] = bh;
-
+               if (bh)
+                       goto found;
                /*
                 * There's still one special case here --- if inode_bitmap == 0
                 * then our last attempt to read the bitmap failed and we have
                 * just ended up caching that failure.  Try again to read it.
                 */
-               if (bh)
-                       goto found;
-               
        } else {
+               int j;
                if (sbi->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
                        sbi->s_loaded_inode_bitmaps++;
                else
diff -urN ext2-5/fs/ext2/ialloc.c ext2-6/fs/ext2/ialloc.c
--- ext2-5/fs/ext2/ialloc.c     Fri Dec  1 11:00:49 2000
+++ ext2-6/fs/ext2/ialloc.c     Fri Dec  1 11:05:40 2000
@@ -39,37 +39,26 @@
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head of bitmap on success or NULL.
  */
-static int read_inode_bitmap (struct super_block * sb,
-                              unsigned long block_group,
-                              unsigned int bitmap_nr)
+static struct buffer_head *read_inode_bitmap (struct super_block * sb,
+                                              unsigned long block_group)
 {
        struct ext2_group_desc * gdp;
        struct buffer_head * bh = NULL;
-       int retval = 0;
 
        gdp = ext2_get_group_desc (sb, block_group, NULL);
-       if (!gdp) {
-               retval = -EIO;
+       if (!gdp)
                goto error_out;
-       }
+
        bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
-       if (!bh) {
+       if (!bh)
                ext2_error (sb, "read_inode_bitmap",
                            "Cannot read inode bitmap - "
                            "block_group = %lu, inode_bitmap = %lu",
                            block_group, (unsigned long) gdp->bg_inode_bitmap);
-               retval = -EIO;
-       }
-       /*
-        * On IO error, just leave a zero in the superblock's block pointer for
-        * this group.  The IO will be retried next time.
-        */
 error_out:
-       sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
-       sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
-       return retval;
+       return bh;
 }
 
 /*
@@ -88,7 +77,7 @@
 static int load_inode_bitmap (struct super_block * sb,
                              unsigned int block_group)
 {
-       int i, retval = 0, slot = 0;
+       int i, slot = 0;
        struct ext2_sb_info *sbi = &sb->u.ext2_sb;
        struct buffer_head *bh = sbi->s_inode_bitmap[0];
 
@@ -151,9 +140,15 @@
        }
 
 read_it:
-       retval = read_inode_bitmap (sb, block_group, slot);
-       if (retval < 0)
-               return retval;
+       bh = read_inode_bitmap (sb, block_group);
+       /*
+        * On IO error, just leave a zero in the superblock's block pointer for
+        * this group.  The IO will be retried next time.
+        */
+       sbi->s_inode_bitmap_number[slot] = block_group;
+       sbi->s_inode_bitmap[slot] = bh;
+       if (!bh)
+               return -EIO;
 found:
        return slot;
 }
diff -urN ext2-6/fs/ext2/ialloc.c ext2-7/fs/ext2/ialloc.c
--- ext2-6/fs/ext2/ialloc.c     Fri Dec  1 11:05:40 2000
+++ ext2-7/fs/ext2/ialloc.c     Fri Dec  1 11:08:56 2000
@@ -72,10 +72,10 @@
  * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
  *    this function reads the bitmap without maintaining a LRU cache.
  * 
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or the ERR_PTR(error)
  */
-static int load_inode_bitmap (struct super_block * sb,
-                             unsigned int block_group)
+static struct buffer_head *load_inode_bitmap (struct super_block * sb,
+                                             unsigned int block_group)
 {
        int i, slot = 0;
        struct ext2_sb_info *sbi = &sb->u.ext2_sb;
@@ -148,9 +148,9 @@
        sbi->s_inode_bitmap_number[slot] = block_group;
        sbi->s_inode_bitmap[slot] = bh;
        if (!bh)
-               return -EIO;
+               return ERR_PTR(-EIO);
 found:
-       return slot;
+       return bh;
 }
 
 /*
@@ -178,7 +178,6 @@
        struct buffer_head * bh2;
        unsigned long block_group;
        unsigned long bit;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_super_block * es;
 
@@ -202,12 +201,10 @@
        }
        block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
        bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
-       bitmap_nr = load_inode_bitmap (sb, block_group);
-       if (bitmap_nr < 0)
+       bh = load_inode_bitmap (sb, block_group);
+       if (IS_ERR(bh))
                goto error_return;
        
-       bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
-
        is_directory = S_ISDIR(inode->i_mode);
 
        /* Do this BEFORE marking the inode not in use */
@@ -258,7 +255,6 @@
        struct buffer_head * bh2;
        int i, j, avefreei;
        struct inode * inode;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * tmp;
        struct ext2_super_block * es;
@@ -361,11 +357,10 @@
                goto fail;
 
        err = -EIO;
-       bitmap_nr = load_inode_bitmap (sb, i);
-       if (bitmap_nr < 0)
+       bh = load_inode_bitmap (sb, i);
+       if (IS_ERR(bh))
                goto fail;
 
-       bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
                                      EXT2_INODES_PER_GROUP(sb))) <
            EXT2_INODES_PER_GROUP(sb)) {
@@ -465,7 +460,6 @@
 #ifdef EXT2FS_DEBUG
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        int i;
 
@@ -475,16 +469,16 @@
        bitmap_count = 0;
        gdp = NULL;
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+               struct buffer_head *bh;
                gdp = ext2_get_group_desc (sb, i, NULL);
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-               bitmap_nr = load_inode_bitmap (sb, i);
-               if (bitmap_nr < 0)
+               bh = load_inode_bitmap (sb, i);
+               if (IS_ERR(bh))
                        continue;
 
-               x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
-                                    EXT2_INODES_PER_GROUP(sb) / 8);
+               x = ext2_count_free (bh, EXT2_INODES_PER_GROUP(sb) / 8);
                printk ("group %d: stored = %d, counted = %lu\n",
                        i, le16_to_cpu(gdp->bg_free_inodes_count), x);
                bitmap_count += x;
@@ -504,7 +498,6 @@
 {
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        int i;
 
@@ -513,16 +506,16 @@
        bitmap_count = 0;
        gdp = NULL;
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+               struct buffer_head *bh;
                gdp = ext2_get_group_desc (sb, i, NULL);
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-               bitmap_nr = load_inode_bitmap (sb, i);
-               if (bitmap_nr < 0)
+               bh = load_inode_bitmap (sb, i);
+               if (IS_ERR(bh))
                        continue;
                
-               x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
-                                    EXT2_INODES_PER_GROUP(sb) / 8);
+               x = ext2_count_free (bh, EXT2_INODES_PER_GROUP(sb) / 8);
                if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
                        ext2_error (sb, "ext2_check_inodes_bitmap",
                                    "Wrong free inodes count in group %d, "
diff -urN ext2-7/fs/ext2/ialloc.c ext2-8/fs/ext2/ialloc.c
--- ext2-7/fs/ext2/ialloc.c     Fri Dec  1 11:08:56 2000
+++ ext2-8/fs/ext2/ialloc.c     Fri Dec  1 11:11:12 2000
@@ -248,15 +248,111 @@
  * For other inodes, search forward from the parent directory\'s block
  * group to find a free inode.
  */
+
+static int find_cg_dir(struct super_block *sb, int parent_cg)
+{
+       struct ext2_super_block * es = sb->u.ext2_sb.s_es;
+       int ngroups = sb->u.ext2_sb.s_groups_count;
+       int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups;
+       struct ext2_group_desc *cg, *best_cg = NULL;
+       struct buffer_head *bh, *best_bh = NULL;
+       int i = -1, j;
+
+/* I am not yet convinced that this next bit is necessary.
+       for (i = parent_cg, j = 0; j < ngroups; j++, i = ++i % ngroups) {
+               cg = ext2_get_group_desc (sb, i, &bh);
+               if (!cg)
+                       continue;
+               if ((le16_to_cpu(cg->bg_used_dirs_count) << 8) < 
+                    le16_to_cpu(cg->bg_free_inodes_count)) {
+                       best_cg = cg;
+                       best_bh = bh;
+                       goto found;
+               }
+       }
+*/
+       for (j = 0; j < ngroups; j++) {
+               cg = ext2_get_group_desc (sb, j, &bh);
+               if (!cg || !cg->bg_free_inodes_count)
+                       continue;
+               if (le16_to_cpu(cg->bg_free_inodes_count) < avefreei)
+                       continue;
+               if (!best_cg || 
+                   (le16_to_cpu(cg->bg_free_blocks_count) >
+                    le16_to_cpu(best_cg->bg_free_blocks_count))) {
+                       i = j;
+                       best_cg = cg;
+                       best_bh = bh;
+               }
+       }
+       if (!best_cg)
+               return -1;
+found:
+       best_cg->bg_free_inodes_count =
+               cpu_to_le16(le16_to_cpu(best_cg->bg_free_inodes_count) - 1);
+       best_cg->bg_used_dirs_count =
+               cpu_to_le16(le16_to_cpu(best_cg->bg_used_dirs_count) + 1);
+       mark_buffer_dirty(best_bh);
+       return i;
+}
+
+static int find_cg_other(struct super_block *sb, int parent_cg)
+{
+       int ngroups = sb->u.ext2_sb.s_groups_count;
+       struct ext2_group_desc *cg;
+       struct buffer_head *bh;
+       int i, j;
+
+       /*
+        * Try to place the inode in its parent directory
+        */
+       i = parent_cg;
+       cg = ext2_get_group_desc (sb, i, &bh);
+       if (cg && le16_to_cpu(cg->bg_free_inodes_count))
+               goto found;
+
+       /*
+        * Use a quadratic hash to find a group with a
+        * free inode
+        */
+       for (j = 1; j < ngroups; j <<= 1) {
+               i += j;
+               if (i >= ngroups)
+                       i -= ngroups;
+               cg = ext2_get_group_desc (sb, i, &bh);
+               if (cg && le16_to_cpu(cg->bg_free_inodes_count))
+                       goto found;
+       }
+
+       /*
+        * That failed: try linear search for a free inode
+        */
+       i = parent_cg + 1;
+       for (j = 2; j < ngroups; j++) {
+               if (++i >= ngroups)
+                       i = 0;
+               cg = ext2_get_group_desc (sb, i, &bh);
+               if (cg && le16_to_cpu(cg->bg_free_inodes_count))
+                       goto found;
+       }
+
+       return -1;
+
+found:
+       cg->bg_free_inodes_count =
+               cpu_to_le16(le16_to_cpu(cg->bg_free_inodes_count) - 1);
+       mark_buffer_dirty(bh);
+       return i;
+}
+
 struct inode * ext2_new_inode (const struct inode * dir, int mode)
 {
        struct super_block * sb;
        struct buffer_head * bh;
        struct buffer_head * bh2;
-       int i, j, avefreei;
+       int i, j;
        struct inode * inode;
        struct ext2_group_desc * gdp;
-       struct ext2_group_desc * tmp;
        struct ext2_super_block * es;
        int err;
 
@@ -272,137 +368,41 @@
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
 repeat:
-       gdp = NULL; i=0;
-       
-       if (S_ISDIR(mode)) {
-               avefreei = le32_to_cpu(es->s_free_inodes_count) /
-                       sb->u.ext2_sb.s_groups_count;
-/* I am not yet convinced that this next bit is necessary.
-               i = dir->u.ext2_i.i_block_group;
-               for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
-                       tmp = ext2_get_group_desc (sb, i, &bh2);
-                       if (tmp &&
-                           (le16_to_cpu(tmp->bg_used_dirs_count) << 8) < 
-                            le16_to_cpu(tmp->bg_free_inodes_count)) {
-                               gdp = tmp;
-                               break;
-                       }
-                       else
-                       i = ++i % sb->u.ext2_sb.s_groups_count;
-               }
-*/
-               if (!gdp) {
-                       for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
-                               tmp = ext2_get_group_desc (sb, j, &bh2);
-                               if (tmp &&
-                                   le16_to_cpu(tmp->bg_free_inodes_count) &&
-                                   le16_to_cpu(tmp->bg_free_inodes_count) >= 
avefreei) {
-                                       if (!gdp || 
-                                           (le16_to_cpu(tmp->bg_free_blocks_count) >
-                                            le16_to_cpu(gdp->bg_free_blocks_count))) 
{
-                                               i = j;
-                                               gdp = tmp;
-                                       }
-                               }
-                       }
-               }
-       }
+       if (S_ISDIR(mode)) 
+               i = find_cg_dir(sb, dir->u.ext2_i.i_block_group);
        else 
-       {
-               /*
-                * Try to place the inode in its parent directory
-                */
-               i = dir->u.ext2_i.i_block_group;
-               tmp = ext2_get_group_desc (sb, i, &bh2);
-               if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
-                       gdp = tmp;
-               else
-               {
-                       /*
-                        * Use a quadratic hash to find a group with a
-                        * free inode
-                        */
-                       for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
-                               i += j;
-                               if (i >= sb->u.ext2_sb.s_groups_count)
-                                       i -= sb->u.ext2_sb.s_groups_count;
-                               tmp = ext2_get_group_desc (sb, i, &bh2);
-                               if (tmp &&
-                                   le16_to_cpu(tmp->bg_free_inodes_count)) {
-                                       gdp = tmp;
-                                       break;
-                               }
-                       }
-               }
-               if (!gdp) {
-                       /*
-                        * That failed: try linear search for a free inode
-                        */
-                       i = dir->u.ext2_i.i_block_group + 1;
-                       for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
-                               if (++i >= sb->u.ext2_sb.s_groups_count)
-                                       i = 0;
-                               tmp = ext2_get_group_desc (sb, i, &bh2);
-                               if (tmp &&
-                                   le16_to_cpu(tmp->bg_free_inodes_count)) {
-                                       gdp = tmp;
-                                       break;
-                               }
-                       }
-               }
-       }
+               i = find_cg_other(sb, dir->u.ext2_i.i_block_group);
 
        err = -ENOSPC;
-       if (!gdp)
+       if (i == -1)
                goto fail;
 
        err = -EIO;
        bh = load_inode_bitmap (sb, i);
        if (IS_ERR(bh))
-               goto fail;
-
-       if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
-                                     EXT2_INODES_PER_GROUP(sb))) <
-           EXT2_INODES_PER_GROUP(sb)) {
-               if (ext2_set_bit (j, bh->b_data)) {
-                       ext2_error (sb, "ext2_new_inode",
-                                     "bit already set for inode %d", j);
-                       goto repeat;
-               }
-               mark_buffer_dirty(bh);
-               if (sb->s_flags & MS_SYNCHRONOUS) {
-                       ll_rw_block (WRITE, 1, &bh);
-                       wait_on_buffer (bh);
-               }
-       } else {
-               if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
-                       ext2_error (sb, "ext2_new_inode",
-                                   "Free inodes count corrupted in group %d",
-                                   i);
-                       /* Is it really ENOSPC? */
-                       err = -ENOSPC;
-                       if (sb->s_flags & MS_RDONLY)
-                               goto fail;
+               goto fail2;
 
-                       gdp->bg_free_inodes_count = 0;
-                       mark_buffer_dirty(bh2);
-               }
-               goto repeat;
+       j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
+                                             EXT2_INODES_PER_GROUP(sb));
+       if (j >= EXT2_INODES_PER_GROUP(sb))
+               goto bad_count;
+       ext2_set_bit (j, bh->b_data);
+
+       mark_buffer_dirty(bh);
+       if (sb->s_flags & MS_SYNCHRONOUS) {
+               ll_rw_block (WRITE, 1, &bh);
+               wait_on_buffer (bh);
        }
+
        j += i * EXT2_INODES_PER_GROUP(sb) + 1;
        if (j < EXT2_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
                ext2_error (sb, "ext2_new_inode",
                            "reserved inode or inode > inodes count - "
                            "block_group = %d,inode=%d", i, j);
                err = -EIO;
-               goto fail;
+               goto fail2;
        }
-       gdp->bg_free_inodes_count =
-               cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
-       if (S_ISDIR(mode))
-               gdp->bg_used_dirs_count =
-                       cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
-       mark_buffer_dirty(bh2);
+
        es->s_free_inodes_count =
                cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
        mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
@@ -449,10 +449,32 @@
        ext2_debug ("allocating inode %lu\n", inode->i_ino);
        return inode;
 
+fail2:
+       gdp = ext2_get_group_desc (sb, i, &bh2);
+       gdp->bg_free_inodes_count =
+               cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+       if (S_ISDIR(mode))
+               gdp->bg_used_dirs_count =
+                       cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+       mark_buffer_dirty(bh2);
 fail:
        unlock_super(sb);
        iput(inode);
        return ERR_PTR(err);
+
+bad_count:
+       ext2_error (sb, "ext2_new_inode",
+                   "Free inodes count corrupted in group %d",
+                   i);
+       /* Is it really ENOSPC? */
+       err = -ENOSPC;
+       if (sb->s_flags & MS_RDONLY)
+               goto fail;
+
+       gdp = ext2_get_group_desc (sb, i, &bh2);
+       gdp->bg_free_inodes_count = 0;
+       mark_buffer_dirty(bh2);
+       goto repeat;
 }
 
 unsigned long ext2_count_free_inodes (struct super_block * sb)

Reply via email to