diff options
Diffstat (limited to 'fs/ext4/super.c')
| -rw-r--r-- | fs/ext4/super.c | 102 | 
1 files changed, 62 insertions, 40 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 40131b777af6..61182fe6254e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -828,12 +828,22 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)  	ei->cur_aio_dio = NULL;  	ei->i_sync_tid = 0;  	ei->i_datasync_tid = 0; +	atomic_set(&ei->i_ioend_count, 0);  	return &ei->vfs_inode;  } +static int ext4_drop_inode(struct inode *inode) +{ +	int drop = generic_drop_inode(inode); + +	trace_ext4_drop_inode(inode, drop); +	return drop; +} +  static void ext4_destroy_inode(struct inode *inode)  { +	ext4_ioend_wait(inode);  	if (!list_empty(&(EXT4_I(inode)->i_orphan))) {  		ext4_msg(inode->i_sb, KERN_ERR,  			 "Inode %lu (%p): orphan list check failed!", @@ -1173,6 +1183,7 @@ static const struct super_operations ext4_sops = {  	.destroy_inode	= ext4_destroy_inode,  	.write_inode	= ext4_write_inode,  	.dirty_inode	= ext4_dirty_inode, +	.drop_inode	= ext4_drop_inode,  	.evict_inode	= ext4_evict_inode,  	.put_super	= ext4_put_super,  	.sync_fs	= ext4_sync_fs, @@ -1194,6 +1205,7 @@ static const struct super_operations ext4_nojournal_sops = {  	.destroy_inode	= ext4_destroy_inode,  	.write_inode	= ext4_write_inode,  	.dirty_inode	= ext4_dirty_inode, +	.drop_inode	= ext4_drop_inode,  	.evict_inode	= ext4_evict_inode,  	.write_super	= ext4_write_super,  	.put_super	= ext4_put_super, @@ -2699,7 +2711,6 @@ static int ext4_lazyinit_thread(void *arg)  	struct ext4_li_request *elr;  	unsigned long next_wakeup;  	DEFINE_WAIT(wait); -	int ret;  	BUG_ON(NULL == eli); @@ -2723,13 +2734,12 @@ cont_thread:  			elr = list_entry(pos, struct ext4_li_request,  					 lr_request); -			if (time_after_eq(jiffies, elr->lr_next_sched)) -				ret = ext4_run_li_request(elr); - -			if (ret) { -				ret = 0; -				ext4_remove_li_request(elr); -				continue; +			if (time_after_eq(jiffies, elr->lr_next_sched)) { +				if (ext4_run_li_request(elr) != 0) { +					/* error, remove the lazy_init job */ +					ext4_remove_li_request(elr); +					continue; +				}  			}  			if (time_before(elr->lr_next_sched, next_wakeup)) @@ -2740,7 +2750,8 @@ cont_thread:  		if (freezing(current))  			refrigerator(); -		if (time_after_eq(jiffies, next_wakeup)) { +		if ((time_after_eq(jiffies, next_wakeup)) || +		    (MAX_JIFFY_OFFSET == next_wakeup)) {  			cond_resched();  			continue;  		} @@ -3348,6 +3359,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	get_random_bytes(&sbi->s_next_generation, sizeof(u32));  	spin_lock_init(&sbi->s_next_gen_lock); +	err = percpu_counter_init(&sbi->s_freeblocks_counter, +			ext4_count_free_blocks(sb)); +	if (!err) { +		err = percpu_counter_init(&sbi->s_freeinodes_counter, +				ext4_count_free_inodes(sb)); +	} +	if (!err) { +		err = percpu_counter_init(&sbi->s_dirs_counter, +				ext4_count_dirs(sb)); +	} +	if (!err) { +		err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0); +	} +	if (err) { +		ext4_msg(sb, KERN_ERR, "insufficient memory"); +		goto failed_mount3; +	} +  	sbi->s_stripe = ext4_get_stripe_size(sbi);  	sbi->s_max_writeback_mb_bump = 128; @@ -3446,22 +3475,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	}  	set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); -no_journal: -	err = percpu_counter_init(&sbi->s_freeblocks_counter, -				  ext4_count_free_blocks(sb)); -	if (!err) -		err = percpu_counter_init(&sbi->s_freeinodes_counter, -					  ext4_count_free_inodes(sb)); -	if (!err) -		err = percpu_counter_init(&sbi->s_dirs_counter, -					  ext4_count_dirs(sb)); -	if (!err) -		err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0); -	if (err) { -		ext4_msg(sb, KERN_ERR, "insufficient memory"); -		goto failed_mount_wq; -	} +	/* +	 * The journal may have updated the bg summary counts, so we +	 * need to update the global counters. +	 */ +	percpu_counter_set(&sbi->s_freeblocks_counter, +			   ext4_count_free_blocks(sb)); +	percpu_counter_set(&sbi->s_freeinodes_counter, +			   ext4_count_free_inodes(sb)); +	percpu_counter_set(&sbi->s_dirs_counter, +			   ext4_count_dirs(sb)); +	percpu_counter_set(&sbi->s_dirtyblocks_counter, 0); +no_journal:  	EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");  	if (!EXT4_SB(sb)->dio_unwritten_wq) {  		printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n"); @@ -3611,10 +3637,6 @@ failed_mount_wq:  		jbd2_journal_destroy(sbi->s_journal);  		sbi->s_journal = NULL;  	} -	percpu_counter_destroy(&sbi->s_freeblocks_counter); -	percpu_counter_destroy(&sbi->s_freeinodes_counter); -	percpu_counter_destroy(&sbi->s_dirs_counter); -	percpu_counter_destroy(&sbi->s_dirtyblocks_counter);  failed_mount3:  	if (sbi->s_flex_groups) {  		if (is_vmalloc_addr(sbi->s_flex_groups)) @@ -3622,6 +3644,10 @@ failed_mount3:  		else  			kfree(sbi->s_flex_groups);  	} +	percpu_counter_destroy(&sbi->s_freeblocks_counter); +	percpu_counter_destroy(&sbi->s_freeinodes_counter); +	percpu_counter_destroy(&sbi->s_dirs_counter); +	percpu_counter_destroy(&sbi->s_dirtyblocks_counter);  failed_mount2:  	for (i = 0; i < db_count; i++)  		brelse(sbi->s_group_desc[i]); @@ -3949,13 +3975,11 @@ static int ext4_commit_super(struct super_block *sb, int sync)  	else  		es->s_kbytes_written =  			cpu_to_le64(EXT4_SB(sb)->s_kbytes_written); -	if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter)) -		ext4_free_blocks_count_set(es, percpu_counter_sum_positive( -					&EXT4_SB(sb)->s_freeblocks_counter)); -	if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter)) -		es->s_free_inodes_count = -			cpu_to_le32(percpu_counter_sum_positive( -					&EXT4_SB(sb)->s_freeinodes_counter)); +	ext4_free_blocks_count_set(es, percpu_counter_sum_positive( +					   &EXT4_SB(sb)->s_freeblocks_counter)); +	es->s_free_inodes_count = +		cpu_to_le32(percpu_counter_sum_positive( +				&EXT4_SB(sb)->s_freeinodes_counter));  	sb->s_dirt = 0;  	BUFFER_TRACE(sbh, "marking dirty");  	mark_buffer_dirty(sbh); @@ -4556,12 +4580,10 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,  static int ext4_quota_off(struct super_block *sb, int type)  { -	/* Force all delayed allocation blocks to be allocated */ -	if (test_opt(sb, DELALLOC)) { -		down_read(&sb->s_umount); +	/* Force all delayed allocation blocks to be allocated. +	 * Caller already holds s_umount sem */ +	if (test_opt(sb, DELALLOC))  		sync_filesystem(sb); -		up_read(&sb->s_umount); -	}  	return dquot_quota_off(sb, type);  }  |