]> Git Repo - J-linux.git/commitdiff
Merge branch 'work.icache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <[email protected]>
Tue, 7 May 2019 17:57:05 +0000 (10:57 -0700)
committerLinus Torvalds <[email protected]>
Tue, 7 May 2019 17:57:05 +0000 (10:57 -0700)
Pull vfs inode freeing updates from Al Viro:
 "Introduction of separate method for RCU-delayed part of
  ->destroy_inode() (if any).

  Pretty much as posted, except that destroy_inode() stashes
  ->free_inode into the victim (anon-unioned with ->i_fops) before
  scheduling i_callback() and the last two patches (sockfs conversion
  and folding struct socket_wq into struct socket) are excluded - that
  pair should go through netdev once davem reopens his tree"

* 'work.icache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (58 commits)
  orangefs: make use of ->free_inode()
  shmem: make use of ->free_inode()
  hugetlb: make use of ->free_inode()
  overlayfs: make use of ->free_inode()
  jfs: switch to ->free_inode()
  fuse: switch to ->free_inode()
  ext4: make use of ->free_inode()
  ecryptfs: make use of ->free_inode()
  ceph: use ->free_inode()
  btrfs: use ->free_inode()
  afs: switch to use of ->free_inode()
  dax: make use of ->free_inode()
  ntfs: switch to ->free_inode()
  securityfs: switch to ->free_inode()
  apparmor: switch to ->free_inode()
  rpcpipe: switch to ->free_inode()
  bpf: switch to ->free_inode()
  mqueue: switch to ->free_inode()
  ufs: switch to ->free_inode()
  coda: switch to ->free_inode()
  ...

1  2 
fs/block_dev.c
fs/btrfs/inode.c
fs/ceph/inode.c
fs/inode.c
fs/nfs/super.c
mm/shmem.c

diff --combined fs/block_dev.c
index bb28e2ead679c10a21a3f12dff7bddefce990ee5,9d5fd05dd64321b15284bb132fc963ebe4c0de2a..9ee3117ee0bfa471e3aeafaca312ca4f3e0e5e0d
@@@ -264,8 -264,7 +264,8 @@@ __blkdev_direct_IO_simple(struct kiocb 
        bio_for_each_segment_all(bvec, &bio, i, iter_all) {
                if (should_dirty && !PageCompound(bvec->bv_page))
                        set_page_dirty_lock(bvec->bv_page);
 -              put_page(bvec->bv_page);
 +              if (!bio_flagged(&bio, BIO_NO_PAGE_REF))
 +                      put_page(bvec->bv_page);
        }
  
        if (unlikely(bio.bi_status))
@@@ -308,10 -307,10 +308,10 @@@ static void blkdev_bio_end_io(struct bi
        struct blkdev_dio *dio = bio->bi_private;
        bool should_dirty = dio->should_dirty;
  
 -      if (dio->multi_bio && !atomic_dec_and_test(&dio->ref)) {
 -              if (bio->bi_status && !dio->bio.bi_status)
 -                      dio->bio.bi_status = bio->bi_status;
 -      } else {
 +      if (bio->bi_status && !dio->bio.bi_status)
 +              dio->bio.bi_status = bio->bi_status;
 +
 +      if (!dio->multi_bio || atomic_dec_and_test(&dio->ref)) {
                if (!dio->is_sync) {
                        struct kiocb *iocb = dio->iocb;
                        ssize_t ret;
@@@ -790,17 -789,9 +790,9 @@@ static struct inode *bdev_alloc_inode(s
        return &ei->vfs_inode;
  }
  
- static void bdev_i_callback(struct rcu_head *head)
+ static void bdev_free_inode(struct inode *inode)
  {
-       struct inode *inode = container_of(head, struct inode, i_rcu);
-       struct bdev_inode *bdi = BDEV_I(inode);
-       kmem_cache_free(bdev_cachep, bdi);
- }
- static void bdev_destroy_inode(struct inode *inode)
- {
-       call_rcu(&inode->i_rcu, bdev_i_callback);
+       kmem_cache_free(bdev_cachep, BDEV_I(inode));
  }
  
  static void init_once(void *foo)
@@@ -840,7 -831,7 +832,7 @@@ static void bdev_evict_inode(struct ino
  static const struct super_operations bdev_sops = {
        .statfs = simple_statfs,
        .alloc_inode = bdev_alloc_inode,
-       .destroy_inode = bdev_destroy_inode,
+       .free_inode = bdev_free_inode,
        .drop_inode = generic_delete_inode,
        .evict_inode = bdev_evict_inode,
  };
diff --combined fs/btrfs/inode.c
index 2973608824ecacbfaad11a6f0d57460d113a5e47,aeb31c2dc14ef3a5a61ae5aff2eec57bba98bda6..ade7d0c5ce1b3338e5976768fe006bbab3b361e2
@@@ -6783,7 -6783,7 +6783,7 @@@ struct extent_map *btrfs_get_extent(str
        u64 extent_start = 0;
        u64 extent_end = 0;
        u64 objectid = btrfs_ino(inode);
 -      u8 extent_type;
 +      int extent_type = -1;
        struct btrfs_path *path = NULL;
        struct btrfs_root *root = inode->root;
        struct btrfs_file_extent_item *item;
@@@ -9206,9 -9206,8 +9206,8 @@@ void btrfs_test_destroy_inode(struct in
  }
  #endif
  
static void btrfs_i_callback(struct rcu_head *head)
void btrfs_free_inode(struct inode *inode)
  {
-       struct inode *inode = container_of(head, struct inode, i_rcu);
        kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
  }
  
@@@ -9234,7 -9233,7 +9233,7 @@@ void btrfs_destroy_inode(struct inode *
         * created.
         */
        if (!root)
-               goto free;
+               return;
  
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
        btrfs_qgroup_check_reserved_leak(inode);
        inode_tree_del(inode);
        btrfs_drop_extent_cache(BTRFS_I(inode), 0, (u64)-1, 0);
- free:
-       call_rcu(&inode->i_rcu, btrfs_i_callback);
  }
  
  int btrfs_drop_inode(struct inode *inode)
diff --combined fs/ceph/inode.c
index c2feb310ac1e0d7bd0c263f4d5944cc2c22852ac,dc0a36d0adf84c054f569ab2c97b1c673f24a307..35dae6d5493a8eb59e51c2a67f8171d444a44319
@@@ -519,9 -519,8 +519,8 @@@ struct inode *ceph_alloc_inode(struct s
        return &ci->vfs_inode;
  }
  
static void ceph_i_callback(struct rcu_head *head)
void ceph_free_inode(struct inode *inode)
  {
-       struct inode *inode = container_of(head, struct inode, i_rcu);
        struct ceph_inode_info *ci = ceph_inode(inode);
  
        kfree(ci->i_symlink);
@@@ -581,8 -580,6 +580,6 @@@ void ceph_destroy_inode(struct inode *i
                ceph_buffer_put(ci->i_xattrs.prealloc_blob);
  
        ceph_put_string(rcu_dereference_raw(ci->i_layout.pool_ns));
-       call_rcu(&inode->i_rcu, ceph_i_callback);
  }
  
  int ceph_drop_inode(struct inode *inode)
@@@ -1163,19 -1160,6 +1160,19 @@@ static int splice_dentry(struct dentry 
        return 0;
  }
  
 +static int d_name_cmp(struct dentry *dentry, const char *name, size_t len)
 +{
 +      int ret;
 +
 +      /* take d_lock to ensure dentry->d_name stability */
 +      spin_lock(&dentry->d_lock);
 +      ret = dentry->d_name.len - len;
 +      if (!ret)
 +              ret = memcmp(dentry->d_name.name, name, len);
 +      spin_unlock(&dentry->d_lock);
 +      return ret;
 +}
 +
  /*
   * Incorporate results into the local cache.  This is either just
   * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
@@@ -1425,8 -1409,7 +1422,8 @@@ retry_lookup
                err = splice_dentry(&req->r_dentry, in);
                if (err < 0)
                        goto done;
 -      } else if (rinfo->head->is_dentry) {
 +      } else if (rinfo->head->is_dentry &&
 +                 !d_name_cmp(req->r_dentry, rinfo->dname, rinfo->dname_len)) {
                struct ceph_vino *ptvino = NULL;
  
                if ((le32_to_cpu(rinfo->diri.in->cap.caps) & CEPH_CAP_FILE_SHARED) ||
diff --combined fs/inode.c
index 9a453f3637f85a377d72c94bd9e6f1e7dbbf2ad5,627e1766503aa9a392b34d14520f44497683e953..16b10e53292e38ff268f4563a857ebddd9e46550
@@@ -202,12 -202,28 +202,28 @@@ out
  }
  EXPORT_SYMBOL(inode_init_always);
  
+ void free_inode_nonrcu(struct inode *inode)
+ {
+       kmem_cache_free(inode_cachep, inode);
+ }
+ EXPORT_SYMBOL(free_inode_nonrcu);
+ static void i_callback(struct rcu_head *head)
+ {
+       struct inode *inode = container_of(head, struct inode, i_rcu);
+       if (inode->free_inode)
+               inode->free_inode(inode);
+       else
+               free_inode_nonrcu(inode);
+ }
  static struct inode *alloc_inode(struct super_block *sb)
  {
+       const struct super_operations *ops = sb->s_op;
        struct inode *inode;
  
-       if (sb->s_op->alloc_inode)
-               inode = sb->s_op->alloc_inode(sb);
+       if (ops->alloc_inode)
+               inode = ops->alloc_inode(sb);
        else
                inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
  
                return NULL;
  
        if (unlikely(inode_init_always(sb, inode))) {
-               if (inode->i_sb->s_op->destroy_inode)
-                       inode->i_sb->s_op->destroy_inode(inode);
-               else
-                       kmem_cache_free(inode_cachep, inode);
+               if (ops->destroy_inode) {
+                       ops->destroy_inode(inode);
+                       if (!ops->free_inode)
+                               return NULL;
+               }
+               inode->free_inode = ops->free_inode;
+               i_callback(&inode->i_rcu);
                return NULL;
        }
  
        return inode;
  }
  
- void free_inode_nonrcu(struct inode *inode)
- {
-       kmem_cache_free(inode_cachep, inode);
- }
- EXPORT_SYMBOL(free_inode_nonrcu);
  void __destroy_inode(struct inode *inode)
  {
        BUG_ON(inode_has_buffers(inode));
  }
  EXPORT_SYMBOL(__destroy_inode);
  
- static void i_callback(struct rcu_head *head)
- {
-       struct inode *inode = container_of(head, struct inode, i_rcu);
-       kmem_cache_free(inode_cachep, inode);
- }
  static void destroy_inode(struct inode *inode)
  {
+       const struct super_operations *ops = inode->i_sb->s_op;
        BUG_ON(!list_empty(&inode->i_lru));
        __destroy_inode(inode);
-       if (inode->i_sb->s_op->destroy_inode)
-               inode->i_sb->s_op->destroy_inode(inode);
-       else
-               call_rcu(&inode->i_rcu, i_callback);
+       if (ops->destroy_inode) {
+               ops->destroy_inode(inode);
+               if (!ops->free_inode)
+                       return;
+       }
+       inode->free_inode = ops->free_inode;
+       call_rcu(&inode->i_rcu, i_callback);
  }
  
  /**
@@@ -1817,13 -1829,8 +1829,13 @@@ int file_remove_privs(struct file *file
        int kill;
        int error = 0;
  
 -      /* Fast path for nothing security related */
 -      if (IS_NOSEC(inode))
 +      /*
 +       * Fast path for nothing security related.
 +       * As well for non-regular files, e.g. blkdev inodes.
 +       * For example, blkdev_write_iter() might get here
 +       * trying to remove privs which it is not allowed to.
 +       */
 +      if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
                return 0;
  
        kill = dentry_needs_remove_privs(dentry);
diff --combined fs/nfs/super.c
index c27ac96a95bd3535bc893493492fdc7681aba1fe,aec4e2c4b02fa1634ad806f224bf1cc3b2a00d7c..450ae77d19bff847364bf2c1634571309eadb48f
@@@ -309,7 -309,7 +309,7 @@@ struct file_system_type nfs_xdev_fs_typ
  
  const struct super_operations nfs_sops = {
        .alloc_inode    = nfs_alloc_inode,
-       .destroy_inode  = nfs_destroy_inode,
+       .free_inode     = nfs_free_inode,
        .write_inode    = nfs_write_inode,
        .drop_inode     = nfs_drop_inode,
        .statfs         = nfs_statfs,
@@@ -2041,8 -2041,7 +2041,8 @@@ static int nfs23_validate_mount_data(vo
                memcpy(sap, &data->addr, sizeof(data->addr));
                args->nfs_server.addrlen = sizeof(data->addr);
                args->nfs_server.port = ntohs(data->addr.sin_port);
 -              if (!nfs_verify_server_address(sap))
 +              if (sap->sa_family != AF_INET ||
 +                  !nfs_verify_server_address(sap))
                        goto out_no_address;
  
                if (!(data->flags & NFS_MOUNT_TCP))
diff --combined mm/shmem.c
index 2275a0ff7c3051d9674ee59b153451c6078741c3,dbb7a6dadba71b25ee14b505440e54c263481341..f4dce9c8670dc2fff58c8ea6e41445c5b7a4269a
@@@ -1081,14 -1081,9 +1081,14 @@@ static void shmem_evict_inode(struct in
                        }
                        spin_unlock(&sbinfo->shrinklist_lock);
                }
 -              if (!list_empty(&info->swaplist)) {
 +              while (!list_empty(&info->swaplist)) {
 +                      /* Wait while shmem_unuse() is scanning this inode... */
 +                      wait_var_event(&info->stop_eviction,
 +                                     !atomic_read(&info->stop_eviction));
                        mutex_lock(&shmem_swaplist_mutex);
 -                      list_del_init(&info->swaplist);
 +                      /* ...but beware of the race if we peeked too early */
 +                      if (!atomic_read(&info->stop_eviction))
 +                              list_del_init(&info->swaplist);
                        mutex_unlock(&shmem_swaplist_mutex);
                }
        }
@@@ -1104,11 -1099,10 +1104,11 @@@ extern struct swap_info_struct *swap_in
  static int shmem_find_swap_entries(struct address_space *mapping,
                                   pgoff_t start, unsigned int nr_entries,
                                   struct page **entries, pgoff_t *indices,
 -                                 bool frontswap)
 +                                 unsigned int type, bool frontswap)
  {
        XA_STATE(xas, &mapping->i_pages, start);
        struct page *page;
 +      swp_entry_t entry;
        unsigned int ret = 0;
  
        if (!nr_entries)
                if (!xa_is_value(page))
                        continue;
  
 -              if (frontswap) {
 -                      swp_entry_t entry = radix_to_swp_entry(page);
 -
 -                      if (!frontswap_test(swap_info[swp_type(entry)],
 -                                          swp_offset(entry)))
 -                              continue;
 -              }
 +              entry = radix_to_swp_entry(page);
 +              if (swp_type(entry) != type)
 +                      continue;
 +              if (frontswap &&
 +                  !frontswap_test(swap_info[type], swp_offset(entry)))
 +                      continue;
  
                indices[ret] = xas.xa_index;
                entries[ret] = page;
@@@ -1199,7 -1194,7 +1199,7 @@@ static int shmem_unuse_inode(struct ino
  
                pvec.nr = shmem_find_swap_entries(mapping, start, nr_entries,
                                                  pvec.pages, indices,
 -                                                frontswap);
 +                                                type, frontswap);
                if (pvec.nr == 0) {
                        ret = 0;
                        break;
@@@ -1232,27 -1227,36 +1232,27 @@@ int shmem_unuse(unsigned int type, boo
                unsigned long *fs_pages_to_unuse)
  {
        struct shmem_inode_info *info, *next;
 -      struct inode *inode;
 -      struct inode *prev_inode = NULL;
        int error = 0;
  
        if (list_empty(&shmem_swaplist))
                return 0;
  
        mutex_lock(&shmem_swaplist_mutex);
 -
 -      /*
 -       * The extra refcount on the inode is necessary to safely dereference
 -       * p->next after re-acquiring the lock. New shmem inodes with swap
 -       * get added to the end of the list and we will scan them all.
 -       */
        list_for_each_entry_safe(info, next, &shmem_swaplist, swaplist) {
                if (!info->swapped) {
                        list_del_init(&info->swaplist);
                        continue;
                }
 -
 -              inode = igrab(&info->vfs_inode);
 -              if (!inode)
 -                      continue;
 -
 +              /*
 +               * Drop the swaplist mutex while searching the inode for swap;
 +               * but before doing so, make sure shmem_evict_inode() will not
 +               * remove placeholder inode from swaplist, nor let it be freed
 +               * (igrab() would protect from unlink, but not from unmount).
 +               */
 +              atomic_inc(&info->stop_eviction);
                mutex_unlock(&shmem_swaplist_mutex);
 -              if (prev_inode)
 -                      iput(prev_inode);
 -              prev_inode = inode;
  
 -              error = shmem_unuse_inode(inode, type, frontswap,
 +              error = shmem_unuse_inode(&info->vfs_inode, type, frontswap,
                                          fs_pages_to_unuse);
                cond_resched();
  
                next = list_next_entry(info, swaplist);
                if (!info->swapped)
                        list_del_init(&info->swaplist);
 +              if (atomic_dec_and_test(&info->stop_eviction))
 +                      wake_up_var(&info->stop_eviction);
                if (error)
                        break;
        }
        mutex_unlock(&shmem_swaplist_mutex);
  
 -      if (prev_inode)
 -              iput(prev_inode);
 -
        return error;
  }
  
@@@ -2233,7 -2238,6 +2233,7 @@@ static struct inode *shmem_get_inode(st
                info = SHMEM_I(inode);
                memset(info, 0, (char *)inode - (char *)info);
                spin_lock_init(&info->lock);
 +              atomic_set(&info->stop_eviction, 0);
                info->seals = F_SEAL_SEAL;
                info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->shrinklist);
@@@ -3631,9 -3635,8 +3631,8 @@@ static struct inode *shmem_alloc_inode(
        return &info->vfs_inode;
  }
  
- static void shmem_destroy_callback(struct rcu_head *head)
+ static void shmem_free_in_core_inode(struct inode *inode)
  {
-       struct inode *inode = container_of(head, struct inode, i_rcu);
        if (S_ISLNK(inode->i_mode))
                kfree(inode->i_link);
        kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
@@@ -3643,7 -3646,6 +3642,6 @@@ static void shmem_destroy_inode(struct 
  {
        if (S_ISREG(inode->i_mode))
                mpol_free_shared_policy(&SHMEM_I(inode)->policy);
-       call_rcu(&inode->i_rcu, shmem_destroy_callback);
  }
  
  static void shmem_init_inode(void *foo)
@@@ -3734,6 -3736,7 +3732,7 @@@ static const struct inode_operations sh
  
  static const struct super_operations shmem_ops = {
        .alloc_inode    = shmem_alloc_inode,
+       .free_inode     = shmem_free_in_core_inode,
        .destroy_inode  = shmem_destroy_inode,
  #ifdef CONFIG_TMPFS
        .statfs         = shmem_statfs,
This page took 0.163954 seconds and 4 git commands to generate.