diff options
Diffstat (limited to 'fs/btrfs/super.c')
| -rw-r--r-- | fs/btrfs/super.c | 94 | 
1 files changed, 62 insertions, 32 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 54bd91ece35b..60f7cbe815e9 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -262,7 +262,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,  	trans->aborted = errno;  	/* Nothing used. The other threads that have joined this  	 * transaction may be able to continue. */ -	if (!trans->blocks_used) { +	if (!trans->blocks_used && list_empty(&trans->new_bgs)) {  		const char *errstr;  		errstr = btrfs_decode_error(errno); @@ -642,11 +642,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)  					     "disabling disk space caching");  			break;  		case Opt_inode_cache: -			btrfs_set_and_info(root, CHANGE_INODE_CACHE, +			btrfs_set_pending_and_info(info, INODE_MAP_CACHE,  					   "enabling inode map caching");  			break;  		case Opt_noinode_cache: -			btrfs_clear_and_info(root, CHANGE_INODE_CACHE, +			btrfs_clear_pending_and_info(info, INODE_MAP_CACHE,  					     "disabling inode map caching");  			break;  		case Opt_clear_cache: @@ -993,9 +993,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait)  	trans = btrfs_attach_transaction_barrier(root);  	if (IS_ERR(trans)) {  		/* no transaction, don't bother */ -		if (PTR_ERR(trans) == -ENOENT) -			return 0; -		return PTR_ERR(trans); +		if (PTR_ERR(trans) == -ENOENT) { +			/* +			 * Exit unless we have some pending changes +			 * that need to go through commit +			 */ +			if (fs_info->pending_changes == 0) +				return 0; +			trans = btrfs_start_transaction(root, 0); +		} else { +			return PTR_ERR(trans); +		}  	}  	return btrfs_commit_transaction(trans, root);  } @@ -1644,8 +1652,20 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  	int i = 0, nr_devices;  	int ret; +	/* +	 * We aren't under the device list lock, so this is racey-ish, but good +	 * enough for our purposes. +	 */  	nr_devices = fs_info->fs_devices->open_devices; -	BUG_ON(!nr_devices); +	if (!nr_devices) { +		smp_mb(); +		nr_devices = fs_info->fs_devices->open_devices; +		ASSERT(nr_devices); +		if (!nr_devices) { +			*free_bytes = 0; +			return 0; +		} +	}  	devices_info = kmalloc_array(nr_devices, sizeof(*devices_info),  			       GFP_NOFS); @@ -1670,11 +1690,17 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  	else  		min_stripe_size = BTRFS_STRIPE_LEN; -	list_for_each_entry(device, &fs_devices->devices, dev_list) { +	if (fs_info->alloc_start) +		mutex_lock(&fs_devices->device_list_mutex); +	rcu_read_lock(); +	list_for_each_entry_rcu(device, &fs_devices->devices, dev_list) {  		if (!device->in_fs_metadata || !device->bdev ||  		    device->is_tgtdev_for_dev_replace)  			continue; +		if (i >= nr_devices) +			break; +  		avail_space = device->total_bytes - device->bytes_used;  		/* align with stripe_len */ @@ -1689,24 +1715,32 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  		skip_space = 1024 * 1024;  		/* user can set the offset in fs_info->alloc_start. */ -		if (fs_info->alloc_start + BTRFS_STRIPE_LEN <= -		    device->total_bytes) +		if (fs_info->alloc_start && +		    fs_info->alloc_start + BTRFS_STRIPE_LEN <= +		    device->total_bytes) { +			rcu_read_unlock();  			skip_space = max(fs_info->alloc_start, skip_space); -		/* -		 * btrfs can not use the free space in [0, skip_space - 1], -		 * we must subtract it from the total. In order to implement -		 * it, we account the used space in this range first. -		 */ -		ret = btrfs_account_dev_extents_size(device, 0, skip_space - 1, -						     &used_space); -		if (ret) { -			kfree(devices_info); -			return ret; -		} +			/* +			 * btrfs can not use the free space in +			 * [0, skip_space - 1], we must subtract it from the +			 * total. In order to implement it, we account the used +			 * space in this range first. +			 */ +			ret = btrfs_account_dev_extents_size(device, 0, +							     skip_space - 1, +							     &used_space); +			if (ret) { +				kfree(devices_info); +				mutex_unlock(&fs_devices->device_list_mutex); +				return ret; +			} -		/* calc the free space in [0, skip_space - 1] */ -		skip_space -= used_space; +			rcu_read_lock(); + +			/* calc the free space in [0, skip_space - 1] */ +			skip_space -= used_space; +		}  		/*  		 * we can use the free space in [0, skip_space - 1], subtract @@ -1725,6 +1759,9 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)  		i++;  	} +	rcu_read_unlock(); +	if (fs_info->alloc_start) +		mutex_unlock(&fs_devices->device_list_mutex);  	nr_devices = i; @@ -1787,8 +1824,6 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)  	 * holding chunk_muext to avoid allocating new chunks, holding  	 * device_list_mutex to avoid the device being removed  	 */ -	mutex_lock(&fs_info->fs_devices->device_list_mutex); -	mutex_lock(&fs_info->chunk_mutex);  	rcu_read_lock();  	list_for_each_entry_rcu(found, head, list) {  		if (found->flags & BTRFS_BLOCK_GROUP_DATA) { @@ -1824,17 +1859,12 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)  	buf->f_bfree -= block_rsv->size >> bits;  	spin_unlock(&block_rsv->lock); -	buf->f_bavail = total_free_data; +	buf->f_bavail = div_u64(total_free_data, factor);  	ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data); -	if (ret) { -		mutex_unlock(&fs_info->chunk_mutex); -		mutex_unlock(&fs_info->fs_devices->device_list_mutex); +	if (ret)  		return ret; -	}  	buf->f_bavail += div_u64(total_free_data, factor);  	buf->f_bavail = buf->f_bavail >> bits; -	mutex_unlock(&fs_info->chunk_mutex); -	mutex_unlock(&fs_info->fs_devices->device_list_mutex);  	buf->f_type = BTRFS_SUPER_MAGIC;  	buf->f_bsize = dentry->d_sb->s_blocksize;  |