Merge branch 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Jul 2019 17:42:02 +0000 (10:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Jul 2019 17:42:02 +0000 (10:42 -0700)
Pull vfs mount updates from Al Viro:
 "The first part of mount updates.

  Convert filesystems to use the new mount API"

* 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (63 commits)
  mnt_init(): call shmem_init() unconditionally
  constify ksys_mount() string arguments
  don't bother with registering rootfs
  init_rootfs(): don't bother with init_ramfs_fs()
  vfs: Convert smackfs to use the new mount API
  vfs: Convert selinuxfs to use the new mount API
  vfs: Convert securityfs to use the new mount API
  vfs: Convert apparmorfs to use the new mount API
  vfs: Convert openpromfs to use the new mount API
  vfs: Convert xenfs to use the new mount API
  vfs: Convert gadgetfs to use the new mount API
  vfs: Convert oprofilefs to use the new mount API
  vfs: Convert ibmasmfs to use the new mount API
  vfs: Convert qib_fs/ipathfs to use the new mount API
  vfs: Convert efivarfs to use the new mount API
  vfs: Convert configfs to use the new mount API
  vfs: Convert binfmt_misc to use the new mount API
  convenience helper: get_tree_single()
  convenience helper get_tree_nodev()
  vfs: Kill sget_userns()
  ...

44 files changed:
1  2 
arch/ia64/kernel/perfmon.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
drivers/dax/super.c
drivers/dma-buf/dma-buf.c
drivers/gpu/drm/drm_drv.c
drivers/misc/cxl/api.c
drivers/misc/ibmasm/ibmasmfs.c
drivers/misc/vmw_balloon.c
drivers/scsi/cxlflash/ocxl_hw.c
drivers/virtio/virtio_balloon.c
drivers/xen/xenfs/super.c
fs/aio.c
fs/anon_inodes.c
fs/binfmt_misc.c
fs/block_dev.c
fs/configfs/mount.c
fs/efivarfs/super.c
fs/fs_parser.c
fs/fsopen.c
fs/internal.h
fs/libfs.c
fs/namespace.c
fs/nfsd/nfsctl.c
fs/openpromfs/inode.c
fs/proc/root.c
include/linux/dcache.h
include/linux/fs.h
include/linux/fs_context.h
include/linux/syscalls.h
include/uapi/linux/magic.h
init/do_mounts.c
init/main.c
ipc/mqueue.c
kernel/cgroup/cgroup.c
kernel/cgroup/cpuset.c
mm/shmem.c
mm/z3fold.c
mm/zsmalloc.c
net/socket.c
net/sunrpc/rpc_pipe.c
security/apparmor/apparmorfs.c
security/inode.c
security/selinux/selinuxfs.c
security/smack/smackfs.c

Simple merge
Simple merge
  #include <linux/poll.h>
  #include <linux/reservation.h>
  #include <linux/mm.h>
 +#include <linux/mount.h>
++#include <linux/pseudo_fs.h>
  
  #include <uapi/linux/dma-buf.h>
 +#include <uapi/linux/magic.h>
  
  static inline int is_dma_buf_file(struct file *);
  
@@@ -37,41 -46,6 +38,45 @@@ struct dma_buf_list 
  
  static struct dma_buf_list db_list;
  
- static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type,
-               int flags, const char *name, void *data)
 +static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)
 +{
 +      struct dma_buf *dmabuf;
 +      char name[DMA_BUF_NAME_LEN];
 +      size_t ret = 0;
 +
 +      dmabuf = dentry->d_fsdata;
 +      mutex_lock(&dmabuf->lock);
 +      if (dmabuf->name)
 +              ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN);
 +      mutex_unlock(&dmabuf->lock);
 +
 +      return dynamic_dname(dentry, buffer, buflen, "/%s:%s",
 +                           dentry->d_name.name, ret > 0 ? name : "");
 +}
 +
 +static const struct dentry_operations dma_buf_dentry_ops = {
 +      .d_dname = dmabuffs_dname,
 +};
 +
 +static struct vfsmount *dma_buf_mnt;
 +
-       return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops,
-                       DMA_BUF_MAGIC);
++static int dma_buf_fs_init_context(struct fs_context *fc)
 +{
-       .mount = dma_buf_fs_mount,
++      struct pseudo_fs_context *ctx;
++
++      ctx = init_pseudo(fc, DMA_BUF_MAGIC);
++      if (!ctx)
++              return -ENOMEM;
++      ctx->dops = &dma_buf_dentry_ops;
++      return 0;
 +}
 +
 +static struct file_system_type dma_buf_fs_type = {
 +      .name = "dmabuf",
++      .init_fs_context = dma_buf_fs_init_context,
 +      .kill_sb = kill_anon_super,
 +};
 +
  static int dma_buf_release(struct inode *inode, struct file *file)
  {
        struct dma_buf *dmabuf;
Simple merge
Simple merge
Simple merge
@@@ -28,8 -28,6 +28,9 @@@
  #include <linux/rwsem.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
 +#include <linux/mount.h>
++#include <linux/pseudo_fs.h>
 +#include <linux/balloon_compaction.h>
  #include <linux/vmw_vmci_defs.h>
  #include <linux/vmw_vmci_api.h>
  #include <asm/hypervisor.h>
@@@ -1725,204 -1552,9 +1726,197 @@@ static inline void vmballoon_debugfs_ex
  
  #endif        /* CONFIG_DEBUG_FS */
  
- static struct dentry *vmballoon_mount(struct file_system_type *fs_type,
-                                     int flags, const char *dev_name,
-                                     void *data)
 +
 +#ifdef CONFIG_BALLOON_COMPACTION
 +
-       static const struct dentry_operations ops = {
-               .d_dname = simple_dname,
-       };
-       return mount_pseudo(fs_type, "balloon-vmware:", NULL, &ops,
-                           BALLOON_VMW_MAGIC);
++static int vmballoon_init_fs_context(struct fs_context *fc)
 +{
-       .name           = "balloon-vmware",
-       .mount          = vmballoon_mount,
-       .kill_sb        = kill_anon_super,
++      return init_pseudo(fc, BALLOON_VMW_MAGIC) ? 0 : -ENOMEM;
 +}
 +
 +static struct file_system_type vmballoon_fs = {
++      .name                   = "balloon-vmware",
++      .init_fs_context        = vmballoon_init_fs_context,
++      .kill_sb                = kill_anon_super,
 +};
 +
 +static struct vfsmount *vmballoon_mnt;
 +
 +/**
 + * vmballoon_migratepage() - migrates a balloon page.
 + * @b_dev_info: balloon device information descriptor.
 + * @newpage: the page to which @page should be migrated.
 + * @page: a ballooned page that should be migrated.
 + * @mode: migration mode, ignored.
 + *
 + * This function is really open-coded, but that is according to the interface
 + * that balloon_compaction provides.
 + *
 + * Return: zero on success, -EAGAIN when migration cannot be performed
 + *       momentarily, and -EBUSY if migration failed and should be retried
 + *       with that specific page.
 + */
 +static int vmballoon_migratepage(struct balloon_dev_info *b_dev_info,
 +                               struct page *newpage, struct page *page,
 +                               enum migrate_mode mode)
 +{
 +      unsigned long status, flags;
 +      struct vmballoon *b;
 +      int ret;
 +
 +      b = container_of(b_dev_info, struct vmballoon, b_dev_info);
 +
 +      /*
 +       * If the semaphore is taken, there is ongoing configuration change
 +       * (i.e., balloon reset), so try again.
 +       */
 +      if (!down_read_trylock(&b->conf_sem))
 +              return -EAGAIN;
 +
 +      spin_lock(&b->comm_lock);
 +      /*
 +       * We must start by deflating and not inflating, as otherwise the
 +       * hypervisor may tell us that it has enough memory and the new page is
 +       * not needed. Since the old page is isolated, we cannot use the list
 +       * interface to unlock it, as the LRU field is used for isolation.
 +       * Instead, we use the native interface directly.
 +       */
 +      vmballoon_add_page(b, 0, page);
 +      status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
 +                                 VMW_BALLOON_DEFLATE);
 +
 +      if (status == VMW_BALLOON_SUCCESS)
 +              status = vmballoon_status_page(b, 0, &page);
 +
 +      /*
 +       * If a failure happened, let the migration mechanism know that it
 +       * should not retry.
 +       */
 +      if (status != VMW_BALLOON_SUCCESS) {
 +              spin_unlock(&b->comm_lock);
 +              ret = -EBUSY;
 +              goto out_unlock;
 +      }
 +
 +      /*
 +       * The page is isolated, so it is safe to delete it without holding
 +       * @pages_lock . We keep holding @comm_lock since we will need it in a
 +       * second.
 +       */
 +      balloon_page_delete(page);
 +
 +      put_page(page);
 +
 +      /* Inflate */
 +      vmballoon_add_page(b, 0, newpage);
 +      status = vmballoon_lock_op(b, 1, VMW_BALLOON_4K_PAGE,
 +                                 VMW_BALLOON_INFLATE);
 +
 +      if (status == VMW_BALLOON_SUCCESS)
 +              status = vmballoon_status_page(b, 0, &newpage);
 +
 +      spin_unlock(&b->comm_lock);
 +
 +      if (status != VMW_BALLOON_SUCCESS) {
 +              /*
 +               * A failure happened. While we can deflate the page we just
 +               * inflated, this deflation can also encounter an error. Instead
 +               * we will decrease the size of the balloon to reflect the
 +               * change and report failure.
 +               */
 +              atomic64_dec(&b->size);
 +              ret = -EBUSY;
 +      } else {
 +              /*
 +               * Success. Take a reference for the page, and we will add it to
 +               * the list after acquiring the lock.
 +               */
 +              get_page(newpage);
 +              ret = MIGRATEPAGE_SUCCESS;
 +      }
 +
 +      /* Update the balloon list under the @pages_lock */
 +      spin_lock_irqsave(&b->b_dev_info.pages_lock, flags);
 +
 +      /*
 +       * On inflation success, we already took a reference for the @newpage.
 +       * If we succeed just insert it to the list and update the statistics
 +       * under the lock.
 +       */
 +      if (ret == MIGRATEPAGE_SUCCESS) {
 +              balloon_page_insert(&b->b_dev_info, newpage);
 +              __count_vm_event(BALLOON_MIGRATE);
 +      }
 +
 +      /*
 +       * We deflated successfully, so regardless to the inflation success, we
 +       * need to reduce the number of isolated_pages.
 +       */
 +      b->b_dev_info.isolated_pages--;
 +      spin_unlock_irqrestore(&b->b_dev_info.pages_lock, flags);
 +
 +out_unlock:
 +      up_read(&b->conf_sem);
 +      return ret;
 +}
 +
 +/**
 + * vmballoon_compaction_deinit() - removes compaction related data.
 + *
 + * @b: pointer to the balloon.
 + */
 +static void vmballoon_compaction_deinit(struct vmballoon *b)
 +{
 +      if (!IS_ERR(b->b_dev_info.inode))
 +              iput(b->b_dev_info.inode);
 +
 +      b->b_dev_info.inode = NULL;
 +      kern_unmount(vmballoon_mnt);
 +      vmballoon_mnt = NULL;
 +}
 +
 +/**
 + * vmballoon_compaction_init() - initialized compaction for the balloon.
 + *
 + * @b: pointer to the balloon.
 + *
 + * If during the initialization a failure occurred, this function does not
 + * perform cleanup. The caller must call vmballoon_compaction_deinit() in this
 + * case.
 + *
 + * Return: zero on success or error code on failure.
 + */
 +static __init int vmballoon_compaction_init(struct vmballoon *b)
 +{
 +      vmballoon_mnt = kern_mount(&vmballoon_fs);
 +      if (IS_ERR(vmballoon_mnt))
 +              return PTR_ERR(vmballoon_mnt);
 +
 +      b->b_dev_info.migratepage = vmballoon_migratepage;
 +      b->b_dev_info.inode = alloc_anon_inode(vmballoon_mnt->mnt_sb);
 +
 +      if (IS_ERR(b->b_dev_info.inode))
 +              return PTR_ERR(b->b_dev_info.inode);
 +
 +      b->b_dev_info.inode->i_mapping->a_ops = &balloon_aops;
 +      return 0;
 +}
 +
 +#else /* CONFIG_BALLOON_COMPACTION */
 +
 +static void vmballoon_compaction_deinit(struct vmballoon *b)
 +{
 +}
 +
 +static int vmballoon_compaction_init(struct vmballoon *b)
 +{
 +      return 0;
 +}
 +
 +#endif /* CONFIG_BALLOON_COMPACTION */
 +
  static int __init vmballoon_init(void)
  {
 -      enum vmballoon_page_size_type page_size;
        int error;
  
        /*
Simple merge
Simple merge
Simple merge
diff --cc fs/aio.c
Simple merge
Simple merge
Simple merge
diff --cc fs/block_dev.c
Simple merge
Simple merge
Simple merge
diff --cc fs/fs_parser.c
Simple merge
diff --cc fs/fsopen.c
Simple merge
diff --cc fs/internal.h
Simple merge
diff --cc fs/libfs.c
Simple merge
diff --cc fs/namespace.c
Simple merge
@@@ -1149,201 -1147,8 +1150,201 @@@ static ssize_t write_v4_end_grace(struc
   *    populating the filesystem.
   */
  
- static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
 +/* Basically copying rpc_get_inode. */
 +static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
 +{
 +      struct inode *inode = new_inode(sb);
 +      if (!inode)
 +              return NULL;
 +      /* Following advice from simple_fill_super documentation: */
 +      inode->i_ino = iunique(sb, NFSD_MaxReserved);
 +      inode->i_mode = mode;
 +      inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 +      switch (mode & S_IFMT) {
 +      case S_IFDIR:
 +              inode->i_fop = &simple_dir_operations;
 +              inode->i_op = &simple_dir_inode_operations;
 +              inc_nlink(inode);
 +      default:
 +              break;
 +      }
 +      return inode;
 +}
 +
 +static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 +{
 +      struct inode *inode;
 +
 +      inode = nfsd_get_inode(dir->i_sb, mode);
 +      if (!inode)
 +              return -ENOMEM;
 +      d_add(dentry, inode);
 +      inc_nlink(dir);
 +      fsnotify_mkdir(dir, dentry);
 +      return 0;
 +}
 +
 +static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name)
 +{
 +      struct inode *dir = parent->d_inode;
 +      struct dentry *dentry;
 +      int ret = -ENOMEM;
 +
 +      inode_lock(dir);
 +      dentry = d_alloc_name(parent, name);
 +      if (!dentry)
 +              goto out_err;
 +      ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600);
 +      if (ret)
 +              goto out_err;
 +      if (ncl) {
 +              d_inode(dentry)->i_private = ncl;
 +              kref_get(&ncl->cl_ref);
 +      }
 +out:
 +      inode_unlock(dir);
 +      return dentry;
 +out_err:
 +      dentry = ERR_PTR(ret);
 +      goto out;
 +}
 +
 +static void clear_ncl(struct inode *inode)
 +{
 +      struct nfsdfs_client *ncl = inode->i_private;
 +
 +      inode->i_private = NULL;
 +      synchronize_rcu();
 +      kref_put(&ncl->cl_ref, ncl->cl_release);
 +}
 +
 +
 +static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
 +{
 +      struct nfsdfs_client *nc = inode->i_private;
 +
 +      if (nc)
 +              kref_get(&nc->cl_ref);
 +      return nc;
 +}
 +
 +struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
 +{
 +      struct nfsdfs_client *nc;
 +
 +      rcu_read_lock();
 +      nc = __get_nfsdfs_client(inode);
 +      rcu_read_unlock();
 +      return nc;
 +}
 +/* from __rpc_unlink */
 +static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
 +{
 +      int ret;
 +
 +      clear_ncl(d_inode(dentry));
 +      dget(dentry);
 +      ret = simple_unlink(dir, dentry);
 +      d_delete(dentry);
 +      dput(dentry);
 +      WARN_ON_ONCE(ret);
 +}
 +
 +static void nfsdfs_remove_files(struct dentry *root)
 +{
 +      struct dentry *dentry, *tmp;
 +
 +      list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) {
 +              if (!simple_positive(dentry)) {
 +                      WARN_ON_ONCE(1); /* I think this can't happen? */
 +                      continue;
 +              }
 +              nfsdfs_remove_file(d_inode(root), dentry);
 +      }
 +}
 +
 +/* XXX: cut'n'paste from simple_fill_super; figure out if we could share
 + * code instead. */
 +static  int nfsdfs_create_files(struct dentry *root,
 +                                      const struct tree_descr *files)
 +{
 +      struct inode *dir = d_inode(root);
 +      struct inode *inode;
 +      struct dentry *dentry;
 +      int i;
 +
 +      inode_lock(dir);
 +      for (i = 0; files->name && files->name[0]; i++, files++) {
 +              if (!files->name)
 +                      continue;
 +              dentry = d_alloc_name(root, files->name);
 +              if (!dentry)
 +                      goto out;
 +              inode = nfsd_get_inode(d_inode(root)->i_sb,
 +                                      S_IFREG | files->mode);
 +              if (!inode) {
 +                      dput(dentry);
 +                      goto out;
 +              }
 +              inode->i_fop = files->ops;
 +              inode->i_private = __get_nfsdfs_client(dir);
 +              d_add(dentry, inode);
 +              fsnotify_create(dir, dentry);
 +      }
 +      inode_unlock(dir);
 +      return 0;
 +out:
 +      nfsdfs_remove_files(root);
 +      inode_unlock(dir);
 +      return -ENOMEM;
 +}
 +
 +/* on success, returns positive number unique to that client. */
 +struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
 +              struct nfsdfs_client *ncl, u32 id,
 +              const struct tree_descr *files)
 +{
 +      struct dentry *dentry;
 +      char name[11];
 +      int ret;
 +
 +      sprintf(name, "%u", id);
 +
 +      dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
 +      if (IS_ERR(dentry)) /* XXX: tossing errors? */
 +              return NULL;
 +      ret = nfsdfs_create_files(dentry, files);
 +      if (ret) {
 +              nfsd_client_rmdir(dentry);
 +              return NULL;
 +      }
 +      return dentry;
 +}
 +
 +/* Taken from __rpc_rmdir: */
 +void nfsd_client_rmdir(struct dentry *dentry)
 +{
 +      struct inode *dir = d_inode(dentry->d_parent);
 +      struct inode *inode = d_inode(dentry);
 +      int ret;
 +
 +      inode_lock(dir);
 +      nfsdfs_remove_files(dentry);
 +      clear_ncl(inode);
 +      dget(dentry);
 +      ret = simple_rmdir(dir, dentry);
 +      WARN_ON_ONCE(ret);
 +      d_delete(dentry);
 +      inode_unlock(dir);
 +}
 +
+ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
  {
 +      struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
 +                                                      nfsd_net_id);
 +      struct dentry *dentry;
 +      int ret;
 +
        static const struct tree_descr nfsd_files[] = {
                [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
                [NFSD_Export_features] = {"export_features",
  #endif
                /* last one */ {""}
        };
-       get_net(sb->s_fs_info);
 -      return simple_fill_super(sb, 0x6e667364, nfsd_files);
 +      ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
 +      if (ret)
 +              return ret;
 +      dentry = nfsd_mkdir(sb->s_root, NULL, "clients");
 +      if (IS_ERR(dentry))
 +              return PTR_ERR(dentry);
 +      nn->nfsd_client_dir = dentry;
 +      return 0;
+ }
  
+ static int nfsd_fs_get_tree(struct fs_context *fc)
+ {
+       fc->s_fs_info = get_net(fc->net_ns);
+       return vfs_get_super(fc, vfs_get_keyed_super, nfsd_fill_super);
  }
  
- static struct dentry *nfsd_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+ static void nfsd_fs_free_fc(struct fs_context *fc)
  {
-       struct net *net = current->nsproxy->net_ns;
-       return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super);
+       if (fc->s_fs_info)
+               put_net(fc->s_fs_info);
+ }
+ static const struct fs_context_operations nfsd_fs_context_ops = {
+       .free           = nfsd_fs_free_fc,
+       .get_tree       = nfsd_fs_get_tree,
+ };
+ static int nfsd_init_fs_context(struct fs_context *fc)
+ {
+       put_user_ns(fc->user_ns);
+       fc->user_ns = get_user_ns(fc->net_ns->user_ns);
+       fc->ops = &nfsd_fs_context_ops;
+       return 0;
  }
  
  static void nfsd_umount(struct super_block *sb)
Simple merge
diff --cc fs/proc/root.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -91,6 -91,6 +91,7 @@@
  #define UDF_SUPER_MAGIC               0x15013346
  #define BALLOON_KVM_MAGIC     0x13661366
  #define ZSMALLOC_MAGIC                0x58295829
 +#define DMA_BUF_MAGIC         0x444d4142      /* "DMAB" */
+ #define Z3FOLD_MAGIC          0x33
  
  #endif /* __LINUX_MAGIC_H__ */
Simple merge
diff --cc init/main.c
Simple merge
diff --cc ipc/mqueue.c
Simple merge
Simple merge
Simple merge
diff --cc mm/shmem.c
Simple merge
diff --cc mm/z3fold.c
Simple merge
diff --cc mm/zsmalloc.c
Simple merge
diff --cc net/socket.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge