Merge tag 'for-5.12-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / fs / btrfs / inode.c
index 2e1c282..35bfa05 100644 (file)
@@ -1674,9 +1674,6 @@ next_slot:
                         */
                        btrfs_release_path(path);
 
-                       /* If extent is RO, we must COW it */
-                       if (btrfs_extent_readonly(fs_info, disk_bytenr))
-                               goto out_check;
                        ret = btrfs_cross_ref_exist(root, ino,
                                                    found_key.offset -
                                                    extent_offset, disk_bytenr, false);
@@ -1723,6 +1720,7 @@ next_slot:
                                WARN_ON_ONCE(freespace_inode);
                                goto out_check;
                        }
+                       /* If the extent's block group is RO, we must COW */
                        if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))
                                goto out_check;
                        nocow = true;
@@ -6085,7 +6083,7 @@ static int btrfs_dirty_inode(struct inode *inode)
                return PTR_ERR(trans);
 
        ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
-       if (ret && ret == -ENOSPC) {
+       if (ret && (ret == -ENOSPC || ret == -EDQUOT)) {
                /* whoops, lets try again with the full transaction */
                btrfs_end_transaction(trans);
                trans = btrfs_start_transaction(root, 1);
@@ -10200,6 +10198,7 @@ static int btrfs_add_swapfile_pin(struct inode *inode, void *ptr,
        sp->ptr = ptr;
        sp->inode = inode;
        sp->is_block_group = is_block_group;
+       sp->bg_extent_count = 1;
 
        spin_lock(&fs_info->swapfile_pins_lock);
        p = &fs_info->swapfile_pins.rb_node;
@@ -10213,6 +10212,8 @@ static int btrfs_add_swapfile_pin(struct inode *inode, void *ptr,
                           (sp->ptr == entry->ptr && sp->inode > entry->inode)) {
                        p = &(*p)->rb_right;
                } else {
+                       if (is_block_group)
+                               entry->bg_extent_count++;
                        spin_unlock(&fs_info->swapfile_pins_lock);
                        kfree(sp);
                        return 1;
@@ -10238,8 +10239,11 @@ static void btrfs_free_swapfile_pins(struct inode *inode)
                sp = rb_entry(node, struct btrfs_swapfile_pin, node);
                if (sp->inode == inode) {
                        rb_erase(&sp->node, &fs_info->swapfile_pins);
-                       if (sp->is_block_group)
+                       if (sp->is_block_group) {
+                               btrfs_dec_block_group_swap_extents(sp->ptr,
+                                                          sp->bg_extent_count);
                                btrfs_put_block_group(sp->ptr);
+                       }
                        kfree(sp);
                }
                node = next;
@@ -10300,7 +10304,8 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
                               sector_t *span)
 {
        struct inode *inode = file_inode(file);
-       struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_state *cached_state = NULL;
        struct extent_map *em = NULL;
@@ -10351,13 +10356,27 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
           "cannot activate swapfile while exclusive operation is running");
                return -EBUSY;
        }
+
+       /*
+        * Prevent snapshot creation while we are activating the swap file.
+        * We do not want to race with snapshot creation. If snapshot creation
+        * already started before we bumped nr_swapfiles from 0 to 1 and
+        * completes before the first write into the swap file after it is
+        * activated, than that write would fallback to COW.
+        */
+       if (!btrfs_drew_try_write_lock(&root->snapshot_lock)) {
+               btrfs_exclop_finish(fs_info);
+               btrfs_warn(fs_info,
+          "cannot activate swapfile because snapshot creation is in progress");
+               return -EINVAL;
+       }
        /*
         * Snapshots can create extents which require COW even if NODATACOW is
         * set. We use this counter to prevent snapshots. We must increment it
         * before walking the extents because we don't want a concurrent
         * snapshot to run after we've already checked the extents.
         */
-       atomic_inc(&BTRFS_I(inode)->root->nr_swapfiles);
+       atomic_inc(&root->nr_swapfiles);
 
        isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize);
 
@@ -10454,6 +10473,17 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
                        goto out;
                }
 
+               if (!btrfs_inc_block_group_swap_extents(bg)) {
+                       btrfs_warn(fs_info,
+                          "block group for swapfile at %llu is read-only%s",
+                          bg->start,
+                          atomic_read(&fs_info->scrubs_running) ?
+                                      " (scrub running)" : "");
+                       btrfs_put_block_group(bg);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                ret = btrfs_add_swapfile_pin(inode, bg, true);
                if (ret) {
                        btrfs_put_block_group(bg);
@@ -10492,6 +10522,8 @@ out:
        if (ret)
                btrfs_swap_deactivate(file);
 
+       btrfs_drew_write_unlock(&root->snapshot_lock);
+
        btrfs_exclop_finish(fs_info);
 
        if (ret)