btrfs: put delayed item hook into inode
authorDavid Sterba <dsterba@suse.cz>
Thu, 19 Nov 2015 13:15:51 +0000 (14:15 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 7 Jan 2016 13:26:58 +0000 (14:26 +0100)
Inodes for delayed iput allocate a trivial helper structure, let's place
the list hook directly into the inode and save a kmalloc (killing a
__GFP_NOFAIL as a bonus) at the cost of increasing size of btrfs_inode.

The inode can be put into the delayed_iputs list more than once and we
have to keep the count. This means we can't use the list_splice to
process a bunch of inodes because we'd lost track of the count if the
inode is put into the delayed iputs again while it's processed.

Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/btrfs_inode.h
fs/btrfs/inode.c

index 0ef5cc1..61205e3 100644 (file)
@@ -192,6 +192,10 @@ struct btrfs_inode {
        /* File creation time. */
        struct timespec i_otime;
 
+       /* Hook into fs_info->delayed_iputs */
+       struct list_head delayed_iput;
+       long delayed_iput_count;
+
        struct inode vfs_inode;
 };
 
index e8d9f9c..255d0f9 100644 (file)
@@ -3106,55 +3106,47 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
                                      start, (size_t)(end - start + 1));
 }
 
-struct delayed_iput {
-       struct list_head list;
-       struct inode *inode;
-};
-
-/* JDM: If this is fs-wide, why can't we add a pointer to
- * btrfs_inode instead and avoid the allocation? */
 void btrfs_add_delayed_iput(struct inode *inode)
 {
        struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
-       struct delayed_iput *delayed;
+       struct btrfs_inode *binode = BTRFS_I(inode);
 
        if (atomic_add_unless(&inode->i_count, -1, 1))
                return;
 
-       delayed = kmalloc(sizeof(*delayed), GFP_NOFS | __GFP_NOFAIL);
-       delayed->inode = inode;
-
        spin_lock(&fs_info->delayed_iput_lock);
-       list_add_tail(&delayed->list, &fs_info->delayed_iputs);
+       if (binode->delayed_iput_count == 0) {
+               ASSERT(list_empty(&binode->delayed_iput));
+               list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
+       } else {
+               binode->delayed_iput_count++;
+       }
        spin_unlock(&fs_info->delayed_iput_lock);
 }
 
 void btrfs_run_delayed_iputs(struct btrfs_root *root)
 {
-       LIST_HEAD(list);
        struct btrfs_fs_info *fs_info = root->fs_info;
-       struct delayed_iput *delayed;
-       int empty;
-
-       spin_lock(&fs_info->delayed_iput_lock);
-       empty = list_empty(&fs_info->delayed_iputs);
-       spin_unlock(&fs_info->delayed_iput_lock);
-       if (empty)
-               return;
 
        down_read(&fs_info->delayed_iput_sem);
-
        spin_lock(&fs_info->delayed_iput_lock);
-       list_splice_init(&fs_info->delayed_iputs, &list);
-       spin_unlock(&fs_info->delayed_iput_lock);
-
-       while (!list_empty(&list)) {
-               delayed = list_entry(list.next, struct delayed_iput, list);
-               list_del(&delayed->list);
-               iput(delayed->inode);
-               kfree(delayed);
+       while (!list_empty(&fs_info->delayed_iputs)) {
+               struct btrfs_inode *inode;
+
+               inode = list_first_entry(&fs_info->delayed_iputs,
+                               struct btrfs_inode, delayed_iput);
+               if (inode->delayed_iput_count) {
+                       inode->delayed_iput_count--;
+                       list_move_tail(&inode->delayed_iput,
+                                       &fs_info->delayed_iputs);
+               } else {
+                       list_del_init(&inode->delayed_iput);
+               }
+               spin_unlock(&fs_info->delayed_iput_lock);
+               iput(&inode->vfs_inode);
+               spin_lock(&fs_info->delayed_iput_lock);
        }
-
+       spin_unlock(&fs_info->delayed_iput_lock);
        up_read(&root->fs_info->delayed_iput_sem);
 }
 
@@ -9037,6 +9029,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->dir_index = 0;
        ei->last_unlink_trans = 0;
        ei->last_log_commit = 0;
+       ei->delayed_iput_count = 0;
 
        spin_lock_init(&ei->lock);
        ei->outstanding_extents = 0;
@@ -9061,6 +9054,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        mutex_init(&ei->delalloc_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->delalloc_inodes);
+       INIT_LIST_HEAD(&ei->delayed_iput);
        RB_CLEAR_NODE(&ei->rb_node);
 
        return inode;