btrfs: merge btrfs_submit_bio_done to its caller
[sfrench/cifs-2.6.git] / fs / btrfs / inode.c
index 9ea4c6f0352f06e828a400890c50122c7ec33ee5..a88122b89f50d3198200eda3b5bde6235261f742 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uio.h>
 #include <linux/magic.h>
 #include <linux/iversion.h>
+#include <linux/swap.h>
 #include <asm/unaligned.h>
 #include "ctree.h"
 #include "disk-io.h"
@@ -109,8 +110,8 @@ static void __endio_write_update_ordered(struct inode *inode,
  * extent_clear_unlock_delalloc() to clear both the bits EXTENT_DO_ACCOUNTING
  * and EXTENT_DELALLOC simultaneously, because that causes the reserved metadata
  * to be released, which we want to happen only when finishing the ordered
- * extent (btrfs_finish_ordered_io()). Also note that the caller of the
- * fill_delalloc() callback already does proper cleanup for the first page of
+ * extent (btrfs_finish_ordered_io()). Also note that the caller of
+ * btrfs_run_delalloc_range already does proper cleanup for the first page of
  * the range, that is, it invokes the callback writepage_end_io_hook() for the
  * range of the first page.
  */
@@ -847,14 +848,13 @@ retry:
                                    ins.offset, async_extent->pages,
                                    async_extent->nr_pages,
                                    async_cow->write_flags)) {
-                       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
                        struct page *p = async_extent->pages[0];
                        const u64 start = async_extent->start;
                        const u64 end = start + async_extent->ram_size - 1;
 
                        p->mapping = inode->i_mapping;
-                       tree->ops->writepage_end_io_hook(p, start, end,
-                                                        NULL, 0);
+                       btrfs_writepage_endio_finish_ordered(p, start, end, 0);
+
                        p->mapping = NULL;
                        extent_clear_unlock_delalloc(inode, start, end, end,
                                                     NULL, 0,
@@ -1576,12 +1576,12 @@ static inline int need_force_cow(struct inode *inode, u64 start, u64 end)
 }
 
 /*
- * extent_io.c call back to do delayed allocation processing
+ * Function to process delayed allocation (create CoW) for ranges which are
+ * being touched for the first time.
  */
-static int run_delalloc_range(void *private_data, struct page *locked_page,
-                             u64 start, u64 end, int *page_started,
-                             unsigned long *nr_written,
-                             struct writeback_control *wbc)
+int btrfs_run_delalloc_range(void *private_data, struct page *locked_page,
+               u64 start, u64 end, int *page_started, unsigned long *nr_written,
+               struct writeback_control *wbc)
 {
        struct inode *inode = private_data;
        int ret;
@@ -1609,10 +1609,9 @@ static int run_delalloc_range(void *private_data, struct page *locked_page,
        return ret;
 }
 
-static void btrfs_split_extent_hook(void *private_data,
-                                   struct extent_state *orig, u64 split)
+void btrfs_split_delalloc_extent(struct inode *inode,
+                                struct extent_state *orig, u64 split)
 {
-       struct inode *inode = private_data;
        u64 size;
 
        /* not delalloc, ignore it */
@@ -1625,7 +1624,7 @@ static void btrfs_split_extent_hook(void *private_data,
                u64 new_size;
 
                /*
-                * See the explanation in btrfs_merge_extent_hook, the same
+                * See the explanation in btrfs_merge_delalloc_extent, the same
                 * applies here, just in reverse.
                 */
                new_size = orig->end - split + 1;
@@ -1642,16 +1641,13 @@ static void btrfs_split_extent_hook(void *private_data,
 }
 
 /*
- * extent_io.c merge_extent_hook, used to track merged delayed allocation
- * extents so we can keep track of new extents that are just merged onto old
- * extents, such as when we are doing sequential writes, so we can properly
- * account for the metadata space we'll need.
+ * Handle merged delayed allocation extents so we can keep track of new extents
+ * that are just merged onto old extents, such as when we are doing sequential
+ * writes, so we can properly account for the metadata space we'll need.
  */
-static void btrfs_merge_extent_hook(void *private_data,
-                                   struct extent_state *new,
-                                   struct extent_state *other)
+void btrfs_merge_delalloc_extent(struct inode *inode, struct extent_state *new,
+                                struct extent_state *other)
 {
-       struct inode *inode = private_data;
        u64 new_size, old_size;
        u32 num_extents;
 
@@ -1755,15 +1751,12 @@ static void btrfs_del_delalloc_inode(struct btrfs_root *root,
 }
 
 /*
- * extent_io.c set_bit_hook, used to track delayed allocation
- * bytes in this file, and to maintain the list of inodes that
- * have pending delalloc work to be done.
+ * Properly track delayed allocation bytes in the inode and to maintain the
+ * list of inodes that have pending delalloc work to be done.
  */
-static void btrfs_set_bit_hook(void *private_data,
-                              struct extent_state *state, unsigned *bits)
+void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
+                              unsigned *bits)
 {
-       struct inode *inode = private_data;
-
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 
        if ((*bits & EXTENT_DEFRAG) && !(*bits & EXTENT_DELALLOC))
@@ -1809,14 +1802,14 @@ static void btrfs_set_bit_hook(void *private_data,
 }
 
 /*
- * extent_io.c clear_bit_hook, see set_bit_hook for why
+ * Once a range is no longer delalloc this function ensures that proper
+ * accounting happens.
  */
-static void btrfs_clear_bit_hook(void *private_data,
-                                struct extent_state *state,
-                                unsigned *bits)
+void btrfs_clear_delalloc_extent(struct inode *vfs_inode,
+                                struct extent_state *state, unsigned *bits)
 {
-       struct btrfs_inode *inode = BTRFS_I((struct inode *)private_data);
-       struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
+       struct btrfs_inode *inode = BTRFS_I(vfs_inode);
+       struct btrfs_fs_info *fs_info = btrfs_sb(vfs_inode->i_sb);
        u64 len = state->end + 1 - state->start;
        u32 num_extents = count_max_extents(len);
 
@@ -1931,29 +1924,6 @@ static blk_status_t btrfs_submit_bio_start(void *private_data, struct bio *bio,
        return 0;
 }
 
-/*
- * in order to insert checksums into the metadata in large chunks,
- * we wait until bio submission time.   All the pages in the bio are
- * checksummed and sums are attached onto the ordered extent record.
- *
- * At IO completion time the cums attached on the ordered extent record
- * are inserted into the btree
- */
-blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio,
-                         int mirror_num)
-{
-       struct inode *inode = private_data;
-       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       blk_status_t ret;
-
-       ret = btrfs_map_bio(fs_info, bio, mirror_num, 1);
-       if (ret) {
-               bio->bi_status = ret;
-               bio_endio(bio);
-       }
-       return ret;
-}
-
 /*
  * extent_io.c submission hook. This does the right thing for csum calculation
  * on write, or reading the csums from the tree before a read.
@@ -2152,7 +2122,7 @@ out_page:
  * to fix it up.  The async helper will wait for ordered extents, set
  * the delalloc bit and make it safe to write the page.
  */
-static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
+int btrfs_writepage_cow_fixup(struct page *page, u64 start, u64 end)
 {
        struct inode *inode = page->mapping->host;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -3159,8 +3129,8 @@ static void finish_ordered_fn(struct btrfs_work *work)
        btrfs_finish_ordered_io(ordered_extent);
 }
 
-static void btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
-                               struct extent_state *state, int uptodate)
+void btrfs_writepage_endio_finish_ordered(struct page *page, u64 start,
+                                         u64 end, int uptodate)
 {
        struct inode *inode = page->mapping->host;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -6652,7 +6622,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        int err = 0;
-       int drop_on_err = 0;
        u64 objectid = 0;
        u64 index = 0;
 
@@ -6678,7 +6647,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                goto out_fail;
        }
 
-       drop_on_err = 1;
        /* these must be set before we unlock the inode */
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
@@ -6699,7 +6667,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                goto out_fail;
 
        d_instantiate_new(dentry, inode);
-       drop_on_err = 0;
 
 out_fail:
        btrfs_end_transaction(trans);
@@ -9968,7 +9935,7 @@ static struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode
  * some fairly slow code that needs optimization. This walks the list
  * of all the inodes with pending delalloc and forces them to disk.
  */
-static int start_delalloc_inodes(struct btrfs_root *root, int nr)
+static int start_delalloc_inodes(struct btrfs_root *root, int nr, bool snapshot)
 {
        struct btrfs_inode *binode;
        struct inode *inode;
@@ -9996,6 +9963,9 @@ static int start_delalloc_inodes(struct btrfs_root *root, int nr)
                }
                spin_unlock(&root->delalloc_lock);
 
+               if (snapshot)
+                       set_bit(BTRFS_INODE_SNAPSHOT_FLUSH,
+                               &binode->runtime_flags);
                work = btrfs_alloc_delalloc_work(inode);
                if (!work) {
                        iput(inode);
@@ -10029,7 +9999,7 @@ out:
        return ret;
 }
 
-int btrfs_start_delalloc_inodes(struct btrfs_root *root)
+int btrfs_start_delalloc_snapshot(struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
@@ -10037,7 +10007,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root)
        if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                return -EROFS;
 
-       ret = start_delalloc_inodes(root, -1);
+       ret = start_delalloc_inodes(root, -1, true);
        if (ret > 0)
                ret = 0;
        return ret;
@@ -10066,7 +10036,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int nr)
                               &fs_info->delalloc_roots);
                spin_unlock(&fs_info->delalloc_root_lock);
 
-               ret = start_delalloc_inodes(root, nr);
+               ret = start_delalloc_inodes(root, nr, false);
                btrfs_put_fs_root(root);
                if (ret < 0)
                        goto out;
@@ -10451,20 +10421,6 @@ static int btrfs_readpage_io_failed_hook(struct page *page, int failed_mirror)
        return -EAGAIN;
 }
 
-static void btrfs_check_extent_io_range(void *private_data, const char *caller,
-                                       u64 start, u64 end)
-{
-       struct inode *inode = private_data;
-       u64 isize;
-
-       isize = i_size_read(inode);
-       if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) {
-               btrfs_debug_rl(BTRFS_I(inode)->root->fs_info,
-                   "%s: ino %llu isize %llu odd range [%llu,%llu]",
-                       caller, btrfs_ino(BTRFS_I(inode)), isize, start, end);
-       }
-}
-
 void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
 {
        struct inode *inode = tree->private_data;
@@ -10481,6 +10437,343 @@ void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
        }
 }
 
+#ifdef CONFIG_SWAP
+/*
+ * Add an entry indicating a block group or device which is pinned by a
+ * swapfile. Returns 0 on success, 1 if there is already an entry for it, or a
+ * negative errno on failure.
+ */
+static int btrfs_add_swapfile_pin(struct inode *inode, void *ptr,
+                                 bool is_block_group)
+{
+       struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+       struct btrfs_swapfile_pin *sp, *entry;
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+
+       sp = kmalloc(sizeof(*sp), GFP_NOFS);
+       if (!sp)
+               return -ENOMEM;
+       sp->ptr = ptr;
+       sp->inode = inode;
+       sp->is_block_group = is_block_group;
+
+       spin_lock(&fs_info->swapfile_pins_lock);
+       p = &fs_info->swapfile_pins.rb_node;
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, struct btrfs_swapfile_pin, node);
+               if (sp->ptr < entry->ptr ||
+                   (sp->ptr == entry->ptr && sp->inode < entry->inode)) {
+                       p = &(*p)->rb_left;
+               } else if (sp->ptr > entry->ptr ||
+                          (sp->ptr == entry->ptr && sp->inode > entry->inode)) {
+                       p = &(*p)->rb_right;
+               } else {
+                       spin_unlock(&fs_info->swapfile_pins_lock);
+                       kfree(sp);
+                       return 1;
+               }
+       }
+       rb_link_node(&sp->node, parent, p);
+       rb_insert_color(&sp->node, &fs_info->swapfile_pins);
+       spin_unlock(&fs_info->swapfile_pins_lock);
+       return 0;
+}
+
+/* Free all of the entries pinned by this swapfile. */
+static void btrfs_free_swapfile_pins(struct inode *inode)
+{
+       struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+       struct btrfs_swapfile_pin *sp;
+       struct rb_node *node, *next;
+
+       spin_lock(&fs_info->swapfile_pins_lock);
+       node = rb_first(&fs_info->swapfile_pins);
+       while (node) {
+               next = rb_next(node);
+               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)
+                               btrfs_put_block_group(sp->ptr);
+                       kfree(sp);
+               }
+               node = next;
+       }
+       spin_unlock(&fs_info->swapfile_pins_lock);
+}
+
+struct btrfs_swap_info {
+       u64 start;
+       u64 block_start;
+       u64 block_len;
+       u64 lowest_ppage;
+       u64 highest_ppage;
+       unsigned long nr_pages;
+       int nr_extents;
+};
+
+static int btrfs_add_swap_extent(struct swap_info_struct *sis,
+                                struct btrfs_swap_info *bsi)
+{
+       unsigned long nr_pages;
+       u64 first_ppage, first_ppage_reported, next_ppage;
+       int ret;
+
+       first_ppage = ALIGN(bsi->block_start, PAGE_SIZE) >> PAGE_SHIFT;
+       next_ppage = ALIGN_DOWN(bsi->block_start + bsi->block_len,
+                               PAGE_SIZE) >> PAGE_SHIFT;
+
+       if (first_ppage >= next_ppage)
+               return 0;
+       nr_pages = next_ppage - first_ppage;
+
+       first_ppage_reported = first_ppage;
+       if (bsi->start == 0)
+               first_ppage_reported++;
+       if (bsi->lowest_ppage > first_ppage_reported)
+               bsi->lowest_ppage = first_ppage_reported;
+       if (bsi->highest_ppage < (next_ppage - 1))
+               bsi->highest_ppage = next_ppage - 1;
+
+       ret = add_swap_extent(sis, bsi->nr_pages, nr_pages, first_ppage);
+       if (ret < 0)
+               return ret;
+       bsi->nr_extents += ret;
+       bsi->nr_pages += nr_pages;
+       return 0;
+}
+
+static void btrfs_swap_deactivate(struct file *file)
+{
+       struct inode *inode = file_inode(file);
+
+       btrfs_free_swapfile_pins(inode);
+       atomic_dec(&BTRFS_I(inode)->root->nr_swapfiles);
+}
+
+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 extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct extent_state *cached_state = NULL;
+       struct extent_map *em = NULL;
+       struct btrfs_device *device = NULL;
+       struct btrfs_swap_info bsi = {
+               .lowest_ppage = (sector_t)-1ULL,
+       };
+       int ret = 0;
+       u64 isize;
+       u64 start;
+
+       /*
+        * If the swap file was just created, make sure delalloc is done. If the
+        * file changes again after this, the user is doing something stupid and
+        * we don't really care.
+        */
+       ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
+       if (ret)
+               return ret;
+
+       /*
+        * The inode is locked, so these flags won't change after we check them.
+        */
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS) {
+               btrfs_warn(fs_info, "swapfile must not be compressed");
+               return -EINVAL;
+       }
+       if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW)) {
+               btrfs_warn(fs_info, "swapfile must not be copy-on-write");
+               return -EINVAL;
+       }
+       if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
+               btrfs_warn(fs_info, "swapfile must not be checksummed");
+               return -EINVAL;
+       }
+
+       /*
+        * Balance or device remove/replace/resize can move stuff around from
+        * under us. The EXCL_OP flag makes sure they aren't running/won't run
+        * concurrently while we are mapping the swap extents, and
+        * fs_info->swapfile_pins prevents them from running while the swap file
+        * is active and moving the extents. Note that this also prevents a
+        * concurrent device add which isn't actually necessary, but it's not
+        * really worth the trouble to allow it.
+        */
+       if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) {
+               btrfs_warn(fs_info,
+          "cannot activate swapfile while exclusive operation is running");
+               return -EBUSY;
+       }
+       /*
+        * 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);
+
+       isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize);
+
+       lock_extent_bits(io_tree, 0, isize - 1, &cached_state);
+       start = 0;
+       while (start < isize) {
+               u64 logical_block_start, physical_block_start;
+               struct btrfs_block_group_cache *bg;
+               u64 len = isize - start;
+
+               em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len, 0);
+               if (IS_ERR(em)) {
+                       ret = PTR_ERR(em);
+                       goto out;
+               }
+
+               if (em->block_start == EXTENT_MAP_HOLE) {
+                       btrfs_warn(fs_info, "swapfile must not have holes");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (em->block_start == EXTENT_MAP_INLINE) {
+                       /*
+                        * It's unlikely we'll ever actually find ourselves
+                        * here, as a file small enough to fit inline won't be
+                        * big enough to store more than the swap header, but in
+                        * case something changes in the future, let's catch it
+                        * here rather than later.
+                        */
+                       btrfs_warn(fs_info, "swapfile must not be inline");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
+                       btrfs_warn(fs_info, "swapfile must not be compressed");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               logical_block_start = em->block_start + (start - em->start);
+               len = min(len, em->len - (start - em->start));
+               free_extent_map(em);
+               em = NULL;
+
+               ret = can_nocow_extent(inode, start, &len, NULL, NULL, NULL);
+               if (ret < 0) {
+                       goto out;
+               } else if (ret) {
+                       ret = 0;
+               } else {
+                       btrfs_warn(fs_info,
+                                  "swapfile must not be copy-on-write");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               em = btrfs_get_chunk_map(fs_info, logical_block_start, len);
+               if (IS_ERR(em)) {
+                       ret = PTR_ERR(em);
+                       goto out;
+               }
+
+               if (em->map_lookup->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
+                       btrfs_warn(fs_info,
+                                  "swapfile must have single data profile");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (device == NULL) {
+                       device = em->map_lookup->stripes[0].dev;
+                       ret = btrfs_add_swapfile_pin(inode, device, false);
+                       if (ret == 1)
+                               ret = 0;
+                       else if (ret)
+                               goto out;
+               } else if (device != em->map_lookup->stripes[0].dev) {
+                       btrfs_warn(fs_info, "swapfile must be on one device");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               physical_block_start = (em->map_lookup->stripes[0].physical +
+                                       (logical_block_start - em->start));
+               len = min(len, em->len - (logical_block_start - em->start));
+               free_extent_map(em);
+               em = NULL;
+
+               bg = btrfs_lookup_block_group(fs_info, logical_block_start);
+               if (!bg) {
+                       btrfs_warn(fs_info,
+                          "could not find block group containing swapfile");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = btrfs_add_swapfile_pin(inode, bg, true);
+               if (ret) {
+                       btrfs_put_block_group(bg);
+                       if (ret == 1)
+                               ret = 0;
+                       else
+                               goto out;
+               }
+
+               if (bsi.block_len &&
+                   bsi.block_start + bsi.block_len == physical_block_start) {
+                       bsi.block_len += len;
+               } else {
+                       if (bsi.block_len) {
+                               ret = btrfs_add_swap_extent(sis, &bsi);
+                               if (ret)
+                                       goto out;
+                       }
+                       bsi.start = start;
+                       bsi.block_start = physical_block_start;
+                       bsi.block_len = len;
+               }
+
+               start += len;
+       }
+
+       if (bsi.block_len)
+               ret = btrfs_add_swap_extent(sis, &bsi);
+
+out:
+       if (!IS_ERR_OR_NULL(em))
+               free_extent_map(em);
+
+       unlock_extent_cached(io_tree, 0, isize - 1, &cached_state);
+
+       if (ret)
+               btrfs_swap_deactivate(file);
+
+       clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags);
+
+       if (ret)
+               return ret;
+
+       if (device)
+               sis->bdev = device->bdev;
+       *span = bsi.highest_ppage - bsi.lowest_ppage + 1;
+       sis->max = bsi.nr_pages;
+       sis->pages = bsi.nr_pages - 1;
+       sis->highest_bit = bsi.nr_pages - 1;
+       return bsi.nr_extents;
+}
+#else
+static void btrfs_swap_deactivate(struct file *file)
+{
+}
+
+static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
+                              sector_t *span)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
 static const struct inode_operations btrfs_dir_inode_operations = {
        .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
@@ -10524,16 +10817,6 @@ static const struct extent_io_ops btrfs_extent_io_ops = {
        .submit_bio_hook = btrfs_submit_bio_hook,
        .readpage_end_io_hook = btrfs_readpage_end_io_hook,
        .readpage_io_failed_hook = btrfs_readpage_io_failed_hook,
-
-       /* optional callbacks */
-       .fill_delalloc = run_delalloc_range,
-       .writepage_end_io_hook = btrfs_writepage_end_io_hook,
-       .writepage_start_hook = btrfs_writepage_start_hook,
-       .set_bit_hook = btrfs_set_bit_hook,
-       .clear_bit_hook = btrfs_clear_bit_hook,
-       .merge_extent_hook = btrfs_merge_extent_hook,
-       .split_extent_hook = btrfs_split_extent_hook,
-       .check_extent_io_range = btrfs_check_extent_io_range,
 };
 
 /*
@@ -10558,6 +10841,8 @@ static const struct address_space_operations btrfs_aops = {
        .releasepage    = btrfs_releasepage,
        .set_page_dirty = btrfs_set_page_dirty,
        .error_remove_page = generic_error_remove_page,
+       .swap_activate  = btrfs_swap_activate,
+       .swap_deactivate = btrfs_swap_deactivate,
 };
 
 static const struct inode_operations btrfs_file_inode_operations = {