Patch from Alex Tomas hi! here is the new version of the patch. changes since the last one: 1) new primitives ext2_set_bit_atomic and ext2_clear_bit_atomic have been introduced. primitives have additional parameter spinlock *, defined for every arch. each arch should use atomic test_and_set_bit/test_and_clear_bit or use ext2_set_bit and ext2_clear_bit serialized by this lock 2) each group has own spinlock, which is used for group counter modifications and may be used to implement ext2_set_bit_atomic/ext2_clear_bit_atomic 3) sb->s_free_blocks_count isn't used any more. ext2_statfs() and find_group_orlov() loop over groups to count free blocks 4) sb->s_free_blocks_count is recalculated at mount/umount/sync_super time in order to check consistency and to avoid fsck warnings 5) reserved blocks are distributed over all groups at mount time 6) ext2_new_block() tries to use non-reserved blocks and if it fails then tries to use reserved blocks 7) ext2_new_block() and ext2_free_blocks do not modify sb->s_free_blocks, therefore they do not call mark_buffer_dirty() for superblock's buffer_head. I think it may reduce I/O a bit fs/ext2/balloc.c | 173 ++++++++++++++++++++--------------------- fs/ext2/ialloc.c | 16 +-- fs/ext2/super.c | 56 ++++++++++--- include/asm-alpha/bitops.h | 2 include/asm-arm/bitops.h | 4 include/asm-cris/bitops.h | 2 include/asm-i386/bitops.h | 4 include/asm-ia64/bitops.h | 2 include/asm-m68k/bitops.h | 20 ++++ include/asm-m68knommu/bitops.h | 20 ++++ include/asm-mips/bitops.h | 20 ++++ include/asm-mips64/bitops.h | 22 +++++ include/asm-parisc/bitops.h | 4 include/asm-ppc/bitops.h | 2 include/asm-ppc64/bitops.h | 4 include/asm-s390/bitops.h | 4 include/asm-s390x/bitops.h | 4 include/asm-sh/bitops.h | 20 ++++ include/asm-sparc/bitops.h | 2 include/asm-sparc64/bitops.h | 2 include/asm-v850/bitops.h | 2 include/asm-x86_64/bitops.h | 4 include/linux/ext2_fs_sb.h | 8 + 23 files changed, 292 insertions(+), 105 deletions(-) diff -puN fs/ext2/balloc.c~ext2-no-lock_super fs/ext2/balloc.c --- 25/fs/ext2/balloc.c~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/fs/ext2/balloc.c 2003-03-13 23:44:21.000000000 -0800 @@ -94,69 +94,62 @@ error_out: return bh; } -static inline int reserve_blocks(struct super_block *sb, int count) +static inline int group_reserve_blocks(struct ext2_sb_info *sbi, struct ext2_bg_info *bgi, + struct ext2_group_desc *desc, + struct buffer_head *bh, int count, int use_reserve) { - struct ext2_sb_info * sbi = EXT2_SB(sb); - struct ext2_super_block * es = sbi->s_es; - unsigned free_blocks = le32_to_cpu(es->s_free_blocks_count); - unsigned root_blocks = le32_to_cpu(es->s_r_blocks_count); + unsigned free_blocks; + unsigned root_blocks; + spin_lock(&bgi->balloc_lock); + + free_blocks = le16_to_cpu(desc->bg_free_blocks_count); if (free_blocks < count) count = free_blocks; + root_blocks = bgi->reserved; - if (free_blocks < root_blocks + count && !capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { - /* - * We are too close to reserve and we are not privileged. - * Can we allocate anything at all? - */ - if (free_blocks > root_blocks) - count = free_blocks - root_blocks; - else - return 0; + if (free_blocks < bgi->reserved && !use_reserve) { + /* don't use reserved blocks */ + spin_unlock(&bgi->balloc_lock); + return 0; } - - es->s_free_blocks_count = cpu_to_le32(free_blocks - count); - mark_buffer_dirty(sbi->s_sbh); - sb->s_dirt = 1; - return count; -} - -static inline void release_blocks(struct super_block *sb, int count) -{ - if (count) { - struct ext2_sb_info * sbi = EXT2_SB(sb); - struct ext2_super_block * es = sbi->s_es; - unsigned free_blocks = le32_to_cpu(es->s_free_blocks_count); - es->s_free_blocks_count = cpu_to_le32(free_blocks + count); - mark_buffer_dirty(sbi->s_sbh); - sb->s_dirt = 1; + + if (free_blocks < bgi->reserved + count && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + /* + * We are too close to reserve and we are not privileged. + * Can we allocate anything at all? + */ + if (free_blocks > bgi->reserved) + count = free_blocks - bgi->reserved; + else { + spin_unlock(&bgi->balloc_lock); + return 0; + } } -} - -static inline int group_reserve_blocks(struct ext2_group_desc *desc, - struct buffer_head *bh, int count) -{ - unsigned free_blocks; - - if (!desc->bg_free_blocks_count) - return 0; - - free_blocks = le16_to_cpu(desc->bg_free_blocks_count); - if (free_blocks < count) - count = free_blocks; desc->bg_free_blocks_count = cpu_to_le16(free_blocks - count); + + spin_unlock(&bgi->balloc_lock); + mark_buffer_dirty(bh); return count; } -static inline void group_release_blocks(struct ext2_group_desc *desc, - struct buffer_head *bh, int count) +static inline void group_release_blocks(struct ext2_bg_info *bgi, + struct ext2_group_desc *desc, + struct buffer_head *bh, int count) { if (count) { - unsigned free_blocks = le16_to_cpu(desc->bg_free_blocks_count); + unsigned free_blocks; + + spin_lock(&bgi->balloc_lock); + + free_blocks = le16_to_cpu(desc->bg_free_blocks_count); desc->bg_free_blocks_count = cpu_to_le16(free_blocks + count); + + spin_unlock(&bgi->balloc_lock); + mark_buffer_dirty(bh); } } @@ -172,12 +165,11 @@ void ext2_free_blocks (struct inode * in unsigned long i; unsigned long overflow; struct super_block * sb = inode->i_sb; + struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_group_desc * desc; - struct ext2_super_block * es; + struct ext2_super_block * es = sbi->s_es; unsigned freed = 0, group_freed; - lock_super (sb); - es = EXT2_SB(sb)->s_es; if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || block + count > le32_to_cpu(es->s_blocks_count)) { @@ -215,16 +207,17 @@ do_more: if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || in_range (block, le32_to_cpu(desc->bg_inode_table), - EXT2_SB(sb)->s_itb_per_group) || + sbi->s_itb_per_group) || in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - EXT2_SB(sb)->s_itb_per_group)) + sbi->s_itb_per_group)) ext2_error (sb, "ext2_free_blocks", "Freeing blocks in system zones - " "Block = %lu, count = %lu", block, count); for (i = 0, group_freed = 0; i < count; i++) { - if (!ext2_clear_bit(bit + i, bitmap_bh->b_data)) + if (!ext2_clear_bit_atomic(&sbi->s_bgi[block_group].balloc_lock, + bit + i, (void *) bitmap_bh->b_data)) ext2_error (sb, "ext2_free_blocks", "bit already cleared for block %lu", block + i); @@ -236,7 +229,7 @@ do_more: if (sb->s_flags & MS_SYNCHRONOUS) sync_dirty_buffer(bitmap_bh); - group_release_blocks(desc, bh2, group_freed); + group_release_blocks(&sbi->s_bgi[block_group], desc, bh2, group_freed); freed += group_freed; if (overflow) { @@ -246,18 +239,18 @@ do_more: } error_return: brelse(bitmap_bh); - release_blocks(sb, freed); - unlock_super (sb); DQUOT_FREE_BLOCK(inode, freed); } -static int grab_block(char *map, unsigned size, int goal) +static int grab_block(spinlock_t *lock, char *map, unsigned size, int goal) { int k; char *p, *r; if (!ext2_test_bit(goal, map)) goto got_it; + +repeat: if (goal) { /* * The goal was occupied; search forward for a free @@ -297,7 +290,8 @@ static int grab_block(char *map, unsigne } return -1; got_it: - ext2_set_bit(goal, map); + if (ext2_set_bit_atomic(lock, goal, (void *) map)) + goto repeat; return goal; } @@ -319,7 +313,7 @@ int ext2_new_block (struct inode * inode int ret_block; /* j */ int bit; /* k */ int target_block; /* tmp */ - int block = 0; + int block = 0, use_reserve = 0; struct super_block *sb = inode->i_sb; struct ext2_sb_info *sbi = EXT2_SB(sb); struct ext2_super_block *es = sbi->s_es; @@ -341,14 +335,7 @@ int ext2_new_block (struct inode * inode prealloc_goal--; dq_alloc = prealloc_goal + 1; - - lock_super (sb); - - es_alloc = reserve_blocks(sb, dq_alloc); - if (!es_alloc) { - *err = -ENOSPC; - goto out_unlock; - } + es_alloc = dq_alloc; ext2_debug ("goal=%lu.\n", goal); @@ -360,7 +347,8 @@ int ext2_new_block (struct inode * inode if (!desc) goto io_error; - group_alloc = group_reserve_blocks(desc, gdp_bh, es_alloc); + group_alloc = group_reserve_blocks(sbi, &sbi->s_bgi[group_no], + desc, gdp_bh, es_alloc, 0); if (group_alloc) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % group_size); @@ -371,11 +359,12 @@ int ext2_new_block (struct inode * inode ext2_debug("goal is at %d:%d.\n", group_no, ret_block); - ret_block = grab_block(bitmap_bh->b_data, + ret_block = grab_block(&sbi->s_bgi[group_no].balloc_lock, + bitmap_bh->b_data, group_size, ret_block); if (ret_block >= 0) goto got_block; - group_release_blocks(desc, gdp_bh, group_alloc); + group_release_blocks(&sbi->s_bgi[group_no], desc, gdp_bh, group_alloc); group_alloc = 0; } @@ -385,6 +374,7 @@ int ext2_new_block (struct inode * inode * Now search the rest of the groups. We assume that * i and desc correctly point to the last group visited. */ +repeat: for (bit = 0; !group_alloc && bit < sbi->s_groups_count; bit++) { group_no++; @@ -393,7 +383,16 @@ int ext2_new_block (struct inode * inode desc = ext2_get_group_desc(sb, group_no, &gdp_bh); if (!desc) goto io_error; - group_alloc = group_reserve_blocks(desc, gdp_bh, es_alloc); + group_alloc = group_reserve_blocks(sbi, &sbi->s_bgi[group_no], + desc, gdp_bh, es_alloc, use_reserve); + } + if (!use_reserve) { + /* first time we did not try to allocate + * reserved blocks. now it looks like + * no more non-reserved blocks left. we + * will try to allocate reserved blocks -bzzz */ + use_reserve = 1; + goto repeat; } if (!group_alloc) { *err = -ENOSPC; @@ -404,13 +403,11 @@ int ext2_new_block (struct inode * inode if (!bitmap_bh) goto io_error; - ret_block = grab_block(bitmap_bh->b_data, group_size, 0); + ret_block = grab_block(&sbi->s_bgi[group_no].balloc_lock, + bitmap_bh->b_data, group_size, 0); if (ret_block < 0) { - ext2_error (sb, "ext2_new_block", - "Free blocks count corrupted for block group %d", - group_no); group_alloc = 0; - goto io_error; + goto repeat; } got_block: @@ -452,7 +449,8 @@ got_block: unsigned n; for (n = 0; n < group_alloc && ++ret_block < group_size; n++) { - if (ext2_set_bit(ret_block, bitmap_bh->b_data)) + if (ext2_set_bit_atomic(&sbi->s_bgi[group_no].balloc_lock, + ret_block, (void*) bitmap_bh->b_data)) break; } *prealloc_block = block + 1; @@ -471,10 +469,7 @@ got_block: *err = 0; out_release: - group_release_blocks(desc, gdp_bh, group_alloc); - release_blocks(sb, es_alloc); -out_unlock: - unlock_super (sb); + group_release_blocks(&sbi->s_bgi[group_no], desc, gdp_bh, group_alloc); DQUOT_FREE_BLOCK(inode, dq_alloc); out: brelse(bitmap_bh); @@ -487,11 +482,11 @@ io_error: unsigned long ext2_count_free_blocks (struct super_block * sb) { -#ifdef EXT2FS_DEBUG - struct ext2_super_block * es; - unsigned long desc_count, bitmap_count, x; struct ext2_group_desc * desc; + unsigned long desc_count = 0; int i; +#ifdef EXT2FS_DEBUG + unsigned long bitmap_count, x; lock_super (sb); es = EXT2_SB(sb)->s_es; @@ -519,7 +514,13 @@ unsigned long ext2_count_free_blocks (st unlock_super (sb); return bitmap_count; #else - return le32_to_cpu(EXT2_SB(sb)->s_es->s_free_blocks_count); + for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { + desc = ext2_get_group_desc (sb, i, NULL); + if (!desc) + continue; + desc_count += le16_to_cpu(desc->bg_free_blocks_count); + } + return desc_count; #endif } diff -puN fs/ext2/ialloc.c~ext2-no-lock_super fs/ext2/ialloc.c --- 25/fs/ext2/ialloc.c~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/fs/ext2/ialloc.c 2003-03-13 23:44:21.000000000 -0800 @@ -278,7 +278,8 @@ static int find_group_orlov(struct super int ngroups = sbi->s_groups_count; int inodes_per_group = EXT2_INODES_PER_GROUP(sb); int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; - int avefreeb = le32_to_cpu(es->s_free_blocks_count) / ngroups; + int free_blocks = ext2_count_free_blocks(sb); + int avefreeb = free_blocks / ngroups; int blocks_per_dir; int ndirs = sbi->s_dir_count; int max_debt, max_dirs, min_blocks, min_inodes; @@ -320,8 +321,7 @@ static int find_group_orlov(struct super goto fallback; } - blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_free_blocks_count)) / ndirs; + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - free_blocks) / ndirs; max_dirs = ndirs / ngroups + inodes_per_group / 16; min_inodes = avefreei - inodes_per_group / 4; @@ -340,7 +340,7 @@ static int find_group_orlov(struct super desc = ext2_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) continue; - if (sbi->s_debts[group] >= max_debt) + if (sbi->s_bgi[group].debts >= max_debt) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) continue; @@ -501,11 +501,11 @@ repeat: cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); if (S_ISDIR(mode)) { - if (EXT2_SB(sb)->s_debts[group] < 255) - EXT2_SB(sb)->s_debts[group]++; + if (EXT2_SB(sb)->s_bgi[group].debts < 255) + EXT2_SB(sb)->s_bgi[group].debts++; } else { - if (EXT2_SB(sb)->s_debts[group]) - EXT2_SB(sb)->s_debts[group]--; + if (EXT2_SB(sb)->s_bgi[group].debts) + EXT2_SB(sb)->s_bgi[group].debts--; } mark_buffer_dirty(EXT2_SB(sb)->s_sbh); diff -puN fs/ext2/super.c~ext2-no-lock_super fs/ext2/super.c --- 25/fs/ext2/super.c~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/fs/ext2/super.c 2003-03-13 23:44:21.000000000 -0800 @@ -141,7 +141,7 @@ static void ext2_put_super (struct super if (sbi->s_group_desc[i]) brelse (sbi->s_group_desc[i]); kfree(sbi->s_group_desc); - kfree(sbi->s_debts); + kfree(sbi->s_bgi); brelse (sbi->s_sbh); sb->s_fs_info = NULL; kfree(sbi); @@ -464,8 +464,11 @@ static int ext2_check_descriptors (struc int i; int desc_block = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); - unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block); + struct ext2_super_block * es = sbi->s_es; + unsigned long block = le32_to_cpu(es->s_first_data_block); struct ext2_group_desc * gdp = NULL; + unsigned int total_free = 0, free; + unsigned int reserved = le32_to_cpu(es->s_r_blocks_count); ext2_debug ("Checking group descriptors"); @@ -504,6 +507,27 @@ static int ext2_check_descriptors (struc block += EXT2_BLOCKS_PER_GROUP(sb); gdp++; } + + /* restore free blocks counter in SB -bzzz */ + es->s_free_blocks_count = total_free = ext2_count_free_blocks(sb); + + /* distribute reserved blocks over groups -bzzz */ + for(i = sbi->s_groups_count-1; reserved && total_free && i >= 0; i--) { + gdp = ext2_get_group_desc (sb, i, NULL); + if (!gdp) { + ext2_error (sb, "ext2_check_descriptors", + "cant get descriptor for group %d", i); + return 0; + } + + free = le16_to_cpu(gdp->bg_free_blocks_count); + if (free > reserved) + free = reserved; + sbi->s_bgi[i].reserved = free; + reserved -= free; + total_free -= free; + } + return 1; } @@ -769,13 +793,17 @@ static int ext2_fill_super(struct super_ printk ("EXT2-fs: not enough memory\n"); goto failed_mount; } - sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), + sbi->s_bgi = kmalloc(sbi->s_groups_count*sizeof(struct ext2_bg_info), GFP_KERNEL); - if (!sbi->s_debts) { + if (!sbi->s_bgi) { printk ("EXT2-fs: not enough memory\n"); goto failed_mount_group_desc; } - memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts)); + for (i = 0; i < sbi->s_groups_count; i++) { + sbi->s_bgi[i].debts = 0; + sbi->s_bgi[i].reserved = 0; + spin_lock_init(&sbi->s_bgi[i].balloc_lock); + } for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); @@ -820,8 +848,8 @@ failed_mount2: brelse(sbi->s_group_desc[i]); failed_mount_group_desc: kfree(sbi->s_group_desc); - if (sbi->s_debts) - kfree(sbi->s_debts); + if (sbi->s_bgi) + kfree(sbi->s_bgi); failed_mount: brelse(bh); failed_sbi: @@ -840,6 +868,7 @@ static void ext2_commit_super (struct su static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) { + es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); es->s_wtime = cpu_to_le32(get_seconds()); mark_buffer_dirty(EXT2_SB(sb)->s_sbh); sync_dirty_buffer(EXT2_SB(sb)->s_sbh); @@ -868,6 +897,7 @@ void ext2_write_super (struct super_bloc ext2_debug ("setting valid to 0\n"); es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); + es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); es->s_mtime = cpu_to_le32(get_seconds()); ext2_sync_super(sb, es); } else @@ -929,7 +959,8 @@ static int ext2_remount (struct super_bl static int ext2_statfs (struct super_block * sb, struct statfs * buf) { struct ext2_sb_info *sbi = EXT2_SB(sb); - unsigned long overhead; + unsigned long overhead, total_free = 0; + struct ext2_group_desc *desc; int i; if (test_opt (sb, MINIX_DF)) @@ -950,9 +981,14 @@ static int ext2_statfs (struct super_blo * block group descriptors. If the sparse superblocks * feature is turned on, then not all groups have this. */ - for (i = 0; i < sbi->s_groups_count; i++) + for (i = 0; i < sbi->s_groups_count; i++) { overhead += ext2_bg_has_super(sb, i) + ext2_bg_num_gdb(sb, i); + + /* sum total free blocks -bzzz */ + desc = ext2_get_group_desc (sb, i, NULL); + total_free += le16_to_cpu(desc->bg_free_blocks_count); + } /* * Every block group has an inode bitmap, a block @@ -965,7 +1001,7 @@ static int ext2_statfs (struct super_blo buf->f_type = EXT2_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = le32_to_cpu(sbi->s_es->s_blocks_count) - overhead; - buf->f_bfree = ext2_count_free_blocks (sb); + buf->f_bfree = total_free; buf->f_bavail = buf->f_bfree - le32_to_cpu(sbi->s_es->s_r_blocks_count); if (buf->f_bfree < le32_to_cpu(sbi->s_es->s_r_blocks_count)) buf->f_bavail = 0; diff -puN include/asm-alpha/bitops.h~ext2-no-lock_super include/asm-alpha/bitops.h --- 25/include/asm-alpha/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-alpha/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -487,7 +487,9 @@ sched_find_first_bit(unsigned long b[3]) #define ext2_set_bit __test_and_set_bit +#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit __test_and_clear_bit +#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a) #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit diff -puN include/asm-arm/bitops.h~ext2-no-lock_super include/asm-arm/bitops.h --- 25/include/asm-arm/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-arm/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -357,8 +357,12 @@ static inline int sched_find_first_bit(u */ #define ext2_set_bit(nr,p) \ __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) +#define ext2_set_bit_atomic(lock,nr,p) \ + test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) #define ext2_clear_bit(nr,p) \ __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) +#define ext2_clear_bit_atomic(lock,nr,p) \ + test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) #define ext2_test_bit(nr,p) \ __test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) #define ext2_find_first_zero_bit(p,sz) \ diff -puN include/asm-cris/bitops.h~ext2-no-lock_super include/asm-cris/bitops.h --- 25/include/asm-cris/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-cris/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -360,7 +360,9 @@ static inline int find_next_zero_bit (vo #define hweight8(x) generic_hweight8(x) #define ext2_set_bit test_and_set_bit +#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit test_and_clear_bit +#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a) #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit diff -puN include/asm-i386/bitops.h~ext2-no-lock_super include/asm-i386/bitops.h --- 25/include/asm-i386/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-i386/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -479,8 +479,12 @@ static __inline__ int ffs(int x) #define ext2_set_bit(nr,addr) \ __test_and_set_bit((nr),(unsigned long*)addr) +#define ext2_set_bit_atomic(lock,nr,addr) \ + test_and_set_bit((nr),(unsigned long*)addr) #define ext2_clear_bit(nr, addr) \ __test_and_clear_bit((nr),(unsigned long*)addr) +#define ext2_clear_bit_atomic(lock,nr, addr) \ + test_and_clear_bit((nr),(unsigned long*)addr) #define ext2_test_bit(nr, addr) test_bit((nr),(unsigned long*)addr) #define ext2_find_first_zero_bit(addr, size) \ find_first_zero_bit((unsigned long*)addr, size) diff -puN include/asm-ia64/bitops.h~ext2-no-lock_super include/asm-ia64/bitops.h --- 25/include/asm-ia64/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-ia64/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -453,7 +453,9 @@ find_next_bit (void *addr, unsigned long #define __clear_bit(nr, addr) clear_bit(nr, addr) #define ext2_set_bit test_and_set_bit +#define ext2_set_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit test_and_clear_bit +#define ext2_clear_atomic(l,n,a) test_and_clear_bit(n,a) #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit diff -puN include/asm-m68k/bitops.h~ext2-no-lock_super include/asm-m68k/bitops.h --- 25/include/asm-m68k/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-m68k/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -354,6 +354,16 @@ ext2_set_bit (int nr, volatile void *vad return retval; } +static inline int +ext2_set_bit_atomic (spinlock_t *lock, int nr, volatile void *vaddr) +{ + int ret; + spin_lock(lock); + ret = ext2_set_bit(nr, vaddr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_clear_bit (int nr, volatile void *vaddr) { @@ -365,6 +375,16 @@ ext2_clear_bit (int nr, volatile void *v return retval; } +static inline int +ext2_clear_bit_atomic (spinlock_t *lock, int nr, volatile void *vaddr) +{ + int ret; + spin_lock(lock); + ret = ext2_clear_bit(nr, vaddr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_test_bit (int nr, const volatile void *vaddr) { diff -puN include/asm-m68knommu/bitops.h~ext2-no-lock_super include/asm-m68knommu/bitops.h --- 25/include/asm-m68knommu/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-m68knommu/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -387,6 +387,16 @@ extern __inline__ int ext2_set_bit(int n return retval; } +static inline int ext2_set_bit_atomic(spinlock_t *lock, int nr, + volatile void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_set_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_clear_bit(int nr, volatile void * addr) { int mask, retval; @@ -402,6 +412,16 @@ extern __inline__ int ext2_clear_bit(int return retval; } +static inline int ext2_clear_bit_atomic(spinlock_t *lock, int nr, + volatile void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_clear_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_test_bit(int nr, const volatile void * addr) { int mask; diff -puN include/asm-mips64/bitops.h~ext2-no-lock_super include/asm-mips64/bitops.h --- 25/include/asm-mips64/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-mips64/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -516,6 +516,16 @@ ext2_set_bit(int nr,void * addr) return retval; } +static inline int +ext2_set_bit_atomic(spinlock_t * lock, int nr, void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_set_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern inline int ext2_clear_bit(int nr, void * addr) { @@ -531,6 +541,16 @@ ext2_clear_bit(int nr, void * addr) return retval; } +static inline int +ext2_clear_bit_atomic(spinlock_t * lock, int nr, void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_clear_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern inline int ext2_test_bit(int nr, const void * addr) { @@ -599,7 +619,9 @@ found_middle: /* Native ext2 byte ordering, just collapse using defines. */ #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr)) +#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr), (addr)) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr)) +#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr), (addr)) #define ext2_test_bit(nr, addr) test_bit((nr), (addr)) #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size)) #define ext2_find_next_zero_bit(addr, size, offset) \ diff -puN include/asm-mips/bitops.h~ext2-no-lock_super include/asm-mips/bitops.h --- 25/include/asm-mips/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-mips/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -810,6 +810,15 @@ extern __inline__ int ext2_set_bit(int n return retval; } +static inline int ext2_set_bit_atomic(spinlock_t * lock, int nr, void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_set_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_clear_bit(int nr, void * addr) { int mask, retval, flags; @@ -824,6 +833,15 @@ extern __inline__ int ext2_clear_bit(int return retval; } +static inline int ext2_clear_bit_atomic(spinlock_t * lock, int nr, void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_clear_bit(nr, addr); + spin_unlock(lock); + return ret; +} + extern __inline__ int ext2_test_bit(int nr, const void * addr) { int mask; @@ -890,7 +908,9 @@ found_middle: /* Native ext2 byte ordering, just collapse using defines. */ #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr)) +#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr), (addr)) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr)) +#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr), (addr)) #define ext2_test_bit(nr, addr) test_bit((nr), (addr)) #define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size)) #define ext2_find_next_zero_bit(addr, size, offset) \ diff -puN include/asm-parisc/bitops.h~ext2-no-lock_super include/asm-parisc/bitops.h --- 25/include/asm-parisc/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-parisc/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -389,10 +389,14 @@ found_middle: */ #ifdef __LP64__ #define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x38, addr) +#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x38, addr) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x38, addr) +#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x38, addr) #else #define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr) +#define ext2_set_bit_atomic(l,nr,addr) test_and_set_bit((nr) ^ 0x18, addr) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr) +#define ext2_clear_bit_atomic(l,nr,addr) test_and_clear_bit((nr) ^ 0x18, addr) #endif #endif /* __KERNEL__ */ diff -puN include/asm-ppc64/bitops.h~ext2-no-lock_super include/asm-ppc64/bitops.h --- 25/include/asm-ppc64/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-ppc64/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -336,8 +336,12 @@ static __inline__ int __test_and_clear_l #define ext2_set_bit(nr,addr) \ __test_and_set_le_bit((nr),(unsigned long*)addr) +#define ext2_set_bit_atomic(lock, nr,addr) \ + test_and_set_le_bit((nr),(unsigned long*)addr) #define ext2_clear_bit(nr, addr) \ __test_and_clear_le_bit((nr),(unsigned long*)addr) +#define ext2_clear_bit_atomic(lock, nr, addr) \ + test_and_clear_le_bit((nr),(unsigned long*)addr) #define ext2_test_bit(nr, addr) test_le_bit((nr),(unsigned long*)addr) #define ext2_find_first_zero_bit(addr, size) \ find_first_zero_le_bit((unsigned long*)addr, size) diff -puN include/asm-ppc/bitops.h~ext2-no-lock_super include/asm-ppc/bitops.h --- 25/include/asm-ppc/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-ppc/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -392,7 +392,9 @@ found_middle: #define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x18, (unsigned long *)(addr)) +#define ext2_set_bit_atomic(lock, nr, addr) test_and_set_bit((nr) ^ 0x18, (unsigned long *)(addr)) #define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x18, (unsigned long *)(addr)) +#define ext2_clear_bit_atomic(lock, nr, addr) test_and_clear_bit((nr) ^ 0x18, (unsigned long *)(addr)) static __inline__ int ext2_test_bit(int nr, __const__ void * addr) { diff -puN include/asm-s390/bitops.h~ext2-no-lock_super include/asm-s390/bitops.h --- 25/include/asm-s390/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-s390/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -805,8 +805,12 @@ extern __inline__ int fls(int x) #define ext2_set_bit(nr, addr) \ test_and_set_bit((nr)^24, (unsigned long *)addr) +#define ext2_set_bit_atomic(lock, nr, addr) \ + test_and_set_bit((nr)^24, (unsigned long *)addr) #define ext2_clear_bit(nr, addr) \ test_and_clear_bit((nr)^24, (unsigned long *)addr) +#define ext2_clear_bit_atomic(lock, nr, addr) \ + test_and_clear_bit((nr)^24, (unsigned long *)addr) #define ext2_test_bit(nr, addr) \ test_bit((nr)^24, (unsigned long *)addr) diff -puN include/asm-s390x/bitops.h~ext2-no-lock_super include/asm-s390x/bitops.h --- 25/include/asm-s390x/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-s390x/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -838,8 +838,12 @@ extern __inline__ int fls(int x) #define ext2_set_bit(nr, addr) \ test_and_set_bit((nr)^56, (unsigned long *)addr) +#define ext2_set_bit_atomic(lock, nr, addr) \ + test_and_set_bit((nr)^56, (unsigned long *)addr) #define ext2_clear_bit(nr, addr) \ test_and_clear_bit((nr)^56, (unsigned long *)addr) +#define ext2_clear_bit_atomic(lock, nr, addr) \ + test_and_clear_bit((nr)^56, (unsigned long *)addr) #define ext2_test_bit(nr, addr) \ test_bit((nr)^56, (unsigned long *)addr) diff -puN include/asm-sh/bitops.h~ext2-no-lock_super include/asm-sh/bitops.h --- 25/include/asm-sh/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-sh/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -265,6 +265,16 @@ static __inline__ int ext2_set_bit(int n return retval; } +static inline int ext2_set_bit_atomic(spinlock_t *lock, + int nr, volatile void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_set_bit(nr, addr); + spin_unlock(lock); + return ret; +} + static __inline__ int ext2_clear_bit(int nr, volatile void * addr) { int mask, retval; @@ -280,6 +290,16 @@ static __inline__ int ext2_clear_bit(int return retval; } +static inline int ext2_clear_bit_atomic(spinlock_t *lock, + int nr, volatile void * addr) +{ + int ret; + spin_lock(lock); + ret = ext2_clear_bit(nr, addr); + spin_unlock(lock); + return ret; +} + static __inline__ int ext2_test_bit(int nr, const volatile void * addr) { int mask; diff -puN include/asm-sparc64/bitops.h~ext2-no-lock_super include/asm-sparc64/bitops.h --- 25/include/asm-sparc64/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-sparc64/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -351,7 +351,9 @@ found_middle: #ifdef __KERNEL__ #define ext2_set_bit(nr,addr) test_and_set_le_bit((nr),(unsigned long *)(addr)) +#define ext2_set_bit_atomic(lock,nr,addr) test_and_set_le_bit((nr),(unsigned long *)(addr)) #define ext2_clear_bit(nr,addr) test_and_clear_le_bit((nr),(unsigned long *)(addr)) +#define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_le_bit((nr),(unsigned long *)(addr)) #define ext2_test_bit(nr,addr) test_le_bit((nr),(unsigned long *)(addr)) #define ext2_find_first_zero_bit(addr, size) \ find_first_zero_le_bit((unsigned long *)(addr), (size)) diff -puN include/asm-sparc/bitops.h~ext2-no-lock_super include/asm-sparc/bitops.h --- 25/include/asm-sparc/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-sparc/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -454,7 +454,9 @@ found_middle: find_next_zero_le_bit((addr), (size), 0) #define ext2_set_bit __test_and_set_le_bit +#define ext2_set_bit_atomic(l,n,a) test_and_set_le_bit(n,a) #define ext2_clear_bit __test_and_clear_le_bit +#define ext2_clear_bit_atomic(l,n,a) test_and_clear_le_bit(n,a) #define ext2_test_bit test_le_bit #define ext2_find_first_zero_bit find_first_zero_le_bit #define ext2_find_next_zero_bit find_next_zero_le_bit diff -puN include/asm-v850/bitops.h~ext2-no-lock_super include/asm-v850/bitops.h --- 25/include/asm-v850/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-v850/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -252,7 +252,9 @@ static inline int sched_find_first_bit(u #define hweight8(x) generic_hweight8 (x) #define ext2_set_bit test_and_set_bit +#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit test_and_clear_bit +#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a) #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit diff -puN include/asm-x86_64/bitops.h~ext2-no-lock_super include/asm-x86_64/bitops.h --- 25/include/asm-x86_64/bitops.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/asm-x86_64/bitops.h 2003-03-13 23:44:21.000000000 -0800 @@ -487,8 +487,12 @@ static __inline__ int ffs(int x) #define ext2_set_bit(nr,addr) \ __test_and_set_bit((nr),(unsigned long*)addr) +#define ext2_set_bit_atomic(lock,nr,addr) \ + test_and_set_bit((nr),(unsigned long*)addr) #define ext2_clear_bit(nr, addr) \ __test_and_clear_bit((nr),(unsigned long*)addr) +#define ext2_clear_bit_atomic(lock,nr,addr) \ + test_and_clear_bit((nr),(unsigned long*)addr) #define ext2_test_bit(nr, addr) test_bit((nr),(unsigned long*)addr) #define ext2_find_first_zero_bit(addr, size) \ find_first_zero_bit((unsigned long*)addr, size) diff -puN include/linux/ext2_fs_sb.h~ext2-no-lock_super include/linux/ext2_fs_sb.h --- 25/include/linux/ext2_fs_sb.h~ext2-no-lock_super 2003-03-13 23:44:21.000000000 -0800 +++ 25-akpm/include/linux/ext2_fs_sb.h 2003-03-13 23:44:21.000000000 -0800 @@ -16,6 +16,12 @@ #ifndef _LINUX_EXT2_FS_SB #define _LINUX_EXT2_FS_SB +struct ext2_bg_info { + u8 debts; + spinlock_t balloc_lock; + unsigned int reserved; +} ____cacheline_aligned_in_smp; + /* * second extended-fs super-block data in memory */ @@ -44,7 +50,7 @@ struct ext2_sb_info { int s_first_ino; u32 s_next_generation; unsigned long s_dir_count; - u8 *s_debts; + struct ext2_bg_info *s_bgi; }; #endif /* _LINUX_EXT2_FS_SB */ _