cifs: Extract DFS referral expansion logic to separate function
authorSean Finney <seanius@seanius.net>
Mon, 11 Apr 2011 13:19:30 +0000 (13:19 +0000)
committerSteve French <sfrench@us.ibm.com>
Thu, 19 May 2011 14:10:54 +0000 (14:10 +0000)
The logic behind the expansion of DFS referrals is now extracted from
cifs_mount into a new static function, expand_dfs_referral.  This will
reduce duplicate code in upcoming commits.

Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Sean Finney <seanius@seanius.net>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/connect.c

index 2b511991187a185d87d4f6db64f057a3a109462b..b6c6a3629b079d55bb787938c72fae56b9e808fa 100644 (file)
@@ -2745,6 +2745,57 @@ build_unc_path_to_root(const struct smb_vol *volume_info,
        full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
        return full_path;
 }
+
+/*
+ * Perform a dfs referral query for a share and (optionally) prefix
+ *
+ * If a referral is found, mount_data will be set to point at a newly
+ * allocated string containing updated options for the submount.
+ * Otherwise it will be left untouched.
+ *
+ * Returns the rc from get_dfs_path to the caller, which can be used to
+ * determine whether there were referrals.
+ */
+static int
+expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo,
+                   struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
+                   char **mount_data, int check_prefix)
+{
+       int rc;
+       unsigned int num_referrals = 0;
+       struct dfs_info3_param *referrals = NULL;
+       char *full_path = NULL, *ref_path = NULL, *mdata = NULL;
+
+       full_path = build_unc_path_to_root(volume_info, cifs_sb);
+       if (IS_ERR(full_path))
+               return PTR_ERR(full_path);
+
+       /* For DFS paths, skip the first '\' of the UNC */
+       ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
+
+       rc = get_dfs_path(xid, pSesInfo , ref_path, cifs_sb->local_nls,
+                         &num_referrals, &referrals,
+                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (!rc && num_referrals > 0) {
+               char *fake_devname = NULL;
+
+               mdata = cifs_compose_mount_options(cifs_sb->mountdata,
+                                                  full_path + 1, referrals,
+                                                  &fake_devname);
+
+               free_dfs_info_array(referrals, num_referrals);
+               kfree(fake_devname);
+
+               if (IS_ERR(mdata)) {
+                       rc = PTR_ERR(mdata);
+                       mdata = NULL;
+               }
+               *mount_data = mdata;
+       }
+       kfree(full_path);
+       return rc;
+}
 #endif
 
 int
@@ -2761,10 +2812,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        char *mount_data = mount_data_global;
        struct tcon_link *tlink;
 #ifdef CONFIG_CIFS_DFS_UPCALL
-       struct dfs_info3_param *referrals = NULL;
-       unsigned int num_referrals = 0;
        int referral_walks_count = 0;
 try_mount_again:
+
+       /* cleanup activities if we're chasing a referral */
+       if (referral_walks_count) {
+               if (tcon)
+                       cifs_put_tcon(tcon);
+               else if (pSesInfo)
+                       cifs_put_smb_ses(pSesInfo);
+
+               cleanup_volume_info(&volume_info);
+               FreeXid(xid);
+       }
 #endif
        rc = 0;
        tcon = NULL;
@@ -2910,46 +2970,19 @@ remote_path_check:
                if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
                        convert_delimiter(cifs_sb->prepath,
                                        CIFS_DIR_SEP(cifs_sb));
-               full_path = build_unc_path_to_root(volume_info, cifs_sb);
-               if (IS_ERR(full_path)) {
-                       rc = PTR_ERR(full_path);
-                       goto mount_fail_check;
-               }
 
-               cFYI(1, "Getting referral for: %s", full_path);
-               rc = get_dfs_path(xid, pSesInfo , full_path + 1,
-                       cifs_sb->local_nls, &num_referrals, &referrals,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (!rc && num_referrals > 0) {
-                       char *fake_devname = NULL;
-
-                       if (mount_data != mount_data_global)
-                               kfree(mount_data);
-
-                       mount_data = cifs_compose_mount_options(
-                                       cifs_sb->mountdata, full_path + 1,
-                                       referrals, &fake_devname);
-
-                       free_dfs_info_array(referrals, num_referrals);
-                       kfree(fake_devname);
-                       kfree(full_path);
-
-                       if (IS_ERR(mount_data)) {
-                               rc = PTR_ERR(mount_data);
-                               mount_data = NULL;
-                               goto mount_fail_check;
-                       }
+               if (mount_data != mount_data_global)
+                       kfree(mount_data);
 
-                       if (tcon)
-                               cifs_put_tcon(tcon);
-                       else if (pSesInfo)
-                               cifs_put_smb_ses(pSesInfo);
+               rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
+                                        &mount_data, true);
 
-                       cleanup_volume_info(&volume_info);
+               if (!rc) {
                        referral_walks_count++;
-                       FreeXid(xid);
                        goto try_mount_again;
                }
+               mount_data = NULL;
+               goto mount_fail_check;
 #else /* No DFS support, return error on mount */
                rc = -EOPNOTSUPP;
 #endif