diff options
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/bitmap.c | 57 | ||||
-rw-r--r-- | fs/reiserfs/dir.c | 10 | ||||
-rw-r--r-- | fs/reiserfs/inode.c | 4 | ||||
-rw-r--r-- | fs/reiserfs/journal.c | 145 | ||||
-rw-r--r-- | fs/reiserfs/super.c | 20 |
5 files changed, 119 insertions, 117 deletions
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index b286ccb08587..2a5dd34649b3 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -1201,63 +1201,6 @@ int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t * hint, b_blocknr_t * new return ret; } -/* These 2 functions are here to provide blocks reservation to the rest of kernel */ -/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure - there are actually this much blocks on the FS available */ -void reiserfs_claim_blocks_to_be_allocated(struct super_block *sb, /* super block of - filesystem where - blocks should be - reserved */ - int blocks /* How much to reserve */ - ) -{ - - /* Fast case, if reservation is zero - exit immediately. */ - if (!blocks) - return; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - REISERFS_SB(sb)->reserved_blocks += blocks; - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); -} - -/* Unreserve @blocks amount of blocks in fs pointed by @sb */ -void reiserfs_release_claimed_blocks(struct super_block *sb, /* super block of - filesystem where - blocks should be - reserved */ - int blocks /* How much to unreserve */ - ) -{ - - /* Fast case, if unreservation is zero - exit immediately. */ - if (!blocks) - return; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - REISERFS_SB(sb)->reserved_blocks -= blocks; - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); - RFALSE(REISERFS_SB(sb)->reserved_blocks < 0, - "amount of blocks reserved became zero?"); -} - -/* This function estimates how much pages we will be able to write to FS - used for reiserfs_file_write() purposes for now. */ -int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem - to estimate space */ ) -{ - int space; - - spin_lock(&REISERFS_SB(sb)->bitmap_lock); - space = - (SB_FREE_BLOCKS(sb) - - REISERFS_SB(sb)->reserved_blocks) >> (PAGE_CACHE_SHIFT - - sb->s_blocksize_bits); - spin_unlock(&REISERFS_SB(sb)->bitmap_lock); - - return space > 0 ? space : 0; -} - void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info) diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index ffbfc2caaf20..e6b03d2020c1 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -121,6 +121,16 @@ static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) continue; d_reclen = entry_length(bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); + + if (d_reclen <= 0 || + d_name + d_reclen > bh->b_data + bh->b_size) { + /* There is corrupted data in entry, + * We'd better stop here */ + pathrelse(&path_to_entry); + ret = -EIO; + goto out; + } + if (!d_name[d_reclen - 1]) d_reclen = strlen(d_name); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 95051d44a918..9ea12004fa57 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -208,8 +208,8 @@ static int file_capable(struct inode *inode, long block) return 0; } -/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th, - struct inode *inode, struct treepath *path) +static int restart_transaction(struct reiserfs_transaction_handle *th, + struct inode *inode, struct treepath *path) { struct super_block *s = th->t_super; int len = th->t_blocks_allocated; diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index f25086aeef5f..4cad9e75ef56 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -615,6 +615,31 @@ static int journal_list_still_alive(struct super_block *s, return 0; } +/* + * If page->mapping was null, we failed to truncate this page for + * some reason. Most likely because it was truncated after being + * logged via data=journal. + * + * This does a check to see if the buffer belongs to one of these + * lost pages before doing the final put_bh. If page->mapping was + * null, it tries to free buffers on the page, which should make the + * final page_cache_release drop the page from the lru. + */ +static void release_buffer_page(struct buffer_head *bh) +{ + struct page *page = bh->b_page; + if (!page->mapping && !TestSetPageLocked(page)) { + page_cache_get(page); + put_bh(bh); + if (!page->mapping) + try_to_free_buffers(page); + unlock_page(page); + page_cache_release(page); + } else { + put_bh(bh); + } +} + static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) { char b[BDEVNAME_SIZE]; @@ -628,8 +653,9 @@ static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) set_buffer_uptodate(bh); else clear_buffer_uptodate(bh); + unlock_buffer(bh); - put_bh(bh); + release_buffer_page(bh); } static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) @@ -966,7 +992,8 @@ static int flush_older_commits(struct super_block *s, } return 0; } -int reiserfs_async_progress_wait(struct super_block *s) + +static int reiserfs_async_progress_wait(struct super_block *s) { DEFINE_WAIT(wait); struct reiserfs_journal *j = SB_JOURNAL(s); @@ -1546,9 +1573,10 @@ static int flush_journal_list(struct super_block *s, BUG_ON(!test_clear_buffer_journal_dirty (cn->bh)); - /* undo the inc from journal_mark_dirty */ + /* drop one ref for us */ put_bh(cn->bh); - brelse(cn->bh); + /* drop one ref for journal_mark_dirty */ + release_buffer_page(cn->bh); } cn = cn->next; } @@ -2621,6 +2649,61 @@ static int journal_init_dev(struct super_block *super, return result; } +/** + * When creating/tuning a file system user can assign some + * journal params within boundaries which depend on the ratio + * blocksize/standard_blocksize. + * + * For blocks >= standard_blocksize transaction size should + * be not less then JOURNAL_TRANS_MIN_DEFAULT, and not more + * then JOURNAL_TRANS_MAX_DEFAULT. + * + * For blocks < standard_blocksize these boundaries should be + * decreased proportionally. + */ +#define REISERFS_STANDARD_BLKSIZE (4096) + +static int check_advise_trans_params(struct super_block *p_s_sb, + struct reiserfs_journal *journal) +{ + if (journal->j_trans_max) { + /* Non-default journal params. + Do sanity check for them. */ + int ratio = 1; + if (p_s_sb->s_blocksize < REISERFS_STANDARD_BLKSIZE) + ratio = REISERFS_STANDARD_BLKSIZE / p_s_sb->s_blocksize; + + if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio || + journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio || + SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max < + JOURNAL_MIN_RATIO) { + reiserfs_warning(p_s_sb, + "sh-462: bad transaction max size (%u). FSCK?", + journal->j_trans_max); + return 1; + } + if (journal->j_max_batch != (journal->j_trans_max) * + JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT) { + reiserfs_warning(p_s_sb, + "sh-463: bad transaction max batch (%u). FSCK?", + journal->j_max_batch); + return 1; + } + } else { + /* Default journal params. + The file system was created by old version + of mkreiserfs, so some fields contain zeros, + and we need to advise proper values for them */ + if (p_s_sb->s_blocksize != REISERFS_STANDARD_BLKSIZE) + reiserfs_panic(p_s_sb, "sh-464: bad blocksize (%u)", + p_s_sb->s_blocksize); + journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT; + journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT; + journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE; + } + return 0; +} + /* ** must be called once on fs mount. calls journal_read for you */ @@ -2716,49 +2799,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, le32_to_cpu(jh->jh_journal.jp_journal_max_commit_age); journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE; - if (journal->j_trans_max) { - /* make sure these parameters are available, assign it if they are not */ - __u32 initial = journal->j_trans_max; - __u32 ratio = 1; - - if (p_s_sb->s_blocksize < 4096) - ratio = 4096 / p_s_sb->s_blocksize; - - if (SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max < - JOURNAL_MIN_RATIO) - journal->j_trans_max = - SB_ONDISK_JOURNAL_SIZE(p_s_sb) / JOURNAL_MIN_RATIO; - if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio) - journal->j_trans_max = - JOURNAL_TRANS_MAX_DEFAULT / ratio; - if (journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio) - journal->j_trans_max = - JOURNAL_TRANS_MIN_DEFAULT / ratio; - - if (journal->j_trans_max != initial) - reiserfs_warning(p_s_sb, - "sh-461: journal_init: wrong transaction max size (%u). Changed to %u", - initial, journal->j_trans_max); - - journal->j_max_batch = journal->j_trans_max * - JOURNAL_MAX_BATCH_DEFAULT / JOURNAL_TRANS_MAX_DEFAULT; - } - - if (!journal->j_trans_max) { - /*we have the file system was created by old version of mkreiserfs - so this field contains zero value */ - journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT; - journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT; - journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE; - - /* for blocksize >= 4096 - max transaction size is 1024. For block size < 4096 - trans max size is decreased proportionally */ - if (p_s_sb->s_blocksize < 4096) { - journal->j_trans_max /= (4096 / p_s_sb->s_blocksize); - journal->j_max_batch = (journal->j_trans_max) * 9 / 10; - } - } - + if (check_advise_trans_params(p_s_sb, journal) != 0) + goto free_and_return; journal->j_default_max_commit_age = journal->j_max_commit_age; if (commit_max_age != 0) { @@ -3708,13 +3750,8 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, } } - if (bh) { - put_bh(bh); /* get_hash grabs the buffer */ - if (atomic_read(&(bh->b_count)) < 0) { - reiserfs_warning(p_s_sb, - "journal-2165: bh->b_count < 0"); - } - } + if (bh) + release_buffer_page(bh); /* get_hash grabs the buffer */ return 0; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index a005451930b7..b82897ae090b 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -145,7 +145,7 @@ static int finish_unfinished(struct super_block *s) { INITIALIZE_PATH(path); struct cpu_key max_cpu_key, obj_key; - struct reiserfs_key save_link_key; + struct reiserfs_key save_link_key, last_inode_key; int retval = 0; struct item_head *ih; struct buffer_head *bh; @@ -166,6 +166,8 @@ static int finish_unfinished(struct super_block *s) set_cpu_key_k_offset(&max_cpu_key, ~0U); max_cpu_key.key_length = 3; + memset(&last_inode_key, 0, sizeof(last_inode_key)); + #ifdef CONFIG_QUOTA /* Needed for iput() to work correctly and not trash data */ if (s->s_flags & MS_ACTIVE) { @@ -278,8 +280,18 @@ static int finish_unfinished(struct super_block *s) REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; /* not completed unlink (rmdir) found */ reiserfs_info(s, "Removing %k..", INODE_PKEY(inode)); - /* removal gets completed in iput */ - retval = 0; + if (memcmp(&last_inode_key, INODE_PKEY(inode), + sizeof(last_inode_key))){ + last_inode_key = *INODE_PKEY(inode); + /* removal gets completed in iput */ + retval = 0; + } else { + reiserfs_warning(s, "Dead loop in " + "finish_unfinished detected, " + "just remove save link\n"); + retval = remove_save_link_only(s, + &save_link_key, 0); + } } iput(inode); @@ -508,7 +520,7 @@ static void reiserfs_destroy_inode(struct inode *inode) kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); } -static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache * cachep, void *foo) { struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; |