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)