Merge tag 'kvm-ppc-next-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/paulu...
[linux-2.6-block.git] / fs / afs / mntpt.c
index 2e51c6994148f30f4ec8d858b1e318b1d58980c0..eecd8b6991862f907de1a00fd1df54dc084059a1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/gfp.h>
+#include <linux/fs_context.h>
 #include "internal.h"
 
 
@@ -47,6 +48,8 @@ static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
 
 static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
 
+static const char afs_root_volume[] = "root.cell";
+
 /*
  * no valid lookup procedure on this sort of dir
  */
@@ -68,108 +71,112 @@ static int afs_mntpt_open(struct inode *inode, struct file *file)
 }
 
 /*
- * create a vfsmount to be automounted
+ * Set the parameters for the proposed superblock.
  */
-static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
+static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)
 {
-       struct afs_super_info *as;
-       struct vfsmount *mnt;
-       struct afs_vnode *vnode;
-       struct page *page;
-       char *devname, *options;
-       bool rwpath = false;
+       struct afs_fs_context *ctx = fc->fs_private;
+       struct afs_super_info *src_as = AFS_FS_S(mntpt->d_sb);
+       struct afs_vnode *vnode = AFS_FS_I(d_inode(mntpt));
+       struct afs_cell *cell;
+       const char *p;
        int ret;
 
-       _enter("{%pd}", mntpt);
-
-       BUG_ON(!d_inode(mntpt));
-
-       ret = -ENOMEM;
-       devname = (char *) get_zeroed_page(GFP_KERNEL);
-       if (!devname)
-               goto error_no_devname;
-
-       options = (char *) get_zeroed_page(GFP_KERNEL);
-       if (!options)
-               goto error_no_options;
+       if (fc->net_ns != src_as->net_ns) {
+               put_net(fc->net_ns);
+               fc->net_ns = get_net(src_as->net_ns);
+       }
 
-       vnode = AFS_FS_I(d_inode(mntpt));
+       if (src_as->volume && src_as->volume->type == AFSVL_RWVOL) {
+               ctx->type = AFSVL_RWVOL;
+               ctx->force = true;
+       }
+       if (ctx->cell) {
+               afs_put_cell(ctx->net, ctx->cell);
+               ctx->cell = NULL;
+       }
        if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
                /* if the directory is a pseudo directory, use the d_name */
-               static const char afs_root_cell[] = ":root.cell.";
                unsigned size = mntpt->d_name.len;
 
-               ret = -ENOENT;
-               if (size < 2 || size > AFS_MAXCELLNAME)
-                       goto error_no_page;
+               if (size < 2)
+                       return -ENOENT;
 
+               p = mntpt->d_name.name;
                if (mntpt->d_name.name[0] == '.') {
-                       devname[0] = '%';
-                       memcpy(devname + 1, mntpt->d_name.name + 1, size - 1);
-                       memcpy(devname + size, afs_root_cell,
-                              sizeof(afs_root_cell));
-                       rwpath = true;
-               } else {
-                       devname[0] = '#';
-                       memcpy(devname + 1, mntpt->d_name.name, size);
-                       memcpy(devname + size + 1, afs_root_cell,
-                              sizeof(afs_root_cell));
+                       size--;
+                       p++;
+                       ctx->type = AFSVL_RWVOL;
+                       ctx->force = true;
                }
+               if (size > AFS_MAXCELLNAME)
+                       return -ENAMETOOLONG;
+
+               cell = afs_lookup_cell(ctx->net, p, size, NULL, false);
+               if (IS_ERR(cell)) {
+                       pr_err("kAFS: unable to lookup cell '%pd'\n", mntpt);
+                       return PTR_ERR(cell);
+               }
+               ctx->cell = cell;
+
+               ctx->volname = afs_root_volume;
+               ctx->volnamesz = sizeof(afs_root_volume) - 1;
        } else {
                /* read the contents of the AFS special symlink */
+               struct page *page;
                loff_t size = i_size_read(d_inode(mntpt));
                char *buf;
 
-               ret = -EINVAL;
+               if (src_as->cell)
+                       ctx->cell = afs_get_cell(src_as->cell);
+
                if (size > PAGE_SIZE - 1)
-                       goto error_no_page;
+                       return -EINVAL;
 
                page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);
-               if (IS_ERR(page)) {
-                       ret = PTR_ERR(page);
-                       goto error_no_page;
-               }
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
 
                if (PageError(page)) {
                        ret = afs_bad(AFS_FS_I(d_inode(mntpt)), afs_file_error_mntpt);
-                       goto error;
+                       put_page(page);
+                       return ret;
                }
 
-               buf = kmap_atomic(page);
-               memcpy(devname, buf, size);
-               kunmap_atomic(buf);
+               buf = kmap(page);
+               ret = vfs_parse_fs_string(fc, "source", buf, size);
+               kunmap(page);
                put_page(page);
-               page = NULL;
+               if (ret < 0)
+                       return ret;
        }
 
-       /* work out what options we want */
-       as = AFS_FS_S(mntpt->d_sb);
-       if (as->cell) {
-               memcpy(options, "cell=", 5);
-               strcpy(options + 5, as->cell->name);
-               if ((as->volume && as->volume->type == AFSVL_RWVOL) || rwpath)
-                       strcat(options, ",rwpath");
-       }
+       return 0;
+}
 
-       /* try and do the mount */
-       _debug("--- attempting mount %s -o %s ---", devname, options);
-       mnt = vfs_submount(mntpt, &afs_fs_type, devname, options);
-       _debug("--- mount result %p ---", mnt);
+/*
+ * create a vfsmount to be automounted
+ */
+static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
+{
+       struct fs_context *fc;
+       struct vfsmount *mnt;
+       int ret;
 
-       free_page((unsigned long) devname);
-       free_page((unsigned long) options);
-       _leave(" = %p", mnt);
-       return mnt;
+       BUG_ON(!d_inode(mntpt));
 
-error:
-       put_page(page);
-error_no_page:
-       free_page((unsigned long) options);
-error_no_options:
-       free_page((unsigned long) devname);
-error_no_devname:
-       _leave(" = %d", ret);
-       return ERR_PTR(ret);
+       fc = fs_context_for_submount(&afs_fs_type, mntpt);
+       if (IS_ERR(fc))
+               return ERR_CAST(fc);
+
+       ret = afs_mntpt_set_params(fc, mntpt);
+       if (!ret)
+               mnt = fc_mount(fc);
+       else
+               mnt = ERR_PTR(ret);
+
+       put_fs_context(fc);
+       return mnt;
 }
 
 /*