btrfs: Remove delayed_iput parameter from btrfs_start_delalloc_inodes
[sfrench/cifs-2.6.git] / fs / btrfs / inode.c
index 0b86cf10cf2ac79732ea548bbe970819ea758d4e..c6ff72a1ff10e9044b50a4388e6b04db9831d371 100644 (file)
@@ -4245,7 +4245,7 @@ out:
        return ret;
 }
 
-int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
+static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct inode *dir, u64 objectid,
                        const char *name, int name_len)
@@ -4326,6 +4326,200 @@ out:
        return ret;
 }
 
+/*
+ * Helper to check if the subvolume references other subvolumes or if it's
+ * default.
+ */
+static noinline int may_destroy_subvol(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_path *path;
+       struct btrfs_dir_item *di;
+       struct btrfs_key key;
+       u64 dir_id;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /* Make sure this root isn't set as the default subvol */
+       dir_id = btrfs_super_root_dir(fs_info->super_copy);
+       di = btrfs_lookup_dir_item(NULL, fs_info->tree_root, path,
+                                  dir_id, "default", 7, 0);
+       if (di && !IS_ERR(di)) {
+               btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key);
+               if (key.objectid == root->root_key.objectid) {
+                       ret = -EPERM;
+                       btrfs_err(fs_info,
+                                 "deleting default subvolume %llu is not allowed",
+                                 key.objectid);
+                       goto out;
+               }
+               btrfs_release_path(path);
+       }
+
+       key.objectid = root->root_key.objectid;
+       key.type = BTRFS_ROOT_REF_KEY;
+       key.offset = (u64)-1;
+
+       ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+       BUG_ON(ret == 0);
+
+       ret = 0;
+       if (path->slots[0] > 0) {
+               path->slots[0]--;
+               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+               if (key.objectid == root->root_key.objectid &&
+                   key.type == BTRFS_ROOT_REF_KEY)
+                       ret = -ENOTEMPTY;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
+       struct btrfs_root *root = BTRFS_I(dir)->root;
+       struct inode *inode = d_inode(dentry);
+       struct btrfs_root *dest = BTRFS_I(inode)->root;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_block_rsv block_rsv;
+       u64 root_flags;
+       u64 qgroup_reserved;
+       int ret;
+       int err;
+
+       /*
+        * Don't allow to delete a subvolume with send in progress. This is
+        * inside the inode lock so the error handling that has to drop the bit
+        * again is not run concurrently.
+        */
+       spin_lock(&dest->root_item_lock);
+       root_flags = btrfs_root_flags(&dest->root_item);
+       if (dest->send_in_progress == 0) {
+               btrfs_set_root_flags(&dest->root_item,
+                               root_flags | BTRFS_ROOT_SUBVOL_DEAD);
+               spin_unlock(&dest->root_item_lock);
+       } else {
+               spin_unlock(&dest->root_item_lock);
+               btrfs_warn(fs_info,
+                          "attempt to delete subvolume %llu during send",
+                          dest->root_key.objectid);
+               return -EPERM;
+       }
+
+       down_write(&fs_info->subvol_sem);
+
+       err = may_destroy_subvol(dest);
+       if (err)
+               goto out_up_write;
+
+       btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
+       /*
+        * One for dir inode,
+        * two for dir entries,
+        * two for root ref/backref.
+        */
+       err = btrfs_subvolume_reserve_metadata(root, &block_rsv,
+                                              5, &qgroup_reserved, true);
+       if (err)
+               goto out_up_write;
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out_release;
+       }
+       trans->block_rsv = &block_rsv;
+       trans->bytes_reserved = block_rsv.size;
+
+       btrfs_record_snapshot_destroy(trans, BTRFS_I(dir));
+
+       ret = btrfs_unlink_subvol(trans, root, dir,
+                               dest->root_key.objectid,
+                               dentry->d_name.name,
+                               dentry->d_name.len);
+       if (ret) {
+               err = ret;
+               btrfs_abort_transaction(trans, ret);
+               goto out_end_trans;
+       }
+
+       btrfs_record_root_in_trans(trans, dest);
+
+       memset(&dest->root_item.drop_progress, 0,
+               sizeof(dest->root_item.drop_progress));
+       dest->root_item.drop_level = 0;
+       btrfs_set_root_refs(&dest->root_item, 0);
+
+       if (!test_and_set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &dest->state)) {
+               ret = btrfs_insert_orphan_item(trans,
+                                       fs_info->tree_root,
+                                       dest->root_key.objectid);
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
+                       err = ret;
+                       goto out_end_trans;
+               }
+       }
+
+       ret = btrfs_uuid_tree_rem(trans, fs_info, dest->root_item.uuid,
+                                 BTRFS_UUID_KEY_SUBVOL,
+                                 dest->root_key.objectid);
+       if (ret && ret != -ENOENT) {
+               btrfs_abort_transaction(trans, ret);
+               err = ret;
+               goto out_end_trans;
+       }
+       if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) {
+               ret = btrfs_uuid_tree_rem(trans, fs_info,
+                                         dest->root_item.received_uuid,
+                                         BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                         dest->root_key.objectid);
+               if (ret && ret != -ENOENT) {
+                       btrfs_abort_transaction(trans, ret);
+                       err = ret;
+                       goto out_end_trans;
+               }
+       }
+
+out_end_trans:
+       trans->block_rsv = NULL;
+       trans->bytes_reserved = 0;
+       ret = btrfs_end_transaction(trans);
+       if (ret && !err)
+               err = ret;
+       inode->i_flags |= S_DEAD;
+out_release:
+       btrfs_subvolume_release_metadata(fs_info, &block_rsv);
+out_up_write:
+       up_write(&fs_info->subvol_sem);
+       if (err) {
+               spin_lock(&dest->root_item_lock);
+               root_flags = btrfs_root_flags(&dest->root_item);
+               btrfs_set_root_flags(&dest->root_item,
+                               root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
+               spin_unlock(&dest->root_item_lock);
+       } else {
+               d_invalidate(dentry);
+               btrfs_invalidate_inodes(dest);
+               ASSERT(dest->send_in_progress == 0);
+
+               /* the last ref */
+               if (dest->ino_cache_inode) {
+                       iput(dest->ino_cache_inode);
+                       dest->ino_cache_inode = NULL;
+               }
+       }
+
+       return err;
+}
+
 static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = d_inode(dentry);
@@ -4337,7 +4531,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
        if (btrfs_ino(BTRFS_I(inode)) == BTRFS_FIRST_FREE_OBJECTID)
-               return -EPERM;
+               return btrfs_delete_subvolume(dir, dentry);
 
        trans = __unlink_start_trans(dir);
        if (IS_ERR(trans))
@@ -7083,7 +7277,7 @@ insert:
 
        err = 0;
        write_lock(&em_tree->lock);
-       err = btrfs_add_extent_mapping(em_tree, &em, start, len);
+       err = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len);
        write_unlock(&em_tree->lock);
 out:
 
@@ -8131,7 +8325,6 @@ static void __endio_write_update_ordered(struct inode *inode,
        u64 ordered_offset = offset;
        u64 ordered_bytes = bytes;
        u64 last_offset;
-       int ret;
 
        if (btrfs_is_free_space_inode(BTRFS_I(inode))) {
                wq = fs_info->endio_freespace_worker;
@@ -8141,32 +8334,31 @@ static void __endio_write_update_ordered(struct inode *inode,
                func = btrfs_endio_write_helper;
        }
 
-again:
-       last_offset = ordered_offset;
-       ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
-                                                  &ordered_offset,
-                                                  ordered_bytes,
-                                                  uptodate);
-       if (!ret)
-               goto out_test;
-
-       btrfs_init_work(&ordered->work, func, finish_ordered_fn, NULL, NULL);
-       btrfs_queue_work(wq, &ordered->work);
-out_test:
-       /*
-        * If btrfs_dec_test_ordered_pending does not find any ordered extent
-        * in the range, we can exit.
-        */
-       if (ordered_offset == last_offset)
-               return;
-       /*
-        * our bio might span multiple ordered extents.  If we haven't
-        * completed the accounting for the whole dio, go back and try again
-        */
-       if (ordered_offset < offset + bytes) {
-               ordered_bytes = offset + bytes - ordered_offset;
-               ordered = NULL;
-               goto again;
+       while (ordered_offset < offset + bytes) {
+               last_offset = ordered_offset;
+               if (btrfs_dec_test_first_ordered_pending(inode, &ordered,
+                                                          &ordered_offset,
+                                                          ordered_bytes,
+                                                          uptodate)) {
+                       btrfs_init_work(&ordered->work, func,
+                                       finish_ordered_fn,
+                                       NULL, NULL);
+                       btrfs_queue_work(wq, &ordered->work);
+               }
+               /*
+                * If btrfs_dec_test_ordered_pending does not find any ordered
+                * extent in the range, we can exit.
+                */
+               if (ordered_offset == last_offset)
+                       return;
+               /*
+                * Our bio might span multiple ordered extents. In this case
+                * we keep goin until we have accounted the whole dio.
+                */
+               if (ordered_offset < offset + bytes) {
+                       ordered_bytes = offset + bytes - ordered_offset;
+                       ordered = NULL;
+               }
        }
 }
 
@@ -8705,29 +8897,19 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
 static int btrfs_writepages(struct address_space *mapping,
                            struct writeback_control *wbc)
 {
-       struct extent_io_tree *tree;
-
-       tree = &BTRFS_I(mapping->host)->io_tree;
-       return extent_writepages(tree, mapping, wbc);
+       return extent_writepages(mapping, wbc);
 }
 
 static int
 btrfs_readpages(struct file *file, struct address_space *mapping,
                struct list_head *pages, unsigned nr_pages)
 {
-       struct extent_io_tree *tree;
-       tree = &BTRFS_I(mapping->host)->io_tree;
-       return extent_readpages(tree, mapping, pages, nr_pages);
+       return extent_readpages(mapping, pages, nr_pages);
 }
+
 static int __btrfs_releasepage(struct page *page, gfp_t gfp_flags)
 {
-       struct extent_io_tree *tree;
-       struct extent_map_tree *map;
-       int ret;
-
-       tree = &BTRFS_I(page->mapping->host)->io_tree;
-       map = &BTRFS_I(page->mapping->host)->extent_tree;
-       ret = try_release_extent_mapping(map, tree, page, gfp_flags);
+       int ret = try_release_extent_mapping(page, gfp_flags);
        if (ret == 1) {
                ClearPagePrivate(page);
                set_page_private(page, 0);
@@ -10004,12 +10186,6 @@ struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
        return work;
 }
 
-void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work)
-{
-       wait_for_completion(&work->completion);
-       kfree(work);
-}
-
 /*
  * some fairly slow code that needs optimization. This walks the list
  * of all the inodes with pending delalloc and forces them to disk.
@@ -10066,10 +10242,11 @@ static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput,
 out:
        list_for_each_entry_safe(work, next, &works, list) {
                list_del_init(&work->list);
-               btrfs_wait_and_free_delalloc_work(work);
+               wait_for_completion(&work->completion);
+               kfree(work);
        }
 
-       if (!list_empty_careful(&splice)) {
+       if (!list_empty(&splice)) {
                spin_lock(&root->delalloc_lock);
                list_splice_tail(&splice, &root->delalloc_inodes);
                spin_unlock(&root->delalloc_lock);
@@ -10078,7 +10255,7 @@ out:
        return ret;
 }
 
-int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
+int btrfs_start_delalloc_inodes(struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
@@ -10086,14 +10263,13 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                return -EROFS;
 
-       ret = __start_delalloc_inodes(root, delay_iput, -1);
+       ret = __start_delalloc_inodes(root, 0, -1);
        if (ret > 0)
                ret = 0;
        return ret;
 }
 
-int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
-                              int nr)
+int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int nr)
 {
        struct btrfs_root *root;
        struct list_head splice;
@@ -10116,7 +10292,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
                               &fs_info->delalloc_roots);
                spin_unlock(&fs_info->delalloc_root_lock);
 
-               ret = __start_delalloc_inodes(root, delay_iput, nr);
+               ret = __start_delalloc_inodes(root, 0, nr);
                btrfs_put_fs_root(root);
                if (ret < 0)
                        goto out;
@@ -10131,7 +10307,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
 
        ret = 0;
 out:
-       if (!list_empty_careful(&splice)) {
+       if (!list_empty(&splice)) {
                spin_lock(&fs_info->delalloc_root_lock);
                list_splice_tail(&splice, &fs_info->delalloc_roots);
                spin_unlock(&fs_info->delalloc_root_lock);