Btrfs: fix unprotected device list access when getting the fs information
authorMiao Xie <miaox@cn.fujitsu.com>
Wed, 3 Sep 2014 13:35:40 +0000 (21:35 +0800)
committerChris Mason <clm@fb.com>
Wed, 17 Sep 2014 20:38:41 +0000 (13:38 -0700)
When we get the fs information, we forgot to acquire the mutex of device list,
it might cause the problem we might access a device that was removed. Fix
it by acquiring the device list mutex.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/super.c

index 3f1f4e2dc78f49d290d026cf15d3c27bd83732ca..2375f94fb7808b3d13822f3a44c856ec6b9b6efe 100644 (file)
@@ -1696,7 +1696,11 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        int ret;
 
-       /* holding chunk_muext to avoid allocating new chunks */
+       /*
+        * 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) {
@@ -1737,11 +1741,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        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);
                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;