cifs: use fs_context for automounts
authorPaulo Alcantara <pc@cjr.nz>
Tue, 4 Oct 2022 21:41:20 +0000 (18:41 -0300)
committerSteve French <stfrench@microsoft.com>
Mon, 19 Dec 2022 14:03:11 +0000 (08:03 -0600)
Use filesystem context support to handle dfs links.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifs_dfs_ref.c

index b0864da..020e71f 100644 (file)
@@ -258,61 +258,23 @@ compose_mount_options_err:
        goto compose_mount_options_out;
 }
 
-/**
- * cifs_dfs_do_mount - mounts specified path using DFS full path
- *
- * Always pass down @fullpath to smb3_do_mount() so we can use the root server
- * to perform failover in case we failed to connect to the first target in the
- * referral.
- *
- * @mntpt:             directory entry for the path we are trying to automount
- * @cifs_sb:           parent/root superblock
- * @fullpath:          full path in UNC format
- */
-static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
-                                         struct cifs_sb_info *cifs_sb,
-                                         const char *fullpath)
-{
-       struct vfsmount *mnt;
-       char *mountdata;
-       char *devname;
-
-       devname = kstrdup(fullpath, GFP_KERNEL);
-       if (!devname)
-               return ERR_PTR(-ENOMEM);
-
-       convert_delimiter(devname, '/');
-
-       /* TODO: change to call fs_context_for_mount(), fill in context directly, call fc_mount */
-
-       /* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */
-
-       /* strip first '\' from fullpath */
-       mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
-                                              fullpath + 1, NULL, NULL);
-       if (IS_ERR(mountdata)) {
-               kfree(devname);
-               return (struct vfsmount *)mountdata;
-       }
-
-       mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
-       kfree(mountdata);
-       kfree(devname);
-       return mnt;
-}
-
 /*
  * Create a vfsmount that we can automount
  */
-static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
+static struct vfsmount *cifs_dfs_do_automount(struct path *path)
 {
+       int rc;
+       struct dentry *mntpt = path->dentry;
+       struct fs_context *fc;
        struct cifs_sb_info *cifs_sb;
-       void *page;
+       void *page = NULL;
+       struct smb3_fs_context *ctx, *cur_ctx;
+       struct smb3_fs_context tmp;
        char *full_path;
        struct vfsmount *mnt;
 
-       cifs_dbg(FYI, "in %s\n", __func__);
-       BUG_ON(IS_ROOT(mntpt));
+       if (IS_ROOT(mntpt))
+               return ERR_PTR(-ESTALE);
 
        /*
         * The MSDFS spec states that paths in DFS referral requests and
@@ -321,29 +283,47 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
         * gives us the latter, so we must adjust the result.
         */
        cifs_sb = CIFS_SB(mntpt->d_sb);
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
-               mnt = ERR_PTR(-EREMOTE);
-               goto cdda_exit;
-       }
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
+               return ERR_PTR(-EREMOTE);
+
+       cur_ctx = cifs_sb->ctx;
+
+       fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
+       if (IS_ERR(fc))
+               return ERR_CAST(fc);
+
+       ctx = smb3_fc2context(fc);
 
        page = alloc_dentry_path();
        /* always use tree name prefix */
        full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
        if (IS_ERR(full_path)) {
                mnt = ERR_CAST(full_path);
-               goto free_full_path;
+               goto out;
        }
 
-       convert_delimiter(full_path, '\\');
+       convert_delimiter(full_path, '/');
        cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
 
-       mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
-       cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
+       tmp = *cur_ctx;
+       tmp.source = full_path;
+       tmp.UNC = tmp.prepath = NULL;
+
+       rc = smb3_fs_context_dup(ctx, &tmp);
+       if (rc) {
+               mnt = ERR_PTR(rc);
+               goto out;
+       }
+
+       rc = smb3_parse_devname(full_path, ctx);
+       if (!rc)
+               mnt = fc_mount(fc);
+       else
+               mnt = ERR_PTR(rc);
 
-free_full_path:
+out:
+       put_fs_context(fc);
        free_dentry_path(page);
-cdda_exit:
-       cifs_dbg(FYI, "leaving %s\n" , __func__);
        return mnt;
 }
 
@@ -354,9 +334,9 @@ struct vfsmount *cifs_dfs_d_automount(struct path *path)
 {
        struct vfsmount *newmnt;
 
-       cifs_dbg(FYI, "in %s\n", __func__);
+       cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
 
-       newmnt = cifs_dfs_do_automount(path->dentry);
+       newmnt = cifs_dfs_do_automount(path);
        if (IS_ERR(newmnt)) {
                cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
                return newmnt;