btrfs: Don't call btrfs_start_transaction() on frozen fs to avoid deadlock.
[cascardo/linux.git] / fs / btrfs / super.c
index 54bd91e..6f49b28 100644 (file)
@@ -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,27 @@ 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;
+                       /*
+                        * A non-blocking test if the fs is frozen. We must not
+                        * start a new transaction here otherwise a deadlock
+                        * happens. The pending operations are delayed to the
+                        * next commit after thawing.
+                        */
+                       if (__sb_start_write(sb, SB_FREEZE_WRITE, false))
+                               __sb_end_write(sb, SB_FREEZE_WRITE);
+                       else
+                               return 0;
+                       trans = btrfs_start_transaction(root, 0);
+               }
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
        }
        return btrfs_commit_transaction(trans, root);
 }
@@ -1644,8 +1662,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 +1700,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 +1725,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 +1769,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 +1834,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 +1869,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;