From 9fc7c63a1d6e9920038ced782390a54888ed70a6 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 01/48] jbd2: fix the way the b_modified flag is cleared Currently at the start of a journal commit we loop through all of the buffers on the committing transaction and clear the b_modified flag (the flag that is set when a transaction modifies the buffer) under the j_list_lock. The problem is that everywhere else this flag is modified only under the jbd2 lock buffer flag, so it will race with a running transaction who could potentially set it, and have it unset by the committing transaction. This is also a big waste, you can have several thousands of buffers that you are clearing the modified flag on when you may not need to. This patch removes this code and instead clears the b_modified flag upon entering do_get_write_access/journal_get_create_access, so if that transaction does indeed use the buffer then it will be accounted for properly, and if it does not then we know we didn't use it. That will be important for the next patch in this series. Tested thoroughly by myself using postmark/iozone/bonnie++. Cc: Cc: Jan Kara Signed-off-by: Josef Bacik Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 16 ---------------- fs/jbd2/transaction.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index a8173081f83..988fbec1143 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -519,22 +519,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) jbd_debug (3, "JBD: commit phase 2\n"); - /* - * First, drop modified flag: all accesses to the buffers - * will be tracked for a new trasaction only -bzzz - */ - spin_lock(&journal->j_list_lock); - if (commit_transaction->t_buffers) { - new_jh = jh = commit_transaction->t_buffers->b_tnext; - do { - J_ASSERT_JH(new_jh, new_jh->b_modified == 1 || - new_jh->b_modified == 0); - new_jh->b_modified = 0; - new_jh = new_jh->b_tnext; - } while (new_jh != jh); - } - spin_unlock(&journal->j_list_lock); - /* * Now start flushing things to disk, in the order they appear * on the transaction lists. Data blocks go first. diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index b9b0b6f899b..9dc71a6b62e 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -617,6 +617,12 @@ repeat: jh->b_next_transaction == transaction) goto done; + /* + * this is the first time this transaction is touching this buffer, + * reset the modified flag + */ + jh->b_modified = 0; + /* * If there is already a copy-out version of this buffer, then we don't * need to make another one @@ -829,9 +835,16 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == NULL) { jh->b_transaction = transaction; + + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); } else if (jh->b_transaction == journal->j_committing_transaction) { + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; } From 1dfc3220d963385a317264b11154c462a83596ed Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 02/48] jbd2: fix possible journal overflow issues There are several cases where the running transaction can get buffers added to its BJ_Metadata list which it never dirtied, which makes its t_nr_buffers counter end up larger than its t_outstanding_credits counter. This will cause issues when starting new transactions as while we are logging buffers we decrement t_outstanding_buffers, so when t_outstanding_buffers goes negative, we will report that we need less space in the journal than we actually need, so transactions will be started even though there may not be enough room for them. In the worst case scenario (which admittedly is almost impossible to reproduce) this will result in the journal running out of space. The fix is to only refile buffers from the committing transaction to the running transactions BJ_Modified list when b_modified is set on that journal, which is the only way to be sure if the running transaction has modified that buffer. This patch also fixes an accounting error in journal_forget, it is possible that we can call journal_forget on a buffer without having modified it, only gotten write access to it, so instead of freeing a credit, we only do so if the buffer was modified. The assert will help catch if this problem occurs. Without these two patches I could hit this assert within minutes of running postmark, with them this issue no longer arises. Cc: Cc: Jan Kara Signed-off-by: Josef Bacik Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/jbd2/commit.c | 3 +++ fs/jbd2/transaction.c | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 988fbec1143..e0139786f71 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -568,6 +568,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) stats.u.run.rs_blocks = commit_transaction->t_outstanding_credits; stats.u.run.rs_blocks_logged = 0; + J_ASSERT(commit_transaction->t_nr_buffers <= + commit_transaction->t_outstanding_credits); + descriptor = NULL; bufs = 0; while (commit_transaction->t_buffers) { diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 9dc71a6b62e..70245d6638b 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1243,6 +1243,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) struct journal_head *jh; int drop_reserve = 0; int err = 0; + int was_modified = 0; BUFFER_TRACE(bh, "entry"); @@ -1261,6 +1262,9 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) goto not_jbd; } + /* keep track of wether or not this transaction modified us */ + was_modified = jh->b_modified; + /* * The buffer's going from the transaction, we must drop * all references -bzzz @@ -1278,7 +1282,12 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); - drop_reserve = 1; + /* + * we only want to drop a reference if this transaction + * modified the buffer + */ + if (was_modified) + drop_reserve = 1; /* * We are no longer going to journal this buffer. @@ -1318,7 +1327,13 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) if (jh->b_next_transaction) { J_ASSERT(jh->b_next_transaction == transaction); jh->b_next_transaction = NULL; - drop_reserve = 1; + + /* + * only drop a reference if this transaction modified + * the buffer + */ + if (was_modified) + drop_reserve = 1; } } @@ -2090,7 +2105,7 @@ void __jbd2_journal_refile_buffer(struct journal_head *jh) jh->b_transaction = jh->b_next_transaction; jh->b_next_transaction = NULL; __jbd2_journal_file_buffer(jh, jh->b_transaction, - was_dirty ? BJ_Metadata : BJ_Reserved); + jh->b_modified ? BJ_Metadata : BJ_Reserved); J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); if (was_dirty) From 97bd42b9c8be748ad85b362ba3bd401f4d35be80 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 29 Apr 2008 22:04:56 -0400 Subject: [PATCH 03/48] ext4: check return of ext4_orphan_get properly This patch fix a panic while running fsfuzzer. We are improperly checking the return of ext4_orphan_get. Signed-off-by: Josef Bacik Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c81a8e759ba..425f42778ef 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1594,8 +1594,8 @@ static void ext4_orphan_cleanup (struct super_block * sb, while (es->s_last_orphan) { struct inode *inode; - if (!(inode = - ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { + inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); + if (IS_ERR(inode)) { es->s_last_orphan = 0; break; } From 53c550e9750434ddc4275fe0405170e0d1b46731 Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 04/48] ext4: fdatasync should skip metadata writeout when overwriting Currently fdatasync is identical to fsync in ext3. I think fdatasync should skip journal flush in data=ordered and data=writeback mode when it overwrites to already-instantiated blocks on HDD. When I_DIRTY_DATASYNC flag is not set, fdatasync should skip journal writeout because this indicates only atime or/and mtime updates. Following patch is the same approach of ext2's fsync code(ext2_sync_file). I did a performance test using the sysbench. #sysbench --num-threads=128 --max-requests=50000 --test=fileio --file-total-size=128G --file-test-mode=rndwr --file-fsync-mode=fdatasync run The result on ext3 was: -2.6.24 Operations performed: 0 Read, 50080 Write, 59600 Other = 109680 Total Read 0b Written 782.5Mb Total transferred 782.5Mb (12.116Mb/sec) 775.45 Requests/sec executed Test execution summary: total time: 64.5814s total number of events: 50080 total time taken by event execution: 3713.9836 per-request statistics: min: 0.0000s avg: 0.0742s max: 0.9375s approx. 95 percentile: 0.2901s Threads fairness: events (avg/stddev): 391.2500/23.26 execution time (avg/stddev): 29.0155/1.99 -2.6.24-patched Operations performed: 0 Read, 50009 Write, 61596 Other = 111605 Total Read 0b Written 781.39Mb Total transferred 781.39Mb (16.419Mb/sec) 1050.83 Requests/sec executed Test execution summary: total time: 47.5900s total number of events: 50009 total time taken by event execution: 2934.5768 per-request statistics: min: 0.0000s avg: 0.0587s max: 0.8938s approx. 95 percentile: 0.1993s Threads fairness: events (avg/stddev): 390.6953/22.64 execution time (avg/stddev): 22.9264/1.17 Filesystem I/O throughput was improved. Signed-off-by :Hisashi Hifumi Acked-by: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/ext4/fsync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 8d50879d1c2..a04a1ac4e0c 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -72,6 +72,9 @@ int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync) goto out; } + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + goto out; + /* * The VFS has written the file data. If the inode is unaltered * then we need not start a commit. From f3f12faa7414595f502721c90c34deccc1a03c71 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 29 Apr 2008 22:05:28 -0400 Subject: [PATCH 05/48] ext4: fix mount option parsing The "resize" option won't be noticed as it comes after the NULL option, so if you try to mount (or in this case remount) with that option it won't be recognized. Cc: Signed-off-by: Josef Bacik Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 425f42778ef..9d2d9a7fdea 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -945,8 +945,8 @@ static match_table_t tokens = { {Opt_mballoc, "mballoc"}, {Opt_nomballoc, "nomballoc"}, {Opt_stripe, "stripe=%u"}, - {Opt_err, NULL}, {Opt_resize, "resize"}, + {Opt_err, NULL}, }; static ext4_fsblk_t get_sb_block(void **data) From 95c3889cb88ca4833096553c12cde9e7eb792f4c Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 06/48] ext4: Fix fallocate error path Put the old extent details back if we fail to split the uninitialized extent. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9ae6e67090c..a38f3242782 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2154,7 +2154,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ext4_lblk_t iblock, unsigned long max_blocks) { - struct ext4_extent *ex, newex; + struct ext4_extent *ex, newex, orig_ex; struct ext4_extent *ex1 = NULL; struct ext4_extent *ex2 = NULL; struct ext4_extent *ex3 = NULL; @@ -2173,6 +2173,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, allocated = ee_len - (iblock - ee_block); newblock = iblock - ee_block + ext_pblock(ex); ex2 = ex; + orig_ex.ee_block = ex->ee_block; + orig_ex.ee_len = cpu_to_le16(ee_len); + ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); err = ext4_ext_get_access(handle, inode, path + depth); if (err) @@ -2201,13 +2204,25 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex3->ee_len = cpu_to_le16(allocated - max_blocks); ext4_ext_mark_uninitialized(ex3); err = ext4_ext_insert_extent(handle, inode, path, ex3); - if (err) + if (err) { + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_mark_uninitialized(ex); + ext4_ext_dirty(handle, inode, path + depth); goto out; + } /* * The depth, and hence eh & ex might change * as part of the insert above. */ newdepth = ext_depth(inode); + /* + * update the extent length after successfull insert of the + * split extent + */ + orig_ex.ee_len = cpu_to_le16(ee_len - + ext4_ext_get_actual_len(ex3)); if (newdepth != depth) { depth = newdepth; ext4_ext_drop_refs(path); @@ -2282,6 +2297,13 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; insert: err = ext4_ext_insert_extent(handle, inode, path, &newex); + if (err) { + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_mark_uninitialized(ex); + ext4_ext_dirty(handle, inode, path + depth); + } out: return err ? err : allocated; } From e65187e6d0d541f992e684f88a7e090dcff1aac8 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 07/48] ext4: Enable extent format for symlinks. This patch enables extent-formatted normal symlinks. Using extents format allows a symlink to refer to a block number larger than 2^32 on large filesystems. We still don't enable extent format for fast symlinks, which are contained in the inode itself. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/ialloc.c | 4 ++-- fs/ext4/namei.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 486e46a3918..cb14646117f 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -750,8 +750,8 @@ got: goto fail_free_drop; } if (test_opt(sb, EXTENTS)) { - /* set extent flag only for directory and file */ - if (S_ISDIR(mode) || S_ISREG(mode)) { + /* set extent flag only for diretory, file and normal symlink*/ + if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL; ext4_ext_tree_init(handle, inode); err = ext4_update_incompat_feature(handle, sb, diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 28aa2ed4297..68611945687 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2217,6 +2217,8 @@ retry: goto out_stop; } } else { + /* clear the extent format for fast symlink */ + EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL; inode->i_op = &ext4_fast_symlink_inode_operations; memcpy((char*)&EXT4_I(inode)->i_data,symname,l); inode->i_size = l-1; From 3653f3abe37f334659eea9d889cf8dc798fc4baa Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 08/48] arm: Export empty_zero_page for ZERO_PAGE usage in modules. ext4 uses ZERO_PAGE(0) to zero out blocks. We need to export different symbols in different arches for the usage of ZERO_PAGE in modules. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- arch/arm/mm/mmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index d41a75ed3dc..2d6d682c206 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -35,6 +35,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; * zero-initialized data and COW. */ struct page *empty_zero_page; +EXPORT_SYMBOL(empty_zero_page); /* * The pmd table for the upper-most set of pages. From 5fcf4303037a648f7b3e40c9a73361879852efe7 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 09/48] m68k: Export empty_zero_page for ZERO_PAGE usage in modules. ext4 uses ZERO_PAGE(0) to zero out blocks. We need to export different symbols in different arches for the usage of ZERO_PAGE in modules. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- arch/m68k/mm/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index a2bb01f5964..d8fb9c5303c 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -69,6 +69,7 @@ void __init m68k_setup_node(int node) */ void *empty_zero_page; +EXPORT_SYMBOL(empty_zero_page); void show_mem(void) { From 35802c0b2bab71695f131f981d95fcea7432c99b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 10/48] sparc: Export symbols for ZERO_PAGE usage in modules. ext4 uses ZERO_PAGE(0) to zero out blocks. We need to export different symbols in different arches for the usage of ZERO_PAGE in modules. Signed-off-by: Aneesh Kumar K.V Acked-by: David S. Miller Signed-off-by: "Theodore Ts'o" --- arch/sparc/kernel/sparc_ksyms.c | 2 ++ arch/sparc64/mm/init.c | 1 + 2 files changed, 3 insertions(+) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 0bcf98a7ef3..aa8ee06cf48 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -282,3 +282,5 @@ EXPORT_SYMBOL(do_BUG); /* Sun Power Management Idle Handler */ EXPORT_SYMBOL(pm_idle); + +EXPORT_SYMBOL(empty_zero_page); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 8c2b50e8abc..4cad0b32b0a 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -160,6 +160,7 @@ extern unsigned int sparc_ramdisk_image; extern unsigned int sparc_ramdisk_size; struct page *mem_map_zero __read_mostly; +EXPORT_SYMBOL(mem_map_zero); unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly; From 093a088b76352e0a6fdca84eb78b3aa65fbe6dd1 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 11/48] ext4: ENOSPC error handling for writing to an uninitialized extent This patch handles possible ENOSPC errors when writing to an uninitialized extent in case the filesystem is full. A write to a prealloc area causes the split of an unititalized extent into initialized and uninitialized extents. If we don't have space to add new extent information, instead of returning error, convert the existing uninitialized extent to initialized one. We need to zero out the blocks corresponding to the entire extent to prevent uninitialized data reaching userspace. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 106 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a38f3242782..d279ea8c466 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2138,6 +2138,80 @@ void ext4_ext_release(struct super_block *sb) #endif } +static void bi_complete(struct bio *bio, int error) +{ + complete((struct completion *)bio->bi_private); +} + +/* FIXME!! we need to try to merge to left or right after zero-out */ +static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) +{ + int ret = -EIO; + struct bio *bio; + int blkbits, blocksize; + sector_t ee_pblock; + struct completion event; + unsigned int ee_len, len, done, offset; + + + blkbits = inode->i_blkbits; + blocksize = inode->i_sb->s_blocksize; + ee_len = ext4_ext_get_actual_len(ex); + ee_pblock = ext_pblock(ex); + + /* convert ee_pblock to 512 byte sectors */ + ee_pblock = ee_pblock << (blkbits - 9); + + while (ee_len > 0) { + + if (ee_len > BIO_MAX_PAGES) + len = BIO_MAX_PAGES; + else + len = ee_len; + + bio = bio_alloc(GFP_NOIO, len); + if (!bio) + return -ENOMEM; + bio->bi_sector = ee_pblock; + bio->bi_bdev = inode->i_sb->s_bdev; + + done = 0; + offset = 0; + while (done < len) { + ret = bio_add_page(bio, ZERO_PAGE(0), + blocksize, offset); + if (ret != blocksize) { + /* + * We can't add any more pages because of + * hardware limitations. Start a new bio. + */ + break; + } + done++; + offset += blocksize; + if (offset >= PAGE_CACHE_SIZE) + offset = 0; + } + + init_completion(&event); + bio->bi_private = &event; + bio->bi_end_io = bi_complete; + submit_bio(WRITE, bio); + wait_for_completion(&event); + + if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + ret = 0; + else { + ret = -EIO; + break; + } + bio_put(bio); + ee_len -= done; + ee_pblock += done << (blkbits - 9); + } + return ret; +} + /* * This function is called by ext4_ext_get_blocks() if someone tries to write * to an uninitialized extent. It may result in splitting the uninitialized @@ -2204,14 +2278,19 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex3->ee_len = cpu_to_le16(allocated - max_blocks); ext4_ext_mark_uninitialized(ex3); err = ext4_ext_insert_extent(handle, inode, path, ex3); - if (err) { + if (err == -ENOSPC) { + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) + goto fix_extent_len; + /* update the extent length and mark as initialized */ ex->ee_block = orig_ex.ee_block; ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); - ext4_ext_mark_uninitialized(ex); ext4_ext_dirty(handle, inode, path + depth); - goto out; - } + return le16_to_cpu(ex->ee_len); + + } else if (err) + goto fix_extent_len; /* * The depth, and hence eh & ex might change * as part of the insert above. @@ -2297,15 +2376,28 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; insert: err = ext4_ext_insert_extent(handle, inode, path, &newex); - if (err) { + if (err == -ENOSPC) { + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) + goto fix_extent_len; + /* update the extent length and mark as initialized */ ex->ee_block = orig_ex.ee_block; ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); - ext4_ext_mark_uninitialized(ex); ext4_ext_dirty(handle, inode, path + depth); - } + return le16_to_cpu(ex->ee_len); + } else if (err) + goto fix_extent_len; out: return err ? err : allocated; + +fix_extent_len: + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_mark_uninitialized(ex); + ext4_ext_dirty(handle, inode, path + depth); + return err; } /* From 3977c965ec35ce1a7eac988ad313f0fc9aee9660 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 12/48] ext4: zero out small extents when writing to prealloc area. If the preallocated area is small zero out the full extent instead of splitting them. This should avoid the "write every alternate block" problem that could grow the number of extents dramatically. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index d279ea8c466..668d82e494d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2212,6 +2212,8 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) return ret; } +#define EXT4_EXT_ZERO_LEN 7 + /* * This function is called by ext4_ext_get_blocks() if someone tries to write * to an uninitialized extent. It may result in splitting the uninitialized @@ -2254,6 +2256,18 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, err = ext4_ext_get_access(handle, inode, path + depth); if (err) goto out; + /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */ + if (ee_len <= 2*EXT4_EXT_ZERO_LEN) { + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) + goto fix_extent_len; + /* update the extent length and mark as initialized */ + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_dirty(handle, inode, path + depth); + return le16_to_cpu(ex->ee_len); + } /* ex1: ee_block to iblock - 1 : uninitialized */ if (iblock > ee_block) { @@ -2272,6 +2286,38 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, /* ex3: to ee_block + ee_len : uninitialised */ if (allocated > max_blocks) { unsigned int newdepth; + /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ + if (allocated <= EXT4_EXT_ZERO_LEN) { + /* Mark first half uninitialized. + * Mark second half initialized and zero out the + * initialized extent + */ + ex->ee_block = orig_ex.ee_block; + ex->ee_len = cpu_to_le16(ee_len - allocated); + ext4_ext_mark_uninitialized(ex); + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_dirty(handle, inode, path + depth); + + ex3 = &newex; + ex3->ee_block = cpu_to_le32(iblock); + ext4_ext_store_pblock(ex3, newblock); + ex3->ee_len = cpu_to_le16(allocated); + err = ext4_ext_insert_extent(handle, inode, path, ex3); + if (err == -ENOSPC) { + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) + goto fix_extent_len; + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_dirty(handle, inode, path + depth); + return le16_to_cpu(ex->ee_len); + + } else if (err) + goto fix_extent_len; + + return allocated; + } ex3 = &newex; ex3->ee_block = cpu_to_le32(iblock + max_blocks); ext4_ext_store_pblock(ex3, newblock + max_blocks); @@ -2320,6 +2366,23 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; } allocated = max_blocks; + + /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying + * to insert a extent in the middle zerout directly + * otherwise give the extent a chance to merge to left + */ + if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN && + iblock != ee_block) { + err = ext4_ext_zeroout(inode, &orig_ex); + if (err) + goto fix_extent_len; + /* update the extent length and mark as initialized */ + ex->ee_block = orig_ex.ee_block; + ex->ee_len = orig_ex.ee_len; + ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); + ext4_ext_dirty(handle, inode, path + depth); + return le16_to_cpu(ex->ee_len); + } } /* * If there was a change of depth as part of the From 267e4db9ac28a09973476e7ec2cb6807e609d35a Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 13/48] ext4: Fix race between migration and mmap write Fail migrate if we allocated new blocks via mmap write. If we write to holes in the file via mmap, we end up allocating new blocks. This block allocation happens without taking inode->i_mutex. Since migrate is protected by i_mutex and migrate expects that no new blocks get allocated during migrate, fail migrate if new blocks get allocated. We can't take inode->i_mutex in the mmap write path because that would result in a locking order violation between i_mutex and mmap_sem. Also adding a separate rw_sempahore for protection is really high overhead for a rare operation such as migrate. Signed-off-by: Aneesh Kumar K.V Acked-by: Jan Kara Signed-off-by: "Theodore Ts'o" --- fs/ext4/inode.c | 13 ++++++++++++- fs/ext4/migrate.c | 39 ++++++++++++++++++++++++++++++++++----- include/linux/ext4_fs.h | 1 + 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8fab233cb05..24a2604dde7 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -985,6 +985,16 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, } else { retval = ext4_get_blocks_handle(handle, inode, block, max_blocks, bh, create, extend_disksize); + + if (retval > 0 && buffer_new(bh)) { + /* + * We allocated new blocks which will result in + * i_data's format changing. Force the migrate + * to fail by clearing migrate flags + */ + EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags & + ~EXT4_EXT_MIGRATE; + } } up_write((&EXT4_I(inode)->i_data_sem)); return retval; @@ -2976,7 +2986,8 @@ static int ext4_do_update_inode(handle_t *handle, if (ext4_inode_blocks_set(handle, raw_inode, ei)) goto out_brelse; raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); - raw_inode->i_flags = cpu_to_le32(ei->i_flags); + /* clear the migrate flag in the raw_inode */ + raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE); if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != cpu_to_le32(EXT4_OS_HURD)) raw_inode->i_file_acl_high = diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 5c1e27de775..9b4fb07d192 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -327,7 +327,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) } static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, - struct inode *tmp_inode) + struct inode *tmp_inode) { int retval; __le32 i_data[3]; @@ -339,7 +339,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, * i_data field of the original inode */ retval = ext4_journal_extend(handle, 1); - if (retval != 0) { + if (retval) { retval = ext4_journal_restart(handle, 1); if (retval) goto err_out; @@ -350,6 +350,18 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, i_data[2] = ei->i_data[EXT4_TIND_BLOCK]; down_write(&EXT4_I(inode)->i_data_sem); + /* + * if EXT4_EXT_MIGRATE is cleared a block allocation + * happened after we started the migrate. We need to + * fail the migrate + */ + if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) { + retval = -EAGAIN; + up_write(&EXT4_I(inode)->i_data_sem); + goto err_out; + } else + EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags & + ~EXT4_EXT_MIGRATE; /* * We have the extent map build with the tmp inode. * Now copy the i_data across @@ -508,6 +520,17 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp, * switch the inode format to prevent read. */ mutex_lock(&(inode->i_mutex)); + /* + * Even though we take i_mutex we can still cause block allocation + * via mmap write to holes. If we have allocated new blocks we fail + * migrate. New block allocation will clear EXT4_EXT_MIGRATE flag. + * The flag is updated with i_data_sem held to prevent racing with + * block allocation. + */ + down_read((&EXT4_I(inode)->i_data_sem)); + EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE; + up_read((&EXT4_I(inode)->i_data_sem)); + handle = ext4_journal_start(inode, 1); ei = EXT4_I(inode); @@ -559,9 +582,15 @@ err_out: * tmp_inode */ free_ext_block(handle, tmp_inode); - else - retval = ext4_ext_swap_inode_data(handle, inode, - tmp_inode); + else { + retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode); + if (retval) + /* + * if we fail to swap inode data free the extent + * details of the tmp inode + */ + free_ext_block(handle, tmp_inode); + } /* We mark the tmp_inode dirty via ext4_ext_tree_init. */ if (ext4_journal_extend(handle, 1) != 0) diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 25003254859..105337ca9ed 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -231,6 +231,7 @@ struct ext4_group_desc #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ +#define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */ #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ From fd28784adc079afa905df56204b1298ddb4d0bfe Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 14/48] ext4: Fix fallocate to update the file size in each transaction ext4_fallocate needs to update file size in each transaction. Otherwise if we crash the file size won't be seen. We were also not marking the inode dirty after updating file size before. Also when we try to retry allocation due to ENOSPC, make sure we reset the variable ret so that we actually do a retry. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 89 ++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 668d82e494d..c2b004e29ad 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2785,6 +2785,28 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num) return needed; } +static void ext4_falloc_update_inode(struct inode *inode, + int mode, loff_t new_size, int update_ctime) +{ + struct timespec now; + + if (update_ctime) { + now = current_fs_time(inode->i_sb); + if (!timespec_equal(&inode->i_ctime, &now)) + inode->i_ctime = now; + } + /* + * Update only when preallocation was requested beyond + * the file size. + */ + if (!(mode & FALLOC_FL_KEEP_SIZE) && + new_size > i_size_read(inode)) { + i_size_write(inode, new_size); + EXT4_I(inode)->i_disksize = new_size; + } + +} + /* * preallocate space for a file. This implements ext4's fallocate inode * operation, which gets called from sys_fallocate system call. @@ -2796,8 +2818,8 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) { handle_t *handle; ext4_lblk_t block; + loff_t new_size; unsigned long max_blocks; - ext4_fsblk_t nblocks = 0; int ret = 0; int ret2 = 0; int retries = 0; @@ -2816,9 +2838,12 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) return -ENODEV; block = offset >> blkbits; + /* + * We can't just convert len to max_blocks because + * If blocksize = 4096 offset = 3072 and len = 2048 + */ max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) - - block; - + - block; /* * credits to insert 1 extent into extent tree + buffers to be able to * modify 1 super block, 1 block bitmap and 1 group descriptor. @@ -2834,7 +2859,6 @@ retry: ret = PTR_ERR(handle); break; } - ret = ext4_get_blocks_wrap(handle, inode, block, max_blocks, &map_bh, EXT4_CREATE_UNINITIALIZED_EXT, 0); @@ -2850,61 +2874,24 @@ retry: ret2 = ext4_journal_stop(handle); break; } - if (ret > 0) { - /* check wrap through sign-bit/zero here */ - if ((block + ret) < 0 || (block + ret) < block) { - ret = -EIO; - ext4_mark_inode_dirty(handle, inode); - ret2 = ext4_journal_stop(handle); - break; - } - if (buffer_new(&map_bh) && ((block + ret) > - (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits) - >> blkbits))) - nblocks = nblocks + ret; - } - - /* Update ctime if new blocks get allocated */ - if (nblocks) { - struct timespec now; - - now = current_fs_time(inode->i_sb); - if (!timespec_equal(&inode->i_ctime, &now)) - inode->i_ctime = now; - } + if ((block + ret) >= (EXT4_BLOCK_ALIGN(offset + len, + blkbits) >> blkbits)) + new_size = offset + len; + else + new_size = (block + ret) << blkbits; + ext4_falloc_update_inode(inode, mode, new_size, + buffer_new(&map_bh)); ext4_mark_inode_dirty(handle, inode); ret2 = ext4_journal_stop(handle); if (ret2) break; } - - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + if (ret == -ENOSPC && + ext4_should_retry_alloc(inode->i_sb, &retries)) { + ret = 0; goto retry; - - /* - * Time to update the file size. - * Update only when preallocation was requested beyond the file size. - */ - if (!(mode & FALLOC_FL_KEEP_SIZE) && - (offset + len) > i_size_read(inode)) { - if (ret > 0) { - /* - * if no error, we assume preallocation succeeded - * completely - */ - i_size_write(inode, offset + len); - EXT4_I(inode)->i_disksize = i_size_read(inode); - } else if (ret < 0 && nblocks) { - /* Handle partial allocation scenario */ - loff_t newsize; - - newsize = (nblocks << blkbits) + i_size_read(inode); - i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits)); - EXT4_I(inode)->i_disksize = i_size_read(inode); - } } - mutex_unlock(&inode->i_mutex); return ret > 0 ? ret2 : ret; } From e067ba0078cd6f00eb6c4052fec630b78ebe59de Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 15/48] ext4: make ext4_ext_get_blocks always return <= max_blocks ext4_ext_get_blocks() returns number of blocks allocated with buffer heads unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already resevred on disk. Fix ext4_ext_get_blocks to not return greater than max_blocks, since some of the code paths cannot handle such a return value. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index c2b004e29ad..f4ef0b745a5 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2570,8 +2570,18 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, } if (create == EXT4_CREATE_UNINITIALIZED_EXT) goto out; - if (!create) + if (!create) { + /* + * We have blocks reserved already. We + * return allocated blocks so that delalloc + * won't do block reservation for us. But + * the buffer head will be unmapped so that + * a read from the block returns 0s. + */ + if (allocated > max_blocks) + allocated = max_blocks; goto out2; + } ret = ext4_ext_convert_to_initialized(handle, inode, path, iblock, From 1a89734d4057066344356e9c7e13b6379497aebe Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 16/48] ext4: Return unwritten buffer head when trying to read from prealloc space. ext4_ext_get_blocks() returns the number of blocks allocated with buffer head unmapped for a read from prealloc space. This is needed so that delayed allocation doesn't do block reservation for prealloc space since the blocks are already reserved on disk. Mark the buffer head unwritten. Some code paths try to read the block if the buffer_head is not new and no uptodate. Marking the buffer head unwritten avoids this reading. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index f4ef0b745a5..7733e294336 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2580,6 +2580,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, */ if (allocated > max_blocks) allocated = max_blocks; + /* mark the buffer unwritten */ + __set_bit(BH_Unwritten, &bh_result->b_state); goto out2; } From 161e7b7c1d24112d188df9a7b30d468a8d135b96 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 22:03:59 -0400 Subject: [PATCH 17/48] ext4: Cache the correct extent length for uninit extents When we convert an uninitialized extent to an initialized extent we need to make sure we return the number of blocks in the extent from the file system block corresponding to logical file block. Otherwise we cache wrong extent details and this results in file system corruption. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 48 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 7733e294336..c7c42c9c7bf 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2266,7 +2266,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); ext4_ext_dirty(handle, inode, path + depth); - return le16_to_cpu(ex->ee_len); + /* zeroed the full extent */ + return allocated; } /* ex1: ee_block to iblock - 1 : uninitialized */ @@ -2311,11 +2312,45 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); ext4_ext_dirty(handle, inode, path + depth); - return le16_to_cpu(ex->ee_len); + /* zeroed the full extent */ + return allocated; } else if (err) goto fix_extent_len; + /* + * We need to zero out the second half because + * an fallocate request can update file size and + * converting the second half to initialized extent + * implies that we can leak some junk data to user + * space. + */ + err = ext4_ext_zeroout(inode, ex3); + if (err) { + /* + * We should actually mark the + * second half as uninit and return error + * Insert would have changed the extent + */ + depth = ext_depth(inode); + ext4_ext_drop_refs(path); + path = ext4_ext_find_extent(inode, + iblock, path); + if (IS_ERR(path)) { + err = PTR_ERR(path); + return err; + } + ex = path[depth].p_ext; + err = ext4_ext_get_access(handle, inode, + path + depth); + if (err) + return err; + ext4_ext_mark_uninitialized(ex); + ext4_ext_dirty(handle, inode, path + depth); + return err; + } + + /* zeroed the second half */ return allocated; } ex3 = &newex; @@ -2333,7 +2368,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); ext4_ext_dirty(handle, inode, path + depth); - return le16_to_cpu(ex->ee_len); + /* zeroed the full extent */ + return allocated; } else if (err) goto fix_extent_len; @@ -2381,7 +2417,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); ext4_ext_dirty(handle, inode, path + depth); - return le16_to_cpu(ex->ee_len); + /* zero out the first half */ + return allocated; } } /* @@ -2448,7 +2485,8 @@ insert: ex->ee_len = orig_ex.ee_len; ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); ext4_ext_dirty(handle, inode, path + depth); - return le16_to_cpu(ex->ee_len); + /* zero out the first half */ + return allocated; } else if (err) goto fix_extent_len; out: From 5cdd7b2d7716a7ed7d6dc7588e2d015f04d46640 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 29 Apr 2008 22:03:54 -0400 Subject: [PATCH 18/48] Convert ext4 to use unlocked_ioctl I checked ext4_ioctl and it looked largely safe to not be used without BKL. So convert it over to unlocked_ioctl. Signed-off-by: Andi Kleen Signed-off-by: Theodore Ts'o --- fs/ext4/dir.c | 2 +- fs/ext4/file.c | 2 +- fs/ext4/ioctl.c | 12 +++--------- include/linux/ext4_fs.h | 3 +-- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 2c23bade9aa..88c97f7312b 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -42,7 +42,7 @@ const struct file_operations ext4_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = ext4_readdir, /* we take BKL. needed?*/ - .ioctl = ext4_ioctl, /* BKL held */ + .unlocked_ioctl = ext4_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext4_compat_ioctl, #endif diff --git a/fs/ext4/file.c b/fs/ext4/file.c index ac35ec58db5..20507a24506 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -129,7 +129,7 @@ const struct file_operations ext4_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = ext4_file_write, - .ioctl = ext4_ioctl, + .unlocked_ioctl = ext4_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext4_compat_ioctl, #endif diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 25b13ede808..ce937fe432a 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -18,9 +18,9 @@ #include #include -int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, - unsigned long arg) +long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + struct inode *inode = filp->f_dentry->d_inode; struct ext4_inode_info *ei = EXT4_I(inode); unsigned int flags; unsigned short rsv_window_size; @@ -277,9 +277,6 @@ setversion_out: #ifdef CONFIG_COMPAT long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int ret; - /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { case EXT4_IOC32_GETFLAGS: @@ -319,9 +316,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) default: return -ENOIOCTLCMD; } - lock_kernel(); - ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); - unlock_kernel(); - return ret; + return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); } #endif diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 105337ca9ed..33bc88568c5 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -1050,8 +1050,7 @@ extern int ext4_block_truncate_page(handle_t *handle, struct page *page, struct address_space *mapping, loff_t from); /* ioctl.c */ -extern int ext4_ioctl (struct inode *, struct file *, unsigned int, - unsigned long); +extern long ext4_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long); /* migrate.c */ From 4ddfef7b41aebbbede73f361cb938800ba3072dc Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 19/48] ext4: reduce mballoc stack usage with noinline_for_stack mballoc.c is a whole lot of static functions, which gcc seems to really like to inline. With the changes below, on x86, I can at least get from: 432 ext4_mb_new_blocks 240 ext4_mb_free_blocks 208 ext4_mb_discard_group_preallocations 188 ext4_mb_seq_groups_show 164 ext4_mb_init_cache 152 ext4_mb_release_inode_pa 136 ext4_mb_seq_history_show ... to 220 ext4_mb_free_blocks 188 ext4_mb_seq_groups_show 176 ext4_mb_regular_allocator 164 ext4_mb_init_cache 156 ext4_mb_new_blocks 152 ext4_mb_release_inode_pa 136 ext4_mb_seq_history_show 124 ext4_mb_release_group_pa ... which still has some big functions in there, but not 432 bytes! Signed-off-by: Eric Sandeen Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 9d57695de74..66e1451f64e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -1168,8 +1168,9 @@ out: return err; } -static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, - struct ext4_buddy *e4b) +static noinline_for_stack int +ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + struct ext4_buddy *e4b) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct inode *inode = sbi->s_buddy_cache; @@ -1965,7 +1966,8 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, return 0; } -static int ext4_mb_regular_allocator(struct ext4_allocation_context *ac) +static noinline_for_stack int +ext4_mb_regular_allocator(struct ext4_allocation_context *ac) { ext4_group_t group; ext4_group_t i; @@ -2465,7 +2467,8 @@ static void ext4_mb_history_init(struct super_block *sb) /* if we can't allocate history, then we simple won't use it */ } -static void ext4_mb_store_history(struct ext4_allocation_context *ac) +static noinline_for_stack void +ext4_mb_store_history(struct ext4_allocation_context *ac) { struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); struct ext4_mb_history h; @@ -2801,7 +2804,8 @@ int ext4_mb_release(struct super_block *sb) return 0; } -static void ext4_mb_free_committed_blocks(struct super_block *sb) +static noinline_for_stack void +ext4_mb_free_committed_blocks(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); int err; @@ -3021,7 +3025,8 @@ void exit_ext4_mballoc(void) * Check quota and mark choosed space (ac->ac_b_ex) non-free in bitmaps * Returns 0 if success or error code */ -static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, +static noinline_for_stack int +ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, handle_t *handle) { struct buffer_head *bitmap_bh = NULL; @@ -3138,7 +3143,8 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac) * Normalization means making request better in terms of * size and alignment */ -static void ext4_mb_normalize_request(struct ext4_allocation_context *ac, +static noinline_for_stack void +ext4_mb_normalize_request(struct ext4_allocation_context *ac, struct ext4_allocation_request *ar) { int bsbits, max; @@ -3404,7 +3410,8 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, /* * search goal blocks in preallocated space */ -static int ext4_mb_use_preallocated(struct ext4_allocation_context *ac) +static noinline_for_stack int +ext4_mb_use_preallocated(struct ext4_allocation_context *ac) { struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); struct ext4_locality_group *lg; @@ -3571,7 +3578,8 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac, /* * creates new preallocated space for given inode */ -static int ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) +static noinline_for_stack int +ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) { struct super_block *sb = ac->ac_sb; struct ext4_prealloc_space *pa; @@ -3658,7 +3666,8 @@ static int ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) /* * creates new preallocated space for locality group inodes belongs to */ -static int ext4_mb_new_group_pa(struct ext4_allocation_context *ac) +static noinline_for_stack int +ext4_mb_new_group_pa(struct ext4_allocation_context *ac) { struct super_block *sb = ac->ac_sb; struct ext4_locality_group *lg; @@ -3731,8 +3740,8 @@ static int ext4_mb_new_preallocation(struct ext4_allocation_context *ac) * the caller MUST hold group/inode locks. * TODO: optimize the case when there are no in-core structures yet */ -static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b, - struct buffer_head *bitmap_bh, +static noinline_for_stack int +ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, struct ext4_prealloc_space *pa) { struct ext4_allocation_context *ac; @@ -3803,7 +3812,8 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b, return err; } -static int ext4_mb_release_group_pa(struct ext4_buddy *e4b, +static noinline_for_stack int +ext4_mb_release_group_pa(struct ext4_buddy *e4b, struct ext4_prealloc_space *pa) { struct ext4_allocation_context *ac; @@ -3845,7 +3855,8 @@ static int ext4_mb_release_group_pa(struct ext4_buddy *e4b, * - how many do we discard * 1) how many requested */ -static int ext4_mb_discard_group_preallocations(struct super_block *sb, +static noinline_for_stack int +ext4_mb_discard_group_preallocations(struct super_block *sb, ext4_group_t group, int needed) { struct ext4_group_info *grp = ext4_get_group_info(sb, group); @@ -4167,7 +4178,8 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac) mutex_lock(&ac->ac_lg->lg_mutex); } -static int ext4_mb_initialize_context(struct ext4_allocation_context *ac, +static noinline_for_stack int +ext4_mb_initialize_context(struct ext4_allocation_context *ac, struct ext4_allocation_request *ar) { struct super_block *sb = ar->inode->i_sb; @@ -4398,7 +4410,8 @@ static void ext4_mb_poll_new_transaction(struct super_block *sb, ext4_mb_free_committed_blocks(sb); } -static int ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, +static noinline_for_stack int +ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, ext4_group_t group, ext4_grpblk_t block, int count) { struct ext4_group_info *db = e4b->bd_info; From 9a0762c5af40e4aa64fef999967459c98e6ae4c9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 20/48] ext4: Convert list_for_each_rcu() to list_for_each_entry_rcu() The list_for_each_entry_rcu() primitive should be used instead of list_for_each_rcu(), as the former is easier to use and provides better type safety. http://groups.google.com/group/linux.kernel/browse_thread/thread/45749c83451cebeb/0633a65759ce7713?lnk=raot Signed-off-by: Aneesh Kumar K.V Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 66e1451f64e..aaaccf5986f 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3149,10 +3149,10 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, { int bsbits, max; ext4_lblk_t end; - struct list_head *cur; loff_t size, orig_size, start_off; ext4_lblk_t start, orig_start; struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); + struct ext4_prealloc_space *pa; /* do normalize only data requests, metadata requests do not need preallocation */ @@ -3238,12 +3238,9 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, /* check we don't cross already preallocated blocks */ rcu_read_lock(); - list_for_each_rcu(cur, &ei->i_prealloc_list) { - struct ext4_prealloc_space *pa; + list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { unsigned long pa_end; - pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list); - if (pa->pa_deleted) continue; spin_lock(&pa->pa_lock); @@ -3285,10 +3282,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac, /* XXX: extra loop to check we really don't overlap preallocations */ rcu_read_lock(); - list_for_each_rcu(cur, &ei->i_prealloc_list) { - struct ext4_prealloc_space *pa; + list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { unsigned long pa_end; - pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list); spin_lock(&pa->pa_lock); if (pa->pa_deleted == 0) { pa_end = pa->pa_lstart + pa->pa_len; @@ -3416,7 +3411,6 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); struct ext4_locality_group *lg; struct ext4_prealloc_space *pa; - struct list_head *cur; /* only data can be preallocated */ if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) @@ -3424,8 +3418,7 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) /* first, try per-file preallocation */ rcu_read_lock(); - list_for_each_rcu(cur, &ei->i_prealloc_list) { - pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list); + list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { /* all fields in this condition don't change, * so we can skip locking for them */ @@ -3457,8 +3450,7 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) return 0; rcu_read_lock(); - list_for_each_rcu(cur, &lg->lg_prealloc_list) { - pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list); + list_for_each_entry_rcu(pa, &lg->lg_prealloc_list, pa_inode_list) { spin_lock(&pa->pa_lock); if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) { atomic_inc(&pa->pa_count); From e8546d0615542684ca02ba03edebec1a503beb6b Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 21/48] ext4: le*_add_cpu conversion replace all: little_endian_variable = cpu_to_leX(leX_to_cpu(little_endian_variable) + expression_in_cpu_byteorder); with: leX_add_cpu(&little_endian_variable, expression_in_cpu_byteorder); generated with semantic patch Signed-off-by: Marcin Slusarz Signed-off-by: "Theodore Ts'o" Cc: linux-ext4@vger.kernel.org Cc: sct@redhat.com Cc: Andrew Morton Cc: adilger@clusterfs.com Cc: Mingming Cao --- fs/ext4/balloc.c | 7 ++----- fs/ext4/extents.c | 20 +++++++++----------- fs/ext4/ialloc.c | 12 ++++-------- fs/ext4/mballoc.c | 7 ++----- fs/ext4/resize.c | 6 ++---- fs/ext4/super.c | 2 +- fs/ext4/xattr.c | 6 ++---- 7 files changed, 22 insertions(+), 38 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 0737e05ba3d..5d348998ff3 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -752,9 +752,7 @@ do_more: jbd_unlock_bh_state(bitmap_bh); spin_lock(sb_bgl_lock(sbi, block_group)); - desc->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + - group_freed); + le16_add_cpu(&desc->bg_free_blocks_count, group_freed); desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_add(&sbi->s_freeblocks_counter, count); @@ -1823,8 +1821,7 @@ allocated: spin_lock(sb_bgl_lock(sbi, group_no)); if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - gdp->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); + le16_add_cpu(&gdp->bg_free_blocks_count, -num); gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); spin_unlock(sb_bgl_lock(sbi, group_no)); percpu_counter_sub(&sbi->s_freeblocks_counter, num); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index c7c42c9c7bf..3d5a35f373d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -614,7 +614,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, ix->ei_block = cpu_to_le32(logical); ext4_idx_store_pblock(ix, ptr); - curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1); + le16_add_cpu(&curp->p_hdr->eh_entries, 1); BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries) > le16_to_cpu(curp->p_hdr->eh_max)); @@ -736,7 +736,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, } if (m) { memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m); - neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m); + le16_add_cpu(&neh->eh_entries, m); } set_buffer_uptodate(bh); @@ -753,8 +753,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, err = ext4_ext_get_access(handle, inode, path + depth); if (err) goto cleanup; - path[depth].p_hdr->eh_entries = - cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m); + le16_add_cpu(&path[depth].p_hdr->eh_entries, -m); err = ext4_ext_dirty(handle, inode, path + depth); if (err) goto cleanup; @@ -817,8 +816,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, if (m) { memmove(++fidx, path[i].p_idx - m, sizeof(struct ext4_extent_idx) * m); - neh->eh_entries = - cpu_to_le16(le16_to_cpu(neh->eh_entries) + m); + le16_add_cpu(&neh->eh_entries, m); } set_buffer_uptodate(bh); unlock_buffer(bh); @@ -834,7 +832,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, err = ext4_ext_get_access(handle, inode, path + i); if (err) goto cleanup; - path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m); + le16_add_cpu(&path[i].p_hdr->eh_entries, -m); err = ext4_ext_dirty(handle, inode, path + i); if (err) goto cleanup; @@ -1369,7 +1367,7 @@ int ext4_ext_try_to_merge(struct inode *inode, * sizeof(struct ext4_extent); memmove(ex + 1, ex + 2, len); } - eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1); + le16_add_cpu(&eh->eh_entries, -1); merge_done = 1; WARN_ON(eh->eh_entries == 0); if (!eh->eh_entries) @@ -1560,7 +1558,7 @@ has_space: path[depth].p_ext = nearex; } - eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1); + le16_add_cpu(&eh->eh_entries, 1); nearex = path[depth].p_ext; nearex->ee_block = newext->ee_block; ext4_ext_store_pblock(nearex, ext_pblock(newext)); @@ -1699,7 +1697,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, err = ext4_ext_get_access(handle, inode, path); if (err) return err; - path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1); + le16_add_cpu(&path->p_hdr->eh_entries, -1); err = ext4_ext_dirty(handle, inode, path); if (err) return err; @@ -1902,7 +1900,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (num == 0) { /* this extent is removed; mark slot entirely unused */ ext4_ext_store_pblock(ex, 0); - eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); + le16_add_cpu(&eh->eh_entries, -1); } ex->ee_block = cpu_to_le32(block); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index cb14646117f..e8d24f24f28 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -223,11 +223,9 @@ void ext4_free_inode (handle_t *handle, struct inode * inode) if (gdp) { spin_lock(sb_bgl_lock(sbi, block_group)); - gdp->bg_free_inodes_count = cpu_to_le16( - le16_to_cpu(gdp->bg_free_inodes_count) + 1); + le16_add_cpu(&gdp->bg_free_inodes_count, 1); if (is_directory) - gdp->bg_used_dirs_count = cpu_to_le16( - le16_to_cpu(gdp->bg_used_dirs_count) - 1); + le16_add_cpu(&gdp->bg_used_dirs_count, -1); gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); spin_unlock(sb_bgl_lock(sbi, block_group)); @@ -664,11 +662,9 @@ got: cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino); } - gdp->bg_free_inodes_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); + le16_add_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); + le16_add_cpu(&gdp->bg_used_dirs_count, 1); } gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); spin_unlock(sb_bgl_lock(sbi, group)); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index aaaccf5986f..4865d318d7e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3099,9 +3099,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ac->ac_b_ex.fe_group, gdp)); } - gdp->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - - ac->ac_b_ex.fe_len); + le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len); gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len); @@ -4593,8 +4591,7 @@ do_more: } spin_lock(sb_bgl_lock(sbi, block_group)); - gdp->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count); + le16_add_cpu(&gdp->bg_free_blocks_count, count); gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); spin_unlock(sb_bgl_lock(sbi, block_group)); percpu_counter_add(&sbi->s_freeblocks_counter, count); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index e29efa0f9d6..728e3efa84b 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -502,8 +502,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, EXT4_SB(sb)->s_gdb_count++; kfree(o_group_desc); - es->s_reserved_gdt_blocks = - cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1); + le16_add_cpu(&es->s_reserved_gdt_blocks, -1); ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); return 0; @@ -877,8 +876,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) */ ext4_blocks_count_set(es, ext4_blocks_count(es) + input->blocks_count); - es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + - EXT4_INODES_PER_GROUP(sb)); + le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb)); /* * We need to protect s_groups_count against other CPUs seeing diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9d2d9a7fdea..9c0a3448ec6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1392,7 +1392,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, #endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); - es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + le16_add_cpu(&es->s_mnt_count, 1); es->s_mtime = cpu_to_le32(get_seconds()); ext4_update_dynamic_rev(sb); EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e9054c1c7d9..726716b618d 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -484,8 +484,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, get_bh(bh); ext4_forget(handle, 1, inode, bh, bh->b_blocknr); } else { - BHDR(bh)->h_refcount = cpu_to_le32( - le32_to_cpu(BHDR(bh)->h_refcount) - 1); + le32_add_cpu(&BHDR(bh)->h_refcount, -1); error = ext4_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; @@ -789,8 +788,7 @@ inserted: if (error) goto cleanup_dquot; lock_buffer(new_bh); - BHDR(new_bh)->h_refcount = cpu_to_le32(1 + - le32_to_cpu(BHDR(new_bh)->h_refcount)); + le32_add_cpu(&BHDR(new_bh)->h_refcount, 1); ea_bdebug(new_bh, "reusing; refcount now=%d", le32_to_cpu(BHDR(new_bh)->h_refcount)); unlock_buffer(new_bh); From 216c34b2b8a3687afed4d269acec140c8baf23fe Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 22/48] ext4: convert byte order of constant instead of variable Convert byte order of constant instead of variable which can be done at compile time (vs run time). Signed-off-by: Marcin Slusarz Cc: Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9c0a3448ec6..01d163964e6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1388,7 +1388,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, * a plain journaled filesystem we can keep it set as * valid forever! :) */ - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS); + es->s_state &= cpu_to_le16(~EXT4_VALID_FS); #endif if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); From d00a6d7b40b44ee6b03f492a6c58f5bc4649c784 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 23/48] ext4: use ext4_group_first_block_no() Use ext4_group_first_block_no() and assign the return values to ext4_fsblk_t variables. Signed-off-by: Akinobu Mita Signed-off-by: "Theodore Ts'o" Cc: Stephen Tweedie Cc: adilger@clusterfs.com Cc: Andrew Morton Cc: Mingming Cao --- fs/ext4/balloc.c | 6 +++--- fs/ext4/xattr.c | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 5d348998ff3..a080d7f5fac 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -48,7 +48,6 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, ext4_group_t block_group, struct ext4_group_desc *gdp) { - unsigned long start; int bit, bit_max; unsigned free_blocks, group_blocks; struct ext4_sb_info *sbi = EXT4_SB(sb); @@ -106,11 +105,12 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, free_blocks = group_blocks - bit_max; if (bh) { + ext4_fsblk_t start; + for (bit = 0; bit < bit_max; bit++) ext4_set_bit(bit, bh->b_data); - start = block_group * EXT4_BLOCKS_PER_GROUP(sb) + - le32_to_cpu(sbi->s_es->s_first_data_block); + start = ext4_group_first_block_no(sb, block_group); /* Set bits for block and inode bitmaps, and inode table */ ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 726716b618d..bc1d7daac8e 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -806,10 +806,8 @@ inserted: get_bh(new_bh); } else { /* We need to allocate a new block */ - ext4_fsblk_t goal = le32_to_cpu( - EXT4_SB(sb)->s_es->s_first_data_block) + - (ext4_fsblk_t)EXT4_I(inode)->i_block_group * - EXT4_BLOCKS_PER_GROUP(sb); + ext4_fsblk_t goal = ext4_group_first_block_no(sb, + EXT4_I(inode)->i_block_group); ext4_fsblk_t block = ext4_new_block(handle, inode, goal, &error); if (error) From c0a4ef38ac90d9053fcf3e22f81520a507c1a7bd Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 24/48] ext4: use ext4_get_group_desc() Use ext4_get_group_desc() in ext4_get_inode_block() instead of open coding the functionality. Signed-off-by: Akinobu Mita Signed-off-by: "Theodore Ts'o" Cc: Stephen Tweedie Cc: adilger@clusterfs.com Cc: Andrew Morton Cc: Mingming Cao --- fs/ext4/inode.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 24a2604dde7..aa0fb985b15 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2511,12 +2511,10 @@ out_stop: static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, unsigned long ino, struct ext4_iloc *iloc) { - unsigned long desc, group_desc; ext4_group_t block_group; unsigned long offset; ext4_fsblk_t block; - struct buffer_head *bh; - struct ext4_group_desc * gdp; + struct ext4_group_desc *gdp; if (!ext4_valid_inum(sb, ino)) { /* @@ -2528,22 +2526,10 @@ static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, } block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); - if (block_group >= EXT4_SB(sb)->s_groups_count) { - ext4_error(sb,"ext4_get_inode_block","group >= groups count"); + gdp = ext4_get_group_desc(sb, block_group, NULL); + if (!gdp) return 0; - } - smp_rmb(); - group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); - desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); - bh = EXT4_SB(sb)->s_group_desc[group_desc]; - if (!bh) { - ext4_error (sb, "ext4_get_inode_block", - "Descriptor not loaded"); - return 0; - } - gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data + - desc * EXT4_DESC_SIZE(sb)); /* * Figure out the offset within the block group inode table */ From a871611b474bfcdee422c0cf5d16f509dce096f5 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 25/48] ext4: check ext4_journal_get_write_access() errors Check ext4_journal_get_write_access() errors. Signed-off-by: Akinobu Mita Signed-off-by: "Theodore Ts'o" Cc: Stephen Tweedie Cc: adilger@clusterfs.com Cc: Andrew Morton Cc: Mingming Cao --- fs/ext4/namei.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 68611945687..63c33e05347 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -57,10 +57,15 @@ static struct buffer_head *ext4_append(handle_t *handle, *block = inode->i_size >> inode->i_sb->s_blocksize_bits; - if ((bh = ext4_bread(handle, inode, *block, 1, err))) { + bh = ext4_bread(handle, inode, *block, 1, err); + if (bh) { inode->i_size += inode->i_sb->s_blocksize; EXT4_I(inode)->i_disksize = inode->i_size; - ext4_journal_get_write_access(handle,bh); + *err = ext4_journal_get_write_access(handle, bh); + if (*err) { + brelse(bh); + bh = NULL; + } } return bh; } From 14499f3592f3f52ceb7a639466de9ca21e2c1914 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 26/48] ext4: remove extra define of ext4_new_blocks_old from mballoc.c The function prototype of ext4_new_blocks_old() is defined in ext4_fs.h, so we don't need the extra function prototype in mballoc.c Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 4865d318d7e..d9136b539c1 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -576,8 +576,6 @@ static void ext4_mb_store_history(struct ext4_allocation_context *ac); static struct proc_dir_entry *proc_root_ext4; struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t); -ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode, - ext4_fsblk_t goal, unsigned long *count, int *errp); static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, ext4_group_t group); From d3a95d477d4fcb2c276b8357087a6c862c9e1949 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 27/48] ext4: make ext4_xattr_list() static This patch makes the needlessly global ext4_xattr_list() static. Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/xattr.c | 4 +++- fs/ext4/xattr.h | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index bc1d7daac8e..739930427b8 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -92,6 +92,8 @@ static struct buffer_head *ext4_xattr_cache_find(struct inode *, struct mb_cache_entry **); static void ext4_xattr_rehash(struct ext4_xattr_header *, struct ext4_xattr_entry *); +static int ext4_xattr_list(struct inode *inode, char *buffer, + size_t buffer_size); static struct mb_cache *ext4_xattr_cache; @@ -420,7 +422,7 @@ cleanup: * Returns a negative error number on failure, or the number of bytes * used / required on success. */ -int +static int ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { int i_error, b_error; diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index d7f5d6a1265..5992fe979bb 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -74,7 +74,6 @@ extern struct xattr_handler ext4_xattr_security_handler; extern ssize_t ext4_listxattr(struct dentry *, char *, size_t); extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); -extern int ext4_xattr_list(struct inode *, char *, size_t); extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); @@ -98,12 +97,6 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name, return -EOPNOTSUPP; } -static inline int -ext4_xattr_list(struct inode *inode, void *buffer, size_t size) -{ - return -EOPNOTSUPP; -} - static inline int ext4_xattr_set(struct inode *inode, int name_index, const char *name, const void *value, size_t size, int flags) From 418f6e9e5b77443a66f4457bc60f391e4fba8ad8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 29 Apr 2008 08:11:12 -0400 Subject: [PATCH 28/48] ext4: remove duplicate include of ext4_fs_i.h header file include/linux/ext4_fs_i.h is included in include/linux/ext_fs.h twice Signed-off-by: Joe Perches Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- include/linux/ext4_fs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index 33bc88568c5..1ae0f965f38 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -19,7 +19,6 @@ #include #include #include - #include /* @@ -176,7 +175,6 @@ struct ext4_group_desc #define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ #ifdef __KERNEL__ -#include #include #endif /* From 9fa27c85de57d38ca698f4e34fdd1ab06b6c8e49 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Mon, 28 Apr 2008 09:40:00 -0400 Subject: [PATCH 29/48] jbd2: tidy up revoke cache initialisation and destruction Make revocation cache destruction safe to call if initialisation fails partially or entirely. This allows it to be used to cleanup in the case of initialisation failure, simplifying the code slightly. Signed-off-by: Duane Griffin Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" Signed-off-by: Aneesh Kumar K.V --- fs/jbd2/revoke.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 2e1453a5e99..72b260896bb 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -167,33 +167,41 @@ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, return NULL; } +void jbd2_journal_destroy_revoke_caches(void) +{ + if (jbd2_revoke_record_cache) { + kmem_cache_destroy(jbd2_revoke_record_cache); + jbd2_revoke_record_cache = NULL; + } + if (jbd2_revoke_table_cache) { + kmem_cache_destroy(jbd2_revoke_table_cache); + jbd2_revoke_table_cache = NULL; + } +} + int __init jbd2_journal_init_revoke_caches(void) { + J_ASSERT(!jbd2_revoke_record_cache); + J_ASSERT(!jbd2_revoke_table_cache); + jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record", sizeof(struct jbd2_revoke_record_s), 0, SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, NULL); if (!jbd2_revoke_record_cache) - return -ENOMEM; + goto record_cache_failure; jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table", sizeof(struct jbd2_revoke_table_s), 0, SLAB_TEMPORARY, NULL); - if (!jbd2_revoke_table_cache) { - kmem_cache_destroy(jbd2_revoke_record_cache); - jbd2_revoke_record_cache = NULL; - return -ENOMEM; - } + if (!jbd2_revoke_table_cache) + goto table_cache_failure; return 0; -} - -void jbd2_journal_destroy_revoke_caches(void) -{ - kmem_cache_destroy(jbd2_revoke_record_cache); - jbd2_revoke_record_cache = NULL; - kmem_cache_destroy(jbd2_revoke_table_cache); - jbd2_revoke_table_cache = NULL; +table_cache_failure: + jbd2_journal_destroy_revoke_caches(); +record_cache_failure: + return -ENOMEM; } /* Initialise the revoke table for a given journal to a given size. */ From 83c49523c91fff10493f5b3c102063b02ab76907 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 30/48] jbd2: eliminate duplicated code in revocation table init/destroy functions The revocation table initialisation/destruction code is repeated for each of the two revocation tables stored in the journal. Refactoring the duplicated code into functions is tidier, simplifies the logic in initialisation in particular, and slightly reduces the code size. There should not be any functional change. Signed-off-by: Duane Griffin Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/jbd2/revoke.c | 135 +++++++++++++++++++---------------------------- 1 file changed, 55 insertions(+), 80 deletions(-) diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 72b260896bb..144a2065f03 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -204,109 +204,84 @@ record_cache_failure: return -ENOMEM; } -/* Initialise the revoke table for a given journal to a given size. */ - -int jbd2_journal_init_revoke(journal_t *journal, int hash_size) +static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size) { - int shift, tmp; + int shift = 0; + int tmp = hash_size; + struct jbd2_revoke_table_s *table; - J_ASSERT (journal->j_revoke_table[0] == NULL); + table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); + if (!table) + goto out; - shift = 0; - tmp = hash_size; while((tmp >>= 1UL) != 0UL) shift++; - journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); - if (!journal->j_revoke_table[0]) - return -ENOMEM; - journal->j_revoke = journal->j_revoke_table[0]; - - /* Check that the hash_size is a power of two */ - J_ASSERT(is_power_of_2(hash_size)); - - journal->j_revoke->hash_size = hash_size; - - journal->j_revoke->hash_shift = shift; - - journal->j_revoke->hash_table = + table->hash_size = hash_size; + table->hash_shift = shift; + table->hash_table = kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); - if (!journal->j_revoke->hash_table) { - kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); - journal->j_revoke = NULL; - return -ENOMEM; + if (!table->hash_table) { + kmem_cache_free(jbd2_revoke_table_cache, table); + table = NULL; + goto out; } for (tmp = 0; tmp < hash_size; tmp++) - INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + INIT_LIST_HEAD(&table->hash_table[tmp]); - journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); - if (!journal->j_revoke_table[1]) { - kfree(journal->j_revoke_table[0]->hash_table); - kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); - return -ENOMEM; +out: + return table; +} + +static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table) +{ + int i; + struct list_head *hash_list; + + for (i = 0; i < table->hash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT(list_empty(hash_list)); } + kfree(table->hash_table); + kmem_cache_free(jbd2_revoke_table_cache, table); +} + +/* Initialise the revoke table for a given journal to a given size. */ +int jbd2_journal_init_revoke(journal_t *journal, int hash_size) +{ + J_ASSERT(journal->j_revoke_table[0] == NULL); + J_ASSERT(is_power_of_2(hash_size)); + + journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size); + if (!journal->j_revoke_table[0]) + goto fail0; + + journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size); + if (!journal->j_revoke_table[1]) + goto fail1; + journal->j_revoke = journal->j_revoke_table[1]; - /* Check that the hash_size is a power of two */ - J_ASSERT(is_power_of_2(hash_size)); - - journal->j_revoke->hash_size = hash_size; - - journal->j_revoke->hash_shift = shift; - - journal->j_revoke->hash_table = - kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); - if (!journal->j_revoke->hash_table) { - kfree(journal->j_revoke_table[0]->hash_table); - kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]); - kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]); - journal->j_revoke = NULL; - return -ENOMEM; - } - - for (tmp = 0; tmp < hash_size; tmp++) - INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); - spin_lock_init(&journal->j_revoke_lock); return 0; + +fail1: + jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]); +fail0: + return -ENOMEM; } -/* Destoy a journal's revoke table. The table must already be empty! */ - +/* Destroy a journal's revoke table. The table must already be empty! */ void jbd2_journal_destroy_revoke(journal_t *journal) { - struct jbd2_revoke_table_s *table; - struct list_head *hash_list; - int i; - - table = journal->j_revoke_table[0]; - if (!table) - return; - - for (i=0; ihash_size; i++) { - hash_list = &table->hash_table[i]; - J_ASSERT (list_empty(hash_list)); - } - - kfree(table->hash_table); - kmem_cache_free(jbd2_revoke_table_cache, table); - journal->j_revoke = NULL; - - table = journal->j_revoke_table[1]; - if (!table) - return; - - for (i=0; ihash_size; i++) { - hash_list = &table->hash_table[i]; - J_ASSERT (list_empty(hash_list)); - } - - kfree(table->hash_table); - kmem_cache_free(jbd2_revoke_table_cache, table); journal->j_revoke = NULL; + if (journal->j_revoke_table[0]) + jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]); + if (journal->j_revoke_table[1]) + jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]); } From 8a9362eb405e380432e6883cb83830df3b6cdf78 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 31/48] jbd2: replace potentially false assertion with if block If an error occurs during jbd2 cache initialisation it is possible for the journal_head_cache to be NULL when jbd2_journal_destroy_journal_head_cache is called. Replace the J_ASSERT with an if block to handle the situation correctly. Note that even with this fix things will break badly if jbd2 is statically compiled in and cache initialisation fails. Signed-off-by: Duane Griffin Cc: Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index eb7eb6c27bc..2dbf23e82c6 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1976,9 +1976,10 @@ static int journal_init_jbd2_journal_head_cache(void) static void jbd2_journal_destroy_jbd2_journal_head_cache(void) { - J_ASSERT(jbd2_journal_head_cache != NULL); - kmem_cache_destroy(jbd2_journal_head_cache); - jbd2_journal_head_cache = NULL; + if (jbd2_journal_head_cache) { + kmem_cache_destroy(jbd2_journal_head_cache); + jbd2_journal_head_cache = NULL; + } } /* From 5648ba5b2dc0d07a8108fabc7b9100962e9e1d88 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 32/48] jbd2: fix kernel-doc notation Fix kernel-doc notation in jbd2. Signed-off-by: Randy Dunlap Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 5 +++-- fs/jbd2/transaction.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 2dbf23e82c6..d707a219e21 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -997,13 +997,14 @@ fail: */ /** - * journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure + * journal_t * jbd2_journal_init_dev() - creates and initialises a journal structure * @bdev: Block device on which to create the journal * @fs_dev: Device which hold journalled filesystem for this journal. * @start: Block nr Start of journal. * @len: Length of the journal in blocks. * @blocksize: blocksize of journalling device - * @returns: a newly created journal_t * + * + * Returns: a newly created journal_t * * * jbd2_journal_init_dev creates a journal which maps a fixed contiguous * range of blocks on an arbitrary block device. diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 70245d6638b..401bf9d2365 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1462,7 +1462,8 @@ int jbd2_journal_stop(handle_t *handle) return err; } -/**int jbd2_journal_force_commit() - force any uncommitted transactions +/** + * int jbd2_journal_force_commit() - force any uncommitted transactions * @journal: journal to force * * For synchronous operations: force any uncommitted transactions From 620de4e19890c623eb4ba293ec19b42e2e391b89 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Tue, 29 Apr 2008 22:02:47 -0400 Subject: [PATCH 33/48] jbd2: only create debugfs and stats entries if init is successful jbd2 debugfs and stats entries should only be created if cache initialisation is successful. At the moment they are being created unconditionally which will leave them dangling if cache (and hence module) initialisation fails. Signed-off-by: Duane Griffin Cc: Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index d707a219e21..64356e85a10 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -2307,10 +2307,12 @@ static int __init journal_init(void) BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024); ret = journal_init_caches(); - if (ret != 0) + if (ret == 0) { + jbd2_create_debugfs_entry(); + jbd2_create_jbd_stats_proc_entry(); + } else { jbd2_journal_destroy_caches(); - jbd2_create_debugfs_entry(); - jbd2_create_jbd_stats_proc_entry(); + } return ret; } From 46e665e9d297525d286989640cf4247cbe941df6 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 34/48] ext4: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Cc: Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/ext4/balloc.c | 14 ++++----- fs/ext4/ext4_jbd2.c | 12 ++++---- fs/ext4/extents.c | 2 +- fs/ext4/ialloc.c | 10 +++---- fs/ext4/inode.c | 8 +++--- fs/ext4/mballoc.c | 20 ++++++------- fs/ext4/namei.c | 26 ++++++++--------- fs/ext4/resize.c | 70 ++++++++++++++++++++++----------------------- fs/ext4/super.c | 16 +++++------ fs/ext4/xattr.c | 16 +++++------ 10 files changed, 97 insertions(+), 97 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index a080d7f5fac..af5032b23c2 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -58,7 +58,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, /* If checksum is bad mark all blocks used to prevent allocation * essentially implementing a per-group read-only flag. */ if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Checksum bad for group %lu\n", block_group); gdp->bg_free_blocks_count = 0; gdp->bg_free_inodes_count = 0; @@ -235,7 +235,7 @@ static int ext4_valid_block_bitmap(struct super_block *sb, return 1; err_out: - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Invalid block bitmap - " "block_group = %d, block = %llu", block_group, bitmap_blk); @@ -264,7 +264,7 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group) bitmap_blk = ext4_block_bitmap(sb, desc); bh = sb_getblk(sb, bitmap_blk); if (unlikely(!bh)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %llu", (int)block_group, (unsigned long long)bitmap_blk); @@ -281,7 +281,7 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group) } if (bh_submit_read(bh) < 0) { put_bh(bh); - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %llu", (int)block_group, (unsigned long long)bitmap_blk); @@ -360,7 +360,7 @@ restart: BUG(); } #define rsv_window_dump(root, verbose) \ - __rsv_window_dump((root), (verbose), __FUNCTION__) + __rsv_window_dump((root), (verbose), __func__) #else #define rsv_window_dump(root, verbose) do {} while (0) #endif @@ -740,7 +740,7 @@ do_more: if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, bitmap_bh->b_data)) { jbd_unlock_bh_state(bitmap_bh); - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "bit already cleared for block %llu", (ext4_fsblk_t)(block + i)); jbd_lock_bh_state(bitmap_bh); @@ -1796,7 +1796,7 @@ allocated: if (ext4_test_bit(grp_alloc_blk+i, bh2jh(bitmap_bh)->b_committed_data)) { printk("%s: block was unexpectedly set in " - "b_committed_data\n", __FUNCTION__); + "b_committed_data\n", __func__); } } } diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index d6afe4e2734..2e6007d418d 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -9,7 +9,7 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle, { int err = jbd2_journal_get_undo_access(handle, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } @@ -18,7 +18,7 @@ int __ext4_journal_get_write_access(const char *where, handle_t *handle, { int err = jbd2_journal_get_write_access(handle, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } @@ -27,7 +27,7 @@ int __ext4_journal_forget(const char *where, handle_t *handle, { int err = jbd2_journal_forget(handle, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } @@ -36,7 +36,7 @@ int __ext4_journal_revoke(const char *where, handle_t *handle, { int err = jbd2_journal_revoke(handle, blocknr, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } @@ -45,7 +45,7 @@ int __ext4_journal_get_create_access(const char *where, { int err = jbd2_journal_get_create_access(handle, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } @@ -54,6 +54,6 @@ int __ext4_journal_dirty_metadata(const char *where, { int err = jbd2_journal_dirty_metadata(handle, bh); if (err) - ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + ext4_journal_abort_handle(where, __func__, bh, handle, err); return err; } diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 3d5a35f373d..1c8aab4dad2 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -308,7 +308,7 @@ corrupted: } #define ext4_ext_check_header(inode, eh, depth) \ - __ext4_ext_check_header(__FUNCTION__, inode, eh, depth) + __ext4_ext_check_header(__func__, inode, eh, depth) #ifdef EXT_DEBUG static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e8d24f24f28..a86377401ff 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -75,7 +75,7 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh, /* If checksum is bad mark all blocks and inodes use to prevent * allocation, essentially implementing a per-group read-only flag. */ if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { - ext4_error(sb, __FUNCTION__, "Checksum bad for group %lu\n", + ext4_error(sb, __func__, "Checksum bad for group %lu\n", block_group); gdp->bg_free_blocks_count = 0; gdp->bg_free_inodes_count = 0; @@ -586,7 +586,7 @@ got: ino++; if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || ino > EXT4_INODES_PER_GROUP(sb)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "reserved inode or inode > inodes count - " "block_group = %lu, inode=%lu", group, ino + group * EXT4_INODES_PER_GROUP(sb)); @@ -792,7 +792,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) /* Error cases - e2fsck has already cleaned up for us */ if (ino > max_ino) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "bad orphan ino %lu! e2fsck was run?", ino); goto error; } @@ -801,7 +801,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); bitmap_bh = read_inode_bitmap(sb, block_group); if (!bitmap_bh) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "inode bitmap error for orphan %lu", ino); goto error; } @@ -826,7 +826,7 @@ iget_failed: err = PTR_ERR(inode); inode = NULL; bad_orphan: - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "bad orphan inode %lu! e2fsck was run?", ino); printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n", bit, (unsigned long long)bitmap_bh->b_blocknr, diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index aa0fb985b15..bd1a391725c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -93,7 +93,7 @@ int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, BUFFER_TRACE(bh, "call ext4_journal_revoke"); err = ext4_journal_revoke(handle, blocknr, bh); if (err) - ext4_abort(inode->i_sb, __FUNCTION__, + ext4_abort(inode->i_sb, __func__, "error %d when attempting revoke", err); BUFFER_TRACE(bh, "exit"); return err; @@ -1240,7 +1240,7 @@ int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { int err = jbd2_journal_dirty_data(handle, bh); if (err) - ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__, + ext4_journal_abort_handle(__func__, __func__, bh, handle, err); return err; } @@ -3371,7 +3371,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND; if (mnt_count != le16_to_cpu(sbi->s_es->s_mnt_count)) { - ext4_warning(inode->i_sb, __FUNCTION__, + ext4_warning(inode->i_sb, __func__, "Unable to expand inode %lu. Delete" " some EAs or run e2fsck.", inode->i_ino); @@ -3412,7 +3412,7 @@ void ext4_dirty_inode(struct inode *inode) current_handle->h_transaction != handle->h_transaction) { /* This task has a transaction open against a different fs */ printk(KERN_EMERG "%s: transactions do not match!\n", - __FUNCTION__); + __func__); } else { jbd_debug(5, "marking dirty. outer handle=%p\n", current_handle); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index d9136b539c1..0b46fc0ca19 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -734,7 +734,7 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b, blocknr += le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); - ext4_error(sb, __FUNCTION__, "double-free of inode" + ext4_error(sb, __func__, "double-free of inode" " %lu's block %llu(bit %u in group %lu)\n", inode ? inode->i_ino : 0, blocknr, first + i, e4b->bd_group); @@ -906,7 +906,7 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, } #undef MB_CHECK_ASSERT #define mb_check_buddy(e4b) __mb_check_buddy(e4b, \ - __FILE__, __FUNCTION__, __LINE__) + __FILE__, __func__, __LINE__) #else #define mb_check_buddy(e4b) #endif @@ -980,7 +980,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb, grp->bb_fragments = fragments; if (free != grp->bb_free) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "EXT4-fs: group %lu: %u blocks in bitmap, %u in gd\n", group, free, grp->bb_free); /* @@ -1366,7 +1366,7 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, blocknr += le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); - ext4_error(sb, __FUNCTION__, "double-free of inode" + ext4_error(sb, __func__, "double-free of inode" " %lu's block %llu(bit %u in group %lu)\n", inode ? inode->i_ino : 0, blocknr, block, e4b->bd_group); @@ -1847,7 +1847,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, * free blocks even though group info says we * we have free blocks */ - ext4_error(sb, __FUNCTION__, "%d free blocks as per " + ext4_error(sb, __func__, "%d free blocks as per " "group info. But bitmap says 0\n", free); break; @@ -1856,7 +1856,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex); BUG_ON(ex.fe_len <= 0); if (free < ex.fe_len) { - ext4_error(sb, __FUNCTION__, "%d free blocks as per " + ext4_error(sb, __func__, "%d free blocks as per " "group info. But got %d blocks\n", free, ex.fe_len); /* @@ -3073,7 +3073,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, in_range(block, ext4_inode_table(sb, gdp), EXT4_SB(sb)->s_itb_per_group)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Allocating block in system zone - block = %llu", block); } @@ -3786,7 +3786,7 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, pa, (unsigned long) pa->pa_lstart, (unsigned long) pa->pa_pstart, (unsigned long) pa->pa_len); - ext4_error(sb, __FUNCTION__, "free %u, pa_free %u\n", + ext4_error(sb, __func__, "free %u, pa_free %u\n", free, pa->pa_free); /* * pa is already deleted so we use the value obtained @@ -4490,7 +4490,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || block + count > ext4_blocks_count(es)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); goto error_return; @@ -4531,7 +4531,7 @@ do_more: in_range(block + count - 1, ext4_inode_table(sb, gdp), EXT4_SB(sb)->s_itb_per_group)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Freeing blocks in system zone - " "Block = %lu, count = %lu", block, count); } diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 63c33e05347..02cdaec39e2 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -353,7 +353,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, if (root->info.hash_version != DX_HASH_TEA && root->info.hash_version != DX_HASH_HALF_MD4 && root->info.hash_version != DX_HASH_LEGACY) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "Unrecognised inode hash code %d", root->info.hash_version); brelse(bh); @@ -367,7 +367,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, hash = hinfo->hash; if (root->info.unused_flags & 1) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "Unimplemented inode hash flags: %#06x", root->info.unused_flags); brelse(bh); @@ -376,7 +376,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, } if ((indirect = root->info.indirect_levels) > 1) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "Unimplemented inode hash depth: %#06x", root->info.indirect_levels); brelse(bh); @@ -389,7 +389,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, if (dx_get_limit(entries) != dx_root_limit(dir, root->info.info_length)) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "dx entry: limit != root limit"); brelse(bh); *err = ERR_BAD_DX_DIR; @@ -401,7 +401,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, { count = dx_get_count(entries); if (!count || count > dx_get_limit(entries)) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "dx entry: no count or count > limit"); brelse(bh); *err = ERR_BAD_DX_DIR; @@ -446,7 +446,7 @@ dx_probe(struct dentry *dentry, struct inode *dir, goto fail2; at = entries = ((struct dx_node *) bh->b_data)->entries; if (dx_get_limit(entries) != dx_node_limit (dir)) { - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "dx entry: limit != node limit"); brelse(bh); *err = ERR_BAD_DX_DIR; @@ -462,7 +462,7 @@ fail2: } fail: if (*err == ERR_BAD_DX_DIR) - ext4_warning(dir->i_sb, __FUNCTION__, + ext4_warning(dir->i_sb, __func__, "Corrupt dir inode %ld, running e2fsck is " "recommended.", dir->i_ino); return NULL; @@ -919,7 +919,7 @@ restart: wait_on_buffer(bh); if (!buffer_uptodate(bh)) { /* read error, skip block & hope for the best */ - ext4_error(sb, __FUNCTION__, "reading directory #%lu " + ext4_error(sb, __func__, "reading directory #%lu " "offset %lu", dir->i_ino, (unsigned long)block); brelse(bh); @@ -1012,7 +1012,7 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, retval = ext4_htree_next_block(dir, hash, frame, frames, NULL); if (retval < 0) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "error reading index page in directory #%lu", dir->i_ino); *err = retval; @@ -1537,7 +1537,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, if (levels && (dx_get_count(frames->entries) == dx_get_limit(frames->entries))) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Directory index full!"); err = -ENOSPC; goto cleanup; @@ -1865,11 +1865,11 @@ static int empty_dir (struct inode * inode) if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || !(bh = ext4_bread (NULL, inode, 0, 0, &err))) { if (err) - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "error %d reading directory #%lu offset 0", err, inode->i_ino); else - ext4_warning(inode->i_sb, __FUNCTION__, + ext4_warning(inode->i_sb, __func__, "bad directory (dir #%lu) - no data block", inode->i_ino); return 1; @@ -1898,7 +1898,7 @@ static int empty_dir (struct inode * inode) offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err); if (!bh) { if (err) - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "error %d reading directory" " #%lu offset %lu", err, inode->i_ino, offset); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 728e3efa84b..3e0f5d06f3e 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -50,63 +50,63 @@ static int verify_group_input(struct super_block *sb, ext4_get_group_no_and_offset(sb, start, NULL, &offset); if (group != sbi->s_groups_count) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Cannot add at group %u (only %lu groups)", input->group, sbi->s_groups_count); else if (offset != 0) - ext4_warning(sb, __FUNCTION__, "Last group not full"); + ext4_warning(sb, __func__, "Last group not full"); else if (input->reserved_blocks > input->blocks_count / 5) - ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", + ext4_warning(sb, __func__, "Reserved blocks too high (%u)", input->reserved_blocks); else if (free_blocks_count < 0) - ext4_warning(sb, __FUNCTION__, "Bad blocks count %u", + ext4_warning(sb, __func__, "Bad blocks count %u", input->blocks_count); else if (!(bh = sb_bread(sb, end - 1))) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Cannot read last block (%llu)", end - 1); else if (outside(input->block_bitmap, start, end)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Block bitmap not in group (block %llu)", (unsigned long long)input->block_bitmap); else if (outside(input->inode_bitmap, start, end)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Inode bitmap not in group (block %llu)", (unsigned long long)input->inode_bitmap); else if (outside(input->inode_table, start, end) || outside(itend - 1, start, end)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Inode table not in group (blocks %llu-%llu)", (unsigned long long)input->inode_table, itend - 1); else if (input->inode_bitmap == input->block_bitmap) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Block bitmap same as inode bitmap (%llu)", (unsigned long long)input->block_bitmap); else if (inside(input->block_bitmap, input->inode_table, itend)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Block bitmap (%llu) in inode table (%llu-%llu)", (unsigned long long)input->block_bitmap, (unsigned long long)input->inode_table, itend - 1); else if (inside(input->inode_bitmap, input->inode_table, itend)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Inode bitmap (%llu) in inode table (%llu-%llu)", (unsigned long long)input->inode_bitmap, (unsigned long long)input->inode_table, itend - 1); else if (inside(input->block_bitmap, start, metaend)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Block bitmap (%llu) in GDT table" " (%llu-%llu)", (unsigned long long)input->block_bitmap, start, metaend - 1); else if (inside(input->inode_bitmap, start, metaend)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Inode bitmap (%llu) in GDT table" " (%llu-%llu)", (unsigned long long)input->inode_bitmap, start, metaend - 1); else if (inside(input->inode_table, start, metaend) || inside(itend - 1, start, metaend)) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Inode table (%llu-%llu) overlaps" "GDT table (%llu-%llu)", (unsigned long long)input->inode_table, @@ -368,7 +368,7 @@ static int verify_reserved_gdb(struct super_block *sb, while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { if (le32_to_cpu(*p++) != grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "reserved GDT %llu" " missing grp %d (%llu)", blk, grp, @@ -424,7 +424,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, */ if (EXT4_SB(sb)->s_sbh->b_blocknr != le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "won't resize using backup superblock at %llu", (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr); return -EPERM; @@ -448,7 +448,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, data = (__le32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "new group %u GDT block %llu not reserved", input->group, gdblock); err = -EINVAL; @@ -472,7 +472,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, GFP_KERNEL); if (!n_group_desc) { err = -ENOMEM; - ext4_warning (sb, __FUNCTION__, + ext4_warning(sb, __func__, "not enough memory for %lu groups", gdb_num + 1); goto exit_inode; } @@ -570,7 +570,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, /* Get each reserved primary GDT block and verify it holds backups */ for (res = 0; res < reserved_gdb; res++, blk++) { if (le32_to_cpu(*data) != blk) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "reserved block %llu" " not at offset %ld", blk, @@ -714,7 +714,7 @@ static void update_backups(struct super_block *sb, */ exit_err: if (err) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "can't update backup for group %lu (err %d), " "forcing fsck on next reboot", group, err); sbi->s_mount_state &= ~EXT4_VALID_FS; @@ -754,33 +754,33 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Can't resize non-sparse filesystem further"); return -EPERM; } if (ext4_blocks_count(es) + input->blocks_count < ext4_blocks_count(es)) { - ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n"); + ext4_warning(sb, __func__, "blocks_count overflow\n"); return -EINVAL; } if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) < le32_to_cpu(es->s_inodes_count)) { - ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n"); + ext4_warning(sb, __func__, "inodes_count overflow\n"); return -EINVAL; } if (reserved_gdb || gdb_off == 0) { if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE)){ - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "No reserved GDT blocks, can't resize"); return -EPERM; } inode = ext4_iget(sb, EXT4_RESIZE_INO); if (IS_ERR(inode)) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "Error opening resize inode"); return PTR_ERR(inode); } @@ -809,7 +809,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) lock_super(sb); if (input->group != sbi->s_groups_count) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "multiple resizers run on filesystem!"); err = -EBUSY; goto exit_journal; @@ -975,13 +975,13 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, " too large to resize to %llu blocks safely\n", sb->s_id, n_blocks_count); if (sizeof(sector_t) < 8) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "CONFIG_LBD not enabled\n"); return -EINVAL; } if (n_blocks_count < o_blocks_count) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "can't shrink FS - resize aborted"); return -EBUSY; } @@ -990,7 +990,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last); if (last == 0) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "need to use ext2online to resize further"); return -EPERM; } @@ -998,7 +998,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, add = EXT4_BLOCKS_PER_GROUP(sb) - last; if (o_blocks_count + add < o_blocks_count) { - ext4_warning(sb, __FUNCTION__, "blocks_count overflow"); + ext4_warning(sb, __func__, "blocks_count overflow"); return -EINVAL; } @@ -1006,7 +1006,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, add = n_blocks_count - o_blocks_count; if (o_blocks_count + add < n_blocks_count) - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "will only finish group (%llu" " blocks, %u new)", o_blocks_count + add, add); @@ -1014,7 +1014,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, /* See if the device is actually as big as what was requested */ bh = sb_bread(sb, o_blocks_count + add -1); if (!bh) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "can't read last block, resize aborted"); return -ENOSPC; } @@ -1026,13 +1026,13 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, handle = ext4_journal_start_sb(sb, 3); if (IS_ERR(handle)) { err = PTR_ERR(handle); - ext4_warning(sb, __FUNCTION__, "error %d on journal start",err); + ext4_warning(sb, __func__, "error %d on journal start", err); goto exit_put; } lock_super(sb); if (o_blocks_count != ext4_blocks_count(es)) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "multiple resizers run on filesystem!"); unlock_super(sb); ext4_journal_stop(handle); @@ -1042,7 +1042,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh))) { - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "error %d on journal write access", err); unlock_super(sb); ext4_journal_stop(handle); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 01d163964e6..93a7e746f42 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -135,7 +135,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) * take the FS itself readonly cleanly. */ journal = EXT4_SB(sb)->s_journal; if (is_journal_aborted(journal)) { - ext4_abort(sb, __FUNCTION__, + ext4_abort(sb, __func__, "Detected aborted journal"); return ERR_PTR(-EROFS); } @@ -355,7 +355,7 @@ void ext4_update_dynamic_rev(struct super_block *sb) if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV) return; - ext4_warning(sb, __FUNCTION__, + ext4_warning(sb, __func__, "updating to rev %d because of new feature flag, " "running e2fsck is recommended", EXT4_DYNAMIC_REV); @@ -1511,7 +1511,7 @@ static int ext4_check_descriptors(struct super_block *sb) return 0; } if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "Checksum for group %lu failed (%u!=%u)\n", i, le16_to_cpu(ext4_group_desc_csum(sbi, i, gdp)), le16_to_cpu(gdp->bg_checksum)); @@ -1605,7 +1605,7 @@ static void ext4_orphan_cleanup (struct super_block * sb, if (inode->i_nlink) { printk(KERN_DEBUG "%s: truncating inode %lu to %Ld bytes\n", - __FUNCTION__, inode->i_ino, inode->i_size); + __func__, inode->i_ino, inode->i_size); jbd_debug(2, "truncating inode %lu to %Ld bytes\n", inode->i_ino, inode->i_size); ext4_truncate(inode); @@ -1613,7 +1613,7 @@ static void ext4_orphan_cleanup (struct super_block * sb, } else { printk(KERN_DEBUG "%s: deleting unreferenced inode %lu\n", - __FUNCTION__, inode->i_ino); + __func__, inode->i_ino); jbd_debug(2, "deleting unreferenced inode %lu\n", inode->i_ino); nr_orphans++; @@ -2699,9 +2699,9 @@ static void ext4_clear_journal_err(struct super_block * sb, char nbuf[16]; errstr = ext4_decode_error(sb, j_errno, nbuf); - ext4_warning(sb, __FUNCTION__, "Filesystem error recorded " + ext4_warning(sb, __func__, "Filesystem error recorded " "from previous mount: %s", errstr); - ext4_warning(sb, __FUNCTION__, "Marking fs in need of " + ext4_warning(sb, __func__, "Marking fs in need of " "filesystem check."); EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; @@ -2828,7 +2828,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) } if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) - ext4_abort(sb, __FUNCTION__, "Abort forced by user"); + ext4_abort(sb, __func__, "Abort forced by user"); sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 739930427b8..f56598df688 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -227,7 +227,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext4_xattr_check_block(bh)) { -bad_block: ext4_error(inode->i_sb, __FUNCTION__, +bad_block: ext4_error(inode->i_sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; @@ -369,7 +369,7 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); if (ext4_xattr_check_block(bh)) { - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; @@ -661,7 +661,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, atomic_read(&(bs->bh->b_count)), le32_to_cpu(BHDR(bs->bh)->h_refcount)); if (ext4_xattr_check_block(bs->bh)) { - ext4_error(sb, __FUNCTION__, + ext4_error(sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; @@ -861,7 +861,7 @@ cleanup_dquot: goto cleanup; bad_block: - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; @@ -1164,7 +1164,7 @@ retry: if (!bh) goto cleanup; if (ext4_xattr_check_block(bh)) { - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); error = -EIO; @@ -1339,14 +1339,14 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) goto cleanup; bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); if (!bh) { - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: block %llu read error", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; } if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) { - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: bad block %llu", inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; @@ -1473,7 +1473,7 @@ again: } bh = sb_bread(inode->i_sb, ce->e_block); if (!bh) { - ext4_error(inode->i_sb, __FUNCTION__, + ext4_error(inode->i_sb, __func__, "inode %lu: block %lu read error", inode->i_ino, (unsigned long) ce->e_block); } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= From 329d291f50d53f77d15769051f3eb494a9fd54b7 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Thu, 17 Apr 2008 10:38:59 -0400 Subject: [PATCH 35/48] jdb2: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Cc: Signed-off-by: Andrew Morton Signed-off-by: "Theodore Ts'o" --- fs/jbd2/journal.c | 18 +++++++++--------- fs/jbd2/revoke.c | 2 +- fs/jbd2/transaction.c | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 64356e85a10..53632e3e845 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -534,7 +534,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) if (!tid_geq(journal->j_commit_request, tid)) { printk(KERN_EMERG "%s: error: j_commit_request=%d, tid=%d\n", - __FUNCTION__, journal->j_commit_request, tid); + __func__, journal->j_commit_request, tid); } spin_unlock(&journal->j_state_lock); #endif @@ -599,7 +599,7 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, printk(KERN_ALERT "%s: journal block not found " "at offset %lu on %s\n", - __FUNCTION__, + __func__, blocknr, bdevname(journal->j_dev, b)); err = -EIO; @@ -1028,7 +1028,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev, journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); if (!journal->j_wbuf) { printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n", - __FUNCTION__); + __func__); kfree(journal); journal = NULL; goto out; @@ -1084,7 +1084,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode) journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); if (!journal->j_wbuf) { printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n", - __FUNCTION__); + __func__); kfree(journal); return NULL; } @@ -1093,7 +1093,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode) /* If that failed, give up */ if (err) { printk(KERN_ERR "%s: Cannnot locate journal superblock\n", - __FUNCTION__); + __func__); kfree(journal); return NULL; } @@ -1179,7 +1179,7 @@ int jbd2_journal_create(journal_t *journal) */ printk(KERN_EMERG "%s: creation of journal on external device!\n", - __FUNCTION__); + __func__); BUG(); } @@ -1999,7 +1999,7 @@ static struct journal_head *journal_alloc_journal_head(void) jbd_debug(1, "out of memory for journal_head\n"); if (time_after(jiffies, last_warning + 5*HZ)) { printk(KERN_NOTICE "ENOMEM in %s, retrying.\n", - __FUNCTION__); + __func__); last_warning = jiffies; } while (!ret) { @@ -2136,13 +2136,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh) if (jh->b_frozen_data) { printk(KERN_WARNING "%s: freeing " "b_frozen_data\n", - __FUNCTION__); + __func__); jbd2_free(jh->b_frozen_data, bh->b_size); } if (jh->b_committed_data) { printk(KERN_WARNING "%s: freeing " "b_committed_data\n", - __FUNCTION__); + __func__); jbd2_free(jh->b_committed_data, bh->b_size); } bh->b_private = NULL; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 144a2065f03..257ff262576 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -139,7 +139,7 @@ repeat: oom: if (!journal_oom_retry) return -ENOMEM; - jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__); + jbd_debug(1, "ENOMEM in %s, retrying\n", __func__); yield(); goto repeat; } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 401bf9d2365..d6e006e6780 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -696,7 +696,7 @@ repeat: if (!frozen_buffer) { printk(KERN_EMERG "%s: OOM for frozen_buffer\n", - __FUNCTION__); + __func__); JBUFFER_TRACE(jh, "oom!"); error = -ENOMEM; jbd_lock_bh_state(bh); @@ -914,7 +914,7 @@ repeat: committed_data = jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS); if (!committed_data) { printk(KERN_EMERG "%s: No memory for committed data\n", - __FUNCTION__); + __func__); err = -ENOMEM; goto out; } From 53b7e9f6807c1274eee19201396b4c2b5f721553 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 29 Apr 2008 22:02:11 -0400 Subject: [PATCH 36/48] ext4: Fix update of mtime and ctime on rename The patch below makes ext4 update mtime and ctime of the directory into which we move file even if the directory entry already exists. Signed-off-by: Jan Kara Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/namei.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 02cdaec39e2..7fc1bc1c16d 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2354,6 +2354,9 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, EXT4_FEATURE_INCOMPAT_FILETYPE)) new_de->file_type = old_de->file_type; new_dir->i_version++; + new_dir->i_ctime = new_dir->i_mtime = + ext4_current_time(new_dir); + ext4_mark_inode_dirty(handle, new_dir); BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata"); ext4_journal_dirty_metadata(handle, new_bh); brelse(new_bh); From 2887df139c40512cdc147d1a84d95d4f3d261bd1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 29 Apr 2008 22:02:07 -0400 Subject: [PATCH 37/48] ext4: Fix hang on umount with quotas when journal is aborted Call dquot_drop() from ext4_dquot_drop() even if we fail to start a transaction. Otherwise we never get to dropping references to quota structures from the inode and umount will hang indefinitely. Thanks to Payphone LIOU for spotting the problem. Signed-off-by: Jan Kara Signed-off-by: Mingming Cao CC: Payphone LIOU Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 93a7e746f42..e3b3483b600 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3040,8 +3040,14 @@ static int ext4_dquot_drop(struct inode *inode) /* We may delete quota structure so we need to reserve enough blocks */ handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + /* + * We call dquot_drop() anyway to at least release references + * to quota structures so that umount does not hang. + */ + dquot_drop(inode); return PTR_ERR(handle); + } ret = dquot_drop(inode); err = ext4_journal_stop(handle); if (!ret) From 216553c4b7f3e3e2beb4981cddca9b2027523928 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 29 Apr 2008 22:02:02 -0400 Subject: [PATCH 38/48] ext4: fix wrong gfp type under transaction This fixes the allocations with GFP_KERNEL while under a transaction problems in ext4. This patch is the same as its ext3 counterpart, just switches these to GFP_NOFS. Signed-off-by: Josef Bacik Cc: Signed-off-by: Andrew Morton Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/acl.c | 8 ++++---- fs/ext4/extents.c | 2 +- fs/ext4/resize.c | 4 ++-- fs/ext4/xattr.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index a8bae8cd1d5..cc92624a46a 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -37,7 +37,7 @@ ext4_acl_from_disk(const void *value, size_t size) return ERR_PTR(-EINVAL); if (count == 0) return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); + acl = posix_acl_alloc(count, GFP_NOFS); if (!acl) return ERR_PTR(-ENOMEM); for (n=0; n < count; n++) { @@ -91,7 +91,7 @@ ext4_acl_to_disk(const struct posix_acl *acl, size_t *size) *size = ext4_acl_size(acl->a_count); ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count * - sizeof(ext4_acl_entry), GFP_KERNEL); + sizeof(ext4_acl_entry), GFP_NOFS); if (!ext_acl) return ERR_PTR(-ENOMEM); ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION); @@ -187,7 +187,7 @@ ext4_get_acl(struct inode *inode, int type) } retval = ext4_xattr_get(inode, name_index, "", NULL, 0); if (retval > 0) { - value = kmalloc(retval, GFP_KERNEL); + value = kmalloc(retval, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); retval = ext4_xattr_get(inode, name_index, "", value, retval); @@ -335,7 +335,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) if (error) goto cleanup; } - clone = posix_acl_clone(acl, GFP_KERNEL); + clone = posix_acl_clone(acl, GFP_NOFS); error = -ENOMEM; if (!clone) goto cleanup; diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1c8aab4dad2..4e6afc812fd 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1977,7 +1977,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) * We start scanning from right side, freeing all the blocks * after i_size and walking into the tree depth-wise. */ - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL); + path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS); if (path == NULL) { ext4_journal_stop(handle); return -ENOMEM; diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3e0f5d06f3e..0ca63dcbdf8 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -469,7 +469,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, goto exit_dindj; n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), - GFP_KERNEL); + GFP_NOFS); if (!n_group_desc) { err = -ENOMEM; ext4_warning(sb, __func__, @@ -552,7 +552,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, int res, i; int err; - primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL); + primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS); if (!primary) return -ENOMEM; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index f56598df688..df4810d5a38 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -739,7 +739,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ce = NULL; } ea_bdebug(bs->bh, "cloning"); - s->base = kmalloc(bs->bh->b_size, GFP_KERNEL); + s->base = kmalloc(bs->bh->b_size, GFP_NOFS); error = -ENOMEM; if (s->base == NULL) goto cleanup; @@ -751,7 +751,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, } } else { /* Allocate a buffer where we construct the new block. */ - s->base = kzalloc(sb->s_blocksize, GFP_KERNEL); + s->base = kzalloc(sb->s_blocksize, GFP_NOFS); /* assert(header == s->base) */ error = -ENOMEM; if (s->base == NULL) From 3dcf54515aa4981a647ad74859199032965193a5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 29 Apr 2008 18:13:32 -0400 Subject: [PATCH 39/48] ext4: move headers out of include/linux Move ext4 headers out of include/linux. This is just the trivial move, there's some more thing that could be done later. Signed-off-by: Christoph Hellwig Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/acl.c | 4 ++-- fs/ext4/balloc.c | 6 +++--- fs/ext4/bitmap.c | 2 +- fs/ext4/dir.c | 2 +- include/linux/ext4_fs.h => fs/ext4/ext4.h | 12 ++++++------ .../ext4_fs_extents.h => fs/ext4/ext4_extents.h | 8 ++++---- include/linux/ext4_fs_i.h => fs/ext4/ext4_i.h | 8 ++++---- fs/ext4/ext4_jbd2.c | 2 +- {include/linux => fs/ext4}/ext4_jbd2.h | 10 +++++----- include/linux/ext4_fs_sb.h => fs/ext4/ext4_sb.h | 8 ++++---- fs/ext4/extents.c | 4 ++-- fs/ext4/file.c | 4 ++-- fs/ext4/fsync.c | 4 ++-- fs/ext4/hash.c | 2 +- fs/ext4/ialloc.c | 5 ++--- fs/ext4/inode.c | 2 +- fs/ext4/ioctl.c | 4 ++-- fs/ext4/mballoc.c | 4 ++-- fs/ext4/migrate.c | 4 ++-- fs/ext4/namei.c | 4 ++-- fs/ext4/resize.c | 3 +-- fs/ext4/super.c | 5 ++--- fs/ext4/symlink.c | 2 +- fs/ext4/xattr.c | 4 ++-- fs/ext4/xattr_security.c | 4 ++-- fs/ext4/xattr_trusted.c | 4 ++-- fs/ext4/xattr_user.c | 4 ++-- 27 files changed, 61 insertions(+), 64 deletions(-) rename include/linux/ext4_fs.h => fs/ext4/ext4.h (99%) rename include/linux/ext4_fs_extents.h => fs/ext4/ext4_extents.h (98%) rename include/linux/ext4_fs_i.h => fs/ext4/ext4_i.h (97%) rename {include/linux => fs/ext4}/ext4_jbd2.h (98%) rename include/linux/ext4_fs_sb.h => fs/ext4/ext4_sb.h (97%) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index cc92624a46a..3c8dab880d9 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include "ext4_jbd2.h" +#include "ext4.h" #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index af5032b23c2..da994374ec3 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -15,12 +15,12 @@ #include #include #include -#include -#include #include #include - +#include "ext4.h" +#include "ext4_jbd2.h" #include "group.h" + /* * balloc.c contains the blocks allocation and deallocation routines */ diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index 420554f8f79..d37ea675045 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -9,7 +9,7 @@ #include #include -#include +#include "ext4.h" #ifdef EXT4FS_DEBUG diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 88c97f7312b..2bf0331ea19 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -23,10 +23,10 @@ #include #include -#include #include #include #include +#include "ext4.h" static unsigned char ext4_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK diff --git a/include/linux/ext4_fs.h b/fs/ext4/ext4.h similarity index 99% rename from include/linux/ext4_fs.h rename to fs/ext4/ext4.h index 1ae0f965f38..8158083f7ac 100644 --- a/include/linux/ext4_fs.h +++ b/fs/ext4/ext4.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext4_fs.h + * ext4.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,13 +13,13 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT4_FS_H -#define _LINUX_EXT4_FS_H +#ifndef _EXT4_H +#define _EXT4_H #include #include #include -#include +#include "ext4_i.h" /* * The second extended filesystem constants/structures @@ -175,7 +175,7 @@ struct ext4_group_desc #define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ #ifdef __KERNEL__ -#include +#include "ext4_sb.h" #endif /* * Macro-instructions used to manage group descriptors @@ -1202,4 +1202,4 @@ extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, int extend_disksize); #endif /* __KERNEL__ */ -#endif /* _LINUX_EXT4_FS_H */ +#endif /* _EXT4_H */ diff --git a/include/linux/ext4_fs_extents.h b/fs/ext4/ext4_extents.h similarity index 98% rename from include/linux/ext4_fs_extents.h rename to fs/ext4/ext4_extents.h index 1285c583b2d..75333b595fa 100644 --- a/include/linux/ext4_fs_extents.h +++ b/fs/ext4/ext4_extents.h @@ -16,10 +16,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- */ -#ifndef _LINUX_EXT4_EXTENTS -#define _LINUX_EXT4_EXTENTS +#ifndef _EXT4_EXTENTS +#define _EXT4_EXTENTS -#include +#include "ext4.h" /* * With AGGRESSIVE_TEST defined, the capacity of index/leaf blocks @@ -228,5 +228,5 @@ extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *, extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *, ext4_lblk_t *, ext4_fsblk_t *); extern void ext4_ext_drop_refs(struct ext4_ext_path *); -#endif /* _LINUX_EXT4_EXTENTS */ +#endif /* _EXT4_EXTENTS */ diff --git a/include/linux/ext4_fs_i.h b/fs/ext4/ext4_i.h similarity index 97% rename from include/linux/ext4_fs_i.h rename to fs/ext4/ext4_i.h index d5508d3cf29..26a4ae255d7 100644 --- a/include/linux/ext4_fs_i.h +++ b/fs/ext4/ext4_i.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext4_fs_i.h + * ext4_i.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,8 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT4_FS_I -#define _LINUX_EXT4_FS_I +#ifndef _EXT4_I +#define _EXT4_I #include #include @@ -164,4 +164,4 @@ struct ext4_inode_info { spinlock_t i_prealloc_lock; }; -#endif /* _LINUX_EXT4_FS_I */ +#endif /* _EXT4_I */ diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 2e6007d418d..c75384b34f2 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -2,7 +2,7 @@ * Interface between ext4 and JBD */ -#include +#include "ext4_jbd2.h" int __ext4_journal_get_undo_access(const char *where, handle_t *handle, struct buffer_head *bh) diff --git a/include/linux/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h similarity index 98% rename from include/linux/ext4_jbd2.h rename to fs/ext4/ext4_jbd2.h index 38c71d3c8db..9255a7d28b2 100644 --- a/include/linux/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext4_jbd2.h + * ext4_jbd2.h * * Written by Stephen C. Tweedie , 1999 * @@ -12,12 +12,12 @@ * Ext4-specific journaling extensions. */ -#ifndef _LINUX_EXT4_JBD2_H -#define _LINUX_EXT4_JBD2_H +#ifndef _EXT4_JBD2_H +#define _EXT4_JBD2_H #include #include -#include +#include "ext4.h" #define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) @@ -228,4 +228,4 @@ static inline int ext4_should_writeback_data(struct inode *inode) return 0; } -#endif /* _LINUX_EXT4_JBD2_H */ +#endif /* _EXT4_JBD2_H */ diff --git a/include/linux/ext4_fs_sb.h b/fs/ext4/ext4_sb.h similarity index 97% rename from include/linux/ext4_fs_sb.h rename to fs/ext4/ext4_sb.h index abaae2c8ccc..5802e69f219 100644 --- a/include/linux/ext4_fs_sb.h +++ b/fs/ext4/ext4_sb.h @@ -1,5 +1,5 @@ /* - * linux/include/linux/ext4_fs_sb.h + * ext4_sb.h * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) @@ -13,8 +13,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _LINUX_EXT4_FS_SB -#define _LINUX_EXT4_FS_SB +#ifndef _EXT4_SB +#define _EXT4_SB #ifdef __KERNEL__ #include @@ -145,4 +145,4 @@ struct ext4_sb_info { struct ext4_locality_group *s_locality_groups; }; -#endif /* _LINUX_EXT4_FS_SB */ +#endif /* _EXT4_SB */ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 4e6afc812fd..a472bc04636 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -40,8 +39,9 @@ #include #include #include -#include #include +#include "ext4_jbd2.h" +#include "ext4_extents.h" /* diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 20507a24506..4159be6366a 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include "ext4.h" +#include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index a04a1ac4e0c..1c8ba48d4f8 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include "ext4.h" +#include "ext4_jbd2.h" /* * akpm: A new design for ext4_sync_file(). diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c index 1555024e3b3..1d6329dbe39 100644 --- a/fs/ext4/hash.c +++ b/fs/ext4/hash.c @@ -11,8 +11,8 @@ #include #include -#include #include +#include "ext4.h" #define DELTA 0x9E3779B9 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index a86377401ff..d59bdf7233b 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include #include @@ -25,7 +23,8 @@ #include #include #include - +#include "ext4.h" +#include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" #include "group.h" diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bd1a391725c..0c94db462c2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index ce937fe432a..7a6c2f1faba 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -10,13 +10,13 @@ #include #include #include -#include -#include #include #include #include #include #include +#include "ext4_jbd2.h" +#include "ext4.h" long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 0b46fc0ca19..f87471de3af 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include #include @@ -34,6 +32,8 @@ #include #include #include +#include "ext4_jbd2.h" +#include "ext4.h" #include "group.h" /* diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 9b4fb07d192..b9e077ba07e 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -13,8 +13,8 @@ */ #include -#include -#include +#include "ext4_jbd2.h" +#include "ext4_extents.h" /* * The contiguous blocks details which can be diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 7fc1bc1c16d..ab16beaa830 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -28,14 +28,14 @@ #include #include #include -#include -#include #include #include #include #include #include #include +#include "ext4.h" +#include "ext4_jbd2.h" #include "namei.h" #include "xattr.h" diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 0ca63dcbdf8..9f086a6a472 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -11,11 +11,10 @@ #define EXT4FS_DEBUG -#include - #include #include +#include "ext4_jbd2.h" #include "group.h" #define outside(b, first, last) ((b) < (first) || (b) >= (last)) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e3b3483b600..3435184114c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include #include @@ -38,9 +36,10 @@ #include #include #include - #include +#include "ext4.h" +#include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" #include "namei.h" diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index e6f9da4287c..e9178643dc0 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -19,8 +19,8 @@ #include #include -#include #include +#include "ext4.h" #include "xattr.h" static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index df4810d5a38..3fbc2c6c3d0 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -53,11 +53,11 @@ #include #include #include -#include -#include #include #include #include +#include "ext4_jbd2.h" +#include "ext4.h" #include "xattr.h" #include "acl.h" diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index f17eaf2321b..ca5f89fc6ca 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c @@ -6,9 +6,9 @@ #include #include #include -#include -#include #include +#include "ext4_jbd2.h" +#include "ext4.h" #include "xattr.h" static size_t diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c index e0f05acdafe..fff33382cad 100644 --- a/fs/ext4/xattr_trusted.c +++ b/fs/ext4/xattr_trusted.c @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include "ext4_jbd2.h" +#include "ext4.h" #include "xattr.h" #define XATTR_TRUSTED_PREFIX "trusted." diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c index 7ed3d8ebf09..67be723fcc4 100644 --- a/fs/ext4/xattr_user.c +++ b/fs/ext4/xattr_user.c @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include "ext4_jbd2.h" +#include "ext4.h" #include "xattr.h" #define XATTR_USER_PREFIX "user." From c83617db76353ff30e825874be2c15c185b95759 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 22:00:47 -0400 Subject: [PATCH 40/48] ext4: Don't do GFP_NOFS allocations after taking ext4_lock_group We can't do GFP_NOFS allocation after taking ext4_lock_group BUG: sleeping function called from invalid context at mm/slab.c:3054 in_atomic():1, irqs_disabled():0 1 lock held by vi/2426: #0: (&ei->i_data_sem){----}, at: [] ext4_release_file+0x23/0x66 Pid: 2426, comm: vi Not tainted 2.6.25-rc7 #24 [] __might_sleep+0xbe/0xc5 [] kmem_cache_alloc+0x22/0xa6 [] ext4_mb_release_inode_pa+0x73/0x1b3 [] ext4_mb_discard_inode_preallocations+0x22d/0x2d4 [] ? param_set_ushort+0x32/0x39 [] ext4_discard_reservation+0x27/0x6a [] ext4_release_file+0x2a/0x66 [] __fput+0xae/0x155 [] fput+0x17/0x19 [] filp_close+0x50/0x5a [] sys_close+0x71/0xad [] sysenter_past_esp+0x5f/0xa5 Signed-off-by: Aneesh Kumar K.V Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index f87471de3af..d2f0b9661fb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3730,9 +3730,9 @@ static int ext4_mb_new_preallocation(struct ext4_allocation_context *ac) */ static noinline_for_stack int ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, - struct ext4_prealloc_space *pa) + struct ext4_prealloc_space *pa, + struct ext4_allocation_context *ac) { - struct ext4_allocation_context *ac; struct super_block *sb = e4b->bd_sb; struct ext4_sb_info *sbi = EXT4_SB(sb); unsigned long end; @@ -3748,8 +3748,6 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, BUG_ON(group != e4b->bd_group && pa->pa_len != 0); end = bit + pa->pa_len; - ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); - if (ac) { ac->ac_sb = sb; ac->ac_inode = pa->pa_inode; @@ -3794,23 +3792,19 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, */ } atomic_add(free, &sbi->s_mb_discarded); - if (ac) - kmem_cache_free(ext4_ac_cachep, ac); return err; } static noinline_for_stack int ext4_mb_release_group_pa(struct ext4_buddy *e4b, - struct ext4_prealloc_space *pa) + struct ext4_prealloc_space *pa, + struct ext4_allocation_context *ac) { - struct ext4_allocation_context *ac; struct super_block *sb = e4b->bd_sb; ext4_group_t group; ext4_grpblk_t bit; - ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); - if (ac) ac->ac_op = EXT4_MB_HISTORY_DISCARD; @@ -3828,7 +3822,6 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b, ac->ac_b_ex.fe_len = pa->pa_len; ac->ac_b_ex.fe_logical = 0; ext4_mb_store_history(ac); - kmem_cache_free(ext4_ac_cachep, ac); } return 0; @@ -3850,6 +3843,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, struct ext4_group_info *grp = ext4_get_group_info(sb, group); struct buffer_head *bitmap_bh = NULL; struct ext4_prealloc_space *pa, *tmp; + struct ext4_allocation_context *ac; struct list_head list; struct ext4_buddy e4b; int err; @@ -3877,6 +3871,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, grp = ext4_get_group_info(sb, group); INIT_LIST_HEAD(&list); + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); repeat: ext4_lock_group(sb, group); list_for_each_entry_safe(pa, tmp, @@ -3931,9 +3926,9 @@ repeat: spin_unlock(pa->pa_obj_lock); if (pa->pa_linear) - ext4_mb_release_group_pa(&e4b, pa); + ext4_mb_release_group_pa(&e4b, pa, ac); else - ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa); + ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac); list_del(&pa->u.pa_tmp_list); call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); @@ -3941,6 +3936,8 @@ repeat: out: ext4_unlock_group(sb, group); + if (ac) + kmem_cache_free(ext4_ac_cachep, ac); ext4_mb_release_desc(&e4b); put_bh(bitmap_bh); return free; @@ -3961,6 +3958,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode) struct super_block *sb = inode->i_sb; struct buffer_head *bitmap_bh = NULL; struct ext4_prealloc_space *pa, *tmp; + struct ext4_allocation_context *ac; ext4_group_t group = 0; struct list_head list; struct ext4_buddy e4b; @@ -3975,6 +3973,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode) INIT_LIST_HEAD(&list); + ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); repeat: /* first, collect all pa's in the inode */ spin_lock(&ei->i_prealloc_lock); @@ -4039,7 +4038,7 @@ repeat: ext4_lock_group(sb, group); list_del(&pa->pa_group_list); - ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa); + ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac); ext4_unlock_group(sb, group); ext4_mb_release_desc(&e4b); @@ -4048,6 +4047,8 @@ repeat: list_del(&pa->u.pa_tmp_list); call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); } + if (ac) + kmem_cache_free(ext4_ac_cachep, ac); } /* From ef7377289a1510d638004158e43878643bc75dc5 Mon Sep 17 00:00:00 2001 From: Solofo Ramangalahy Date: Tue, 29 Apr 2008 22:00:41 -0400 Subject: [PATCH 41/48] ext4: update ctime and mtime for truncate with extents. The recently announced "Linux POSIX file system test suite" caught a truncate issue when using extents: mtime and ctime are not updated when truncate is successful. This is the single issue caught with "default" ext4 (mkfs and mount with minimal options). The testsuite does not report failure with -o noextents. With the following patch, all tests of the testsuite pass. Signed-off-by: Solofo Ramangalahy Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a472bc04636..47929c4e3da 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2809,6 +2809,8 @@ out_stop: ext4_orphan_del(handle, inode); up_write(&EXT4_I(inode)->i_data_sem); + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + ext4_mark_inode_dirty(handle, inode); ext4_journal_stop(handle); } From 8753e88f1b4345677620ec68f847222a6301e2fd Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 29 Apr 2008 22:00:36 -0400 Subject: [PATCH 42/48] ext4: mark inode dirty after initializing the extent tree We should mark the inode dirty only after initializing the extent tree. Also if we fail during extent initialization we need to call DQUOT_FREE_INODE. Signed-off-by: Aneesh Kumar K.V Signed-off-by: "Theodore Ts'o" --- fs/ext4/ialloc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index d59bdf7233b..c6efbab0c80 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -739,11 +739,6 @@ got: if (err) goto fail_free_drop; - err = ext4_mark_inode_dirty(handle, inode); - if (err) { - ext4_std_error(sb, err); - goto fail_free_drop; - } if (test_opt(sb, EXTENTS)) { /* set extent flag only for diretory, file and normal symlink*/ if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { @@ -752,10 +747,16 @@ got: err = ext4_update_incompat_feature(handle, sb, EXT4_FEATURE_INCOMPAT_EXTENTS); if (err) - goto fail; + goto fail_free_drop; } } + err = ext4_mark_inode_dirty(handle, inode); + if (err) { + ext4_std_error(sb, err); + goto fail_free_drop; + } + ext4_debug("allocating inode %lu\n", inode->i_ino); goto really_out; fail: From c19204b0ae3f8a125118fd5d425d3c7a5f8fda9b Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 29 Apr 2008 22:00:28 -0400 Subject: [PATCH 43/48] ext4: don't use ext4_error in ext4_check_descriptors Because ext4_check_descriptors is called at mount time you can't use ext4_error as it calls ext4_commit_sb, which since the sb isn't all the way initialized causes bad things to happen (ie a panic). This patch changes the ext4_error's to printk's to keep this problem from happening. Thanks much, Signed-off-by: Josef Bacik Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3435184114c..52dd0679a4e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1484,36 +1484,33 @@ static int ext4_check_descriptors(struct super_block *sb) block_bitmap = ext4_block_bitmap(sb, gdp); if (block_bitmap < first_block || block_bitmap > last_block) { - ext4_error (sb, "ext4_check_descriptors", - "Block bitmap for group %lu" - " not in group (block %llu)!", - i, block_bitmap); + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " + "Block bitmap for group %lu not in group " + "(block %llu)!", i, block_bitmap); return 0; } inode_bitmap = ext4_inode_bitmap(sb, gdp); if (inode_bitmap < first_block || inode_bitmap > last_block) { - ext4_error (sb, "ext4_check_descriptors", - "Inode bitmap for group %lu" - " not in group (block %llu)!", - i, inode_bitmap); + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " + "Inode bitmap for group %lu not in group " + "(block %llu)!", i, inode_bitmap); return 0; } inode_table = ext4_inode_table(sb, gdp); if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { - ext4_error (sb, "ext4_check_descriptors", - "Inode table for group %lu" - " not in group (block %llu)!", - i, inode_table); + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " + "Inode table for group %lu not in group " + "(block %llu)!", i, inode_table); return 0; } if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { - ext4_error(sb, __func__, - "Checksum for group %lu failed (%u!=%u)\n", - i, le16_to_cpu(ext4_group_desc_csum(sbi, i, - gdp)), le16_to_cpu(gdp->bg_checksum)); + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " + "Checksum for group %lu failed (%u!=%u)\n", + i, le16_to_cpu(ext4_group_desc_csum(sbi, i, + gdp)), le16_to_cpu(gdp->bg_checksum)); return 0; } if (!flexbg_flag) From 60bd63d1928c65abd71d8b9b45672cf6e3101845 Mon Sep 17 00:00:00 2001 From: Solofo Ramangalahy Date: Tue, 29 Apr 2008 21:59:59 -0400 Subject: [PATCH 44/48] ext4: cleanup for compiling mballoc with verification and debugging #defines This patch allows compiling mballoc with: #define AGGRESSIVE_CHECK #define DOUBLE_CHECK #define MB_DEBUG It fixes: Compilation errors: fs/ext4/mballoc.c: In function '__mb_check_buddy': fs/ext4/mballoc.c:605: error: 'struct ext4_prealloc_space' has no member named 'group_list' fs/ext4/mballoc.c:606: error: 'struct ext4_prealloc_space' has no member named 'pstart' fs/ext4/mballoc.c:608: error: 'struct ext4_prealloc_space' has no member named 'len' Compilation warnings: fs/ext4/mballoc.c: In function 'ext4_mb_normalize_group_request': fs/ext4/mballoc.c:2863: warning: format '%lu' expects type 'long unsigned int', but argument 3 has type 'int' fs/ext4/mballoc.c: In function 'ext4_mb_use_inode_pa': fs/ext4/mballoc.c:3103: warning: format '%lu' expects type 'long unsigned int', but argument 3 has type 'int' Sparse check: fs/ext4/mballoc.c:3818:2: warning: context imbalance in 'ext4_mb_show_ac' - different lock contexts for basic block Signed-off-by: Solofo Ramangalahy Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index d2f0b9661fb..d4ae948606e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -896,10 +896,10 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, list_for_each(cur, &grp->bb_prealloc_list) { ext4_group_t groupnr; struct ext4_prealloc_space *pa; - pa = list_entry(cur, struct ext4_prealloc_space, group_list); - ext4_get_group_no_and_offset(sb, pa->pstart, &groupnr, &k); + pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); + ext4_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &k); MB_CHECK_ASSERT(groupnr == e4b->bd_group); - for (i = 0; i < pa->len; i++) + for (i = 0; i < pa->pa_len; i++) MB_CHECK_ASSERT(mb_test_bit(k + i, buddy)); } return 0; @@ -3131,7 +3131,7 @@ static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac) ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe; else ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; - mb_debug("#%u: goal %lu blocks for locality group\n", + mb_debug("#%u: goal %u blocks for locality group\n", current->pid, ac->ac_g_ex.fe_len); } @@ -3371,7 +3371,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, BUG_ON(pa->pa_free < len); pa->pa_free -= len; - mb_debug("use %llu/%lu from inode pa %p\n", start, len, pa); + mb_debug("use %llu/%u from inode pa %p\n", start, len, pa); } /* @@ -4108,7 +4108,7 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac) printk(KERN_ERR "PA:%lu:%d:%u \n", i, start, pa->pa_len); } - ext4_lock_group(sb, i); + ext4_unlock_group(sb, i); if (grp->bb_free == 0) continue; From 8f6e39a7ade8a5329c5651a2bc07010b3011da6a Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Tue, 29 Apr 2008 22:01:31 -0400 Subject: [PATCH 45/48] ext4: Move mballoc headers/structures to a seperate header file mballoc.h Move function and structure definiations out of mballoc.c and put it under a new header file mballoc.h Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 296 +------------------------------------------- fs/ext4/mballoc.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+), 295 deletions(-) create mode 100644 fs/ext4/mballoc.h diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index d4ae948606e..11e1fd59acb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -21,21 +21,7 @@ * mballoc.c contains the multiblocks allocation routines */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "group.h" - +#include "mballoc.h" /* * MUSTDO: * - test ext4_ext_search_left() and ext4_ext_search_right() @@ -345,286 +331,6 @@ * */ -/* - * with AGGRESSIVE_CHECK allocator runs consistency checks over - * structures. these checks slow things down a lot - */ -#define AGGRESSIVE_CHECK__ - -/* - * with DOUBLE_CHECK defined mballoc creates persistent in-core - * bitmaps, maintains and uses them to check for double allocations - */ -#define DOUBLE_CHECK__ - -/* - */ -#define MB_DEBUG__ -#ifdef MB_DEBUG -#define mb_debug(fmt, a...) printk(fmt, ##a) -#else -#define mb_debug(fmt, a...) -#endif - -/* - * with EXT4_MB_HISTORY mballoc stores last N allocations in memory - * and you can monitor it in /proc/fs/ext4//mb_history - */ -#define EXT4_MB_HISTORY -#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */ -#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */ -#define EXT4_MB_HISTORY_DISCARD 4 /* preallocation discarded */ -#define EXT4_MB_HISTORY_FREE 8 /* free */ - -#define EXT4_MB_HISTORY_DEFAULT (EXT4_MB_HISTORY_ALLOC | \ - EXT4_MB_HISTORY_PREALLOC) - -/* - * How long mballoc can look for a best extent (in found extents) - */ -#define MB_DEFAULT_MAX_TO_SCAN 200 - -/* - * How long mballoc must look for a best extent - */ -#define MB_DEFAULT_MIN_TO_SCAN 10 - -/* - * How many groups mballoc will scan looking for the best chunk - */ -#define MB_DEFAULT_MAX_GROUPS_TO_SCAN 5 - -/* - * with 'ext4_mb_stats' allocator will collect stats that will be - * shown at umount. The collecting costs though! - */ -#define MB_DEFAULT_STATS 1 - -/* - * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served - * by the stream allocator, which purpose is to pack requests - * as close each to other as possible to produce smooth I/O traffic - * We use locality group prealloc space for stream request. - * We can tune the same via /proc/fs/ext4//stream_req - */ -#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */ - -/* - * for which requests use 2^N search using buddies - */ -#define MB_DEFAULT_ORDER2_REQS 2 - -/* - * default group prealloc size 512 blocks - */ -#define MB_DEFAULT_GROUP_PREALLOC 512 - -static struct kmem_cache *ext4_pspace_cachep; -static struct kmem_cache *ext4_ac_cachep; - -#ifdef EXT4_BB_MAX_BLOCKS -#undef EXT4_BB_MAX_BLOCKS -#endif -#define EXT4_BB_MAX_BLOCKS 30 - -struct ext4_free_metadata { - ext4_group_t group; - unsigned short num; - ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS]; - struct list_head list; -}; - -struct ext4_group_info { - unsigned long bb_state; - unsigned long bb_tid; - struct ext4_free_metadata *bb_md_cur; - unsigned short bb_first_free; - unsigned short bb_free; - unsigned short bb_fragments; - struct list_head bb_prealloc_list; -#ifdef DOUBLE_CHECK - void *bb_bitmap; -#endif - unsigned short bb_counters[]; -}; - -#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 -#define EXT4_GROUP_INFO_LOCKED_BIT 1 - -#define EXT4_MB_GRP_NEED_INIT(grp) \ - (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) - - -struct ext4_prealloc_space { - struct list_head pa_inode_list; - struct list_head pa_group_list; - union { - struct list_head pa_tmp_list; - struct rcu_head pa_rcu; - } u; - spinlock_t pa_lock; - atomic_t pa_count; - unsigned pa_deleted; - ext4_fsblk_t pa_pstart; /* phys. block */ - ext4_lblk_t pa_lstart; /* log. block */ - unsigned short pa_len; /* len of preallocated chunk */ - unsigned short pa_free; /* how many blocks are free */ - unsigned short pa_linear; /* consumed in one direction - * strictly, for grp prealloc */ - spinlock_t *pa_obj_lock; - struct inode *pa_inode; /* hack, for history only */ -}; - - -struct ext4_free_extent { - ext4_lblk_t fe_logical; - ext4_grpblk_t fe_start; - ext4_group_t fe_group; - int fe_len; -}; - -/* - * Locality group: - * we try to group all related changes together - * so that writeback can flush/allocate them together as well - */ -struct ext4_locality_group { - /* for allocator */ - struct mutex lg_mutex; /* to serialize allocates */ - struct list_head lg_prealloc_list;/* list of preallocations */ - spinlock_t lg_prealloc_lock; -}; - -struct ext4_allocation_context { - struct inode *ac_inode; - struct super_block *ac_sb; - - /* original request */ - struct ext4_free_extent ac_o_ex; - - /* goal request (after normalization) */ - struct ext4_free_extent ac_g_ex; - - /* the best found extent */ - struct ext4_free_extent ac_b_ex; - - /* copy of the bext found extent taken before preallocation efforts */ - struct ext4_free_extent ac_f_ex; - - /* number of iterations done. we have to track to limit searching */ - unsigned long ac_ex_scanned; - __u16 ac_groups_scanned; - __u16 ac_found; - __u16 ac_tail; - __u16 ac_buddy; - __u16 ac_flags; /* allocation hints */ - __u8 ac_status; - __u8 ac_criteria; - __u8 ac_repeats; - __u8 ac_2order; /* if request is to allocate 2^N blocks and - * N > 0, the field stores N, otherwise 0 */ - __u8 ac_op; /* operation, for history only */ - struct page *ac_bitmap_page; - struct page *ac_buddy_page; - struct ext4_prealloc_space *ac_pa; - struct ext4_locality_group *ac_lg; -}; - -#define AC_STATUS_CONTINUE 1 -#define AC_STATUS_FOUND 2 -#define AC_STATUS_BREAK 3 - -struct ext4_mb_history { - struct ext4_free_extent orig; /* orig allocation */ - struct ext4_free_extent goal; /* goal allocation */ - struct ext4_free_extent result; /* result allocation */ - unsigned pid; - unsigned ino; - __u16 found; /* how many extents have been found */ - __u16 groups; /* how many groups have been scanned */ - __u16 tail; /* what tail broke some buddy */ - __u16 buddy; /* buddy the tail ^^^ broke */ - __u16 flags; - __u8 cr:3; /* which phase the result extent was found at */ - __u8 op:4; - __u8 merged:1; -}; - -struct ext4_buddy { - struct page *bd_buddy_page; - void *bd_buddy; - struct page *bd_bitmap_page; - void *bd_bitmap; - struct ext4_group_info *bd_info; - struct super_block *bd_sb; - __u16 bd_blkbits; - ext4_group_t bd_group; -}; -#define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap) -#define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy) - -#ifndef EXT4_MB_HISTORY -static inline void ext4_mb_store_history(struct ext4_allocation_context *ac) -{ - return; -} -#else -static void ext4_mb_store_history(struct ext4_allocation_context *ac); -#endif - -#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) - -static struct proc_dir_entry *proc_root_ext4; -struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t); - -static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, - ext4_group_t group); -static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *); -static void ext4_mb_free_committed_blocks(struct super_block *); -static void ext4_mb_return_to_preallocation(struct inode *inode, - struct ext4_buddy *e4b, sector_t block, - int count); -static void ext4_mb_put_pa(struct ext4_allocation_context *, - struct super_block *, struct ext4_prealloc_space *pa); -static int ext4_mb_init_per_dev_proc(struct super_block *sb); -static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); - - -static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) -{ - struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); - - bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); -} - -static inline void ext4_unlock_group(struct super_block *sb, - ext4_group_t group) -{ - struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); - - bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); -} - -static inline int ext4_is_group_locked(struct super_block *sb, - ext4_group_t group) -{ - struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); - - return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT, - &(grinfo->bb_state)); -} - -static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, - struct ext4_free_extent *fex) -{ - ext4_fsblk_t block; - - block = (ext4_fsblk_t) fex->fe_group * EXT4_BLOCKS_PER_GROUP(sb) - + fex->fe_start - + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); - return block; -} - static inline void *mb_correct_addr_and_bit(int *bit, void *addr) { #if BITS_PER_LONG == 64 diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h new file mode 100644 index 00000000000..bfe6add46bc --- /dev/null +++ b/fs/ext4/mballoc.h @@ -0,0 +1,304 @@ +/* + * fs/ext4/mballoc.h + * + * Written by: Alex Tomas + * + */ +#ifndef _EXT4_MBALLOC_H +#define _EXT4_MBALLOC_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ext4_jbd2.h" +#include "ext4.h" +#include "group.h" + +/* + * with AGGRESSIVE_CHECK allocator runs consistency checks over + * structures. these checks slow things down a lot + */ +#define AGGRESSIVE_CHECK__ + +/* + * with DOUBLE_CHECK defined mballoc creates persistent in-core + * bitmaps, maintains and uses them to check for double allocations + */ +#define DOUBLE_CHECK__ + +/* + */ +#define MB_DEBUG__ +#ifdef MB_DEBUG +#define mb_debug(fmt, a...) printk(fmt, ##a) +#else +#define mb_debug(fmt, a...) +#endif + +/* + * with EXT4_MB_HISTORY mballoc stores last N allocations in memory + * and you can monitor it in /proc/fs/ext4//mb_history + */ +#define EXT4_MB_HISTORY +#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */ +#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */ +#define EXT4_MB_HISTORY_DISCARD 4 /* preallocation discarded */ +#define EXT4_MB_HISTORY_FREE 8 /* free */ + +#define EXT4_MB_HISTORY_DEFAULT (EXT4_MB_HISTORY_ALLOC | \ + EXT4_MB_HISTORY_PREALLOC) + +/* + * How long mballoc can look for a best extent (in found extents) + */ +#define MB_DEFAULT_MAX_TO_SCAN 200 + +/* + * How long mballoc must look for a best extent + */ +#define MB_DEFAULT_MIN_TO_SCAN 10 + +/* + * How many groups mballoc will scan looking for the best chunk + */ +#define MB_DEFAULT_MAX_GROUPS_TO_SCAN 5 + +/* + * with 'ext4_mb_stats' allocator will collect stats that will be + * shown at umount. The collecting costs though! + */ +#define MB_DEFAULT_STATS 1 + +/* + * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served + * by the stream allocator, which purpose is to pack requests + * as close each to other as possible to produce smooth I/O traffic + * We use locality group prealloc space for stream request. + * We can tune the same via /proc/fs/ext4//stream_req + */ +#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */ + +/* + * for which requests use 2^N search using buddies + */ +#define MB_DEFAULT_ORDER2_REQS 2 + +/* + * default group prealloc size 512 blocks + */ +#define MB_DEFAULT_GROUP_PREALLOC 512 + +static struct kmem_cache *ext4_pspace_cachep; +static struct kmem_cache *ext4_ac_cachep; + +#ifdef EXT4_BB_MAX_BLOCKS +#undef EXT4_BB_MAX_BLOCKS +#endif +#define EXT4_BB_MAX_BLOCKS 30 + +struct ext4_free_metadata { + ext4_group_t group; + unsigned short num; + ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS]; + struct list_head list; +}; + +struct ext4_group_info { + unsigned long bb_state; + unsigned long bb_tid; + struct ext4_free_metadata *bb_md_cur; + unsigned short bb_first_free; + unsigned short bb_free; + unsigned short bb_fragments; + struct list_head bb_prealloc_list; +#ifdef DOUBLE_CHECK + void *bb_bitmap; +#endif + unsigned short bb_counters[]; +}; + +#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 +#define EXT4_GROUP_INFO_LOCKED_BIT 1 + +#define EXT4_MB_GRP_NEED_INIT(grp) \ + (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) + + +struct ext4_prealloc_space { + struct list_head pa_inode_list; + struct list_head pa_group_list; + union { + struct list_head pa_tmp_list; + struct rcu_head pa_rcu; + } u; + spinlock_t pa_lock; + atomic_t pa_count; + unsigned pa_deleted; + ext4_fsblk_t pa_pstart; /* phys. block */ + ext4_lblk_t pa_lstart; /* log. block */ + unsigned short pa_len; /* len of preallocated chunk */ + unsigned short pa_free; /* how many blocks are free */ + unsigned short pa_linear; /* consumed in one direction + * strictly, for grp prealloc */ + spinlock_t *pa_obj_lock; + struct inode *pa_inode; /* hack, for history only */ +}; + + +struct ext4_free_extent { + ext4_lblk_t fe_logical; + ext4_grpblk_t fe_start; + ext4_group_t fe_group; + int fe_len; +}; + +/* + * Locality group: + * we try to group all related changes together + * so that writeback can flush/allocate them together as well + */ +struct ext4_locality_group { + /* for allocator */ + struct mutex lg_mutex; /* to serialize allocates */ + struct list_head lg_prealloc_list;/* list of preallocations */ + spinlock_t lg_prealloc_lock; +}; + +struct ext4_allocation_context { + struct inode *ac_inode; + struct super_block *ac_sb; + + /* original request */ + struct ext4_free_extent ac_o_ex; + + /* goal request (after normalization) */ + struct ext4_free_extent ac_g_ex; + + /* the best found extent */ + struct ext4_free_extent ac_b_ex; + + /* copy of the bext found extent taken before preallocation efforts */ + struct ext4_free_extent ac_f_ex; + + /* number of iterations done. we have to track to limit searching */ + unsigned long ac_ex_scanned; + __u16 ac_groups_scanned; + __u16 ac_found; + __u16 ac_tail; + __u16 ac_buddy; + __u16 ac_flags; /* allocation hints */ + __u8 ac_status; + __u8 ac_criteria; + __u8 ac_repeats; + __u8 ac_2order; /* if request is to allocate 2^N blocks and + * N > 0, the field stores N, otherwise 0 */ + __u8 ac_op; /* operation, for history only */ + struct page *ac_bitmap_page; + struct page *ac_buddy_page; + struct ext4_prealloc_space *ac_pa; + struct ext4_locality_group *ac_lg; +}; + +#define AC_STATUS_CONTINUE 1 +#define AC_STATUS_FOUND 2 +#define AC_STATUS_BREAK 3 + +struct ext4_mb_history { + struct ext4_free_extent orig; /* orig allocation */ + struct ext4_free_extent goal; /* goal allocation */ + struct ext4_free_extent result; /* result allocation */ + unsigned pid; + unsigned ino; + __u16 found; /* how many extents have been found */ + __u16 groups; /* how many groups have been scanned */ + __u16 tail; /* what tail broke some buddy */ + __u16 buddy; /* buddy the tail ^^^ broke */ + __u16 flags; + __u8 cr:3; /* which phase the result extent was found at */ + __u8 op:4; + __u8 merged:1; +}; + +struct ext4_buddy { + struct page *bd_buddy_page; + void *bd_buddy; + struct page *bd_bitmap_page; + void *bd_bitmap; + struct ext4_group_info *bd_info; + struct super_block *bd_sb; + __u16 bd_blkbits; + ext4_group_t bd_group; +}; +#define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap) +#define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy) + +#ifndef EXT4_MB_HISTORY +static inline void ext4_mb_store_history(struct ext4_allocation_context *ac) +{ + return; +} +#else +static void ext4_mb_store_history(struct ext4_allocation_context *ac); +#endif + +#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +static struct proc_dir_entry *proc_root_ext4; +struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t); + +static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, + ext4_group_t group); +static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *); +static void ext4_mb_free_committed_blocks(struct super_block *); +static void ext4_mb_return_to_preallocation(struct inode *inode, + struct ext4_buddy *e4b, sector_t block, + int count); +static void ext4_mb_put_pa(struct ext4_allocation_context *, + struct super_block *, struct ext4_prealloc_space *pa); +static int ext4_mb_init_per_dev_proc(struct super_block *sb); +static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); + + +static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) +{ + struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); + + bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); +} + +static inline void ext4_unlock_group(struct super_block *sb, + ext4_group_t group) +{ + struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); + + bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); +} + +static inline int ext4_is_group_locked(struct super_block *sb, + ext4_group_t group) +{ + struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); + + return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT, + &(grinfo->bb_state)); +} + +static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, + struct ext4_free_extent *fex) +{ + ext4_fsblk_t block; + + block = (ext4_fsblk_t) fex->fe_group * EXT4_BLOCKS_PER_GROUP(sb) + + fex->fe_start + + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); + return block; +} +#endif From 7c2f3d6f89aab04c5c66a0a757888d3a77a5e899 Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Tue, 29 Apr 2008 22:01:27 -0400 Subject: [PATCH 46/48] ext3: fix test ext_generic_write_end() copied return value 'copied' is unsigned, whereas 'ret2' is not. The test (copied < 0) fails Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: "Theodore Ts'o" --- fs/ext3/inode.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index cc47b76091b..6ae4ecf3ce4 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1261,10 +1261,11 @@ static int ext3_ordered_write_end(struct file *file, new_i_size = pos + copied; if (new_i_size > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = new_i_size; - copied = ext3_generic_write_end(file, mapping, pos, len, copied, + ret2 = ext3_generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (copied < 0) - ret = copied; + copied = ret2; + if (ret2 < 0) + ret = ret2; } ret2 = ext3_journal_stop(handle); if (!ret) @@ -1289,10 +1290,11 @@ static int ext3_writeback_write_end(struct file *file, if (new_i_size > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = new_i_size; - copied = ext3_generic_write_end(file, mapping, pos, len, copied, + ret2 = ext3_generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (copied < 0) - ret = copied; + copied = ret2; + if (ret2 < 0) + ret = ret2; ret2 = ext3_journal_stop(handle); if (!ret) From f8a87d89304c1eea8e4a8dc02d134f57590913c6 Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Tue, 29 Apr 2008 22:01:18 -0400 Subject: [PATCH 47/48] ext4: fix test ext_generic_write_end() copied return value 'copied' is unsigned, whereas 'ret2' is not. The test (copied < 0) fails Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/inode.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0c94db462c2..8d970774641 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1311,10 +1311,11 @@ static int ext4_ordered_write_end(struct file *file, new_i_size = pos + copied; if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - copied = ext4_generic_write_end(file, mapping, pos, len, copied, + ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (copied < 0) - ret = copied; + copied = ret2; + if (ret2 < 0) + ret = ret2; } ret2 = ext4_journal_stop(handle); if (!ret) @@ -1339,10 +1340,11 @@ static int ext4_writeback_write_end(struct file *file, if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - copied = ext4_generic_write_end(file, mapping, pos, len, copied, + ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (copied < 0) - ret = copied; + copied = ret2; + if (ret2 < 0) + ret = ret2; ret2 = ext4_journal_stop(handle); if (!ret) From f1fa3342e271029f93d323ca664809b94594fe04 Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Tue, 29 Apr 2008 22:01:15 -0400 Subject: [PATCH 48/48] ext4: fix hot spins in mballoc after err_freebuddy and err_freemeta In ext4_mb_init_backend() 'i' is of type ext4_group_t. Since unsigned, i >= 0 is always true, so fix hot spins after err_freebuddy: and -meta: and prevent decrements when zero. Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/mballoc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 11e1fd59acb..fbec2ef9379 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2272,13 +2272,13 @@ static int ext4_mb_init_backend(struct super_block *sb) meta_group_info[j] = kzalloc(len, GFP_KERNEL); if (meta_group_info[j] == NULL) { printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n"); - i--; goto err_freebuddy; } desc = ext4_get_group_desc(sb, i, NULL); if (desc == NULL) { printk(KERN_ERR "EXT4-fs: can't read descriptor %lu\n", i); + i++; goto err_freebuddy; } memset(meta_group_info[j], 0, len); @@ -2318,13 +2318,11 @@ static int ext4_mb_init_backend(struct super_block *sb) return 0; err_freebuddy: - while (i >= 0) { + while (i-- > 0) kfree(ext4_get_group_info(sb, i)); - i--; - } i = num_meta_group_infos; err_freemeta: - while (--i >= 0) + while (i-- > 0) kfree(sbi->s_group_info[i]); iput(sbi->s_buddy_cache); err_freesgi: