Commit dd613945 authored by Sean Finney's avatar Sean Finney Committed by Steve French

cifs: Extract DFS referral expansion logic to separate function

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: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSean Finney <seanius@seanius.net>
Signed-off-by: default avatarPavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 460458ce
...@@ -2745,6 +2745,57 @@ build_unc_path_to_root(const struct smb_vol *volume_info, ...@@ -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 */ full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
return full_path; 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 #endif
int int
...@@ -2761,10 +2812,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2761,10 +2812,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
char *mount_data = mount_data_global; char *mount_data = mount_data_global;
struct tcon_link *tlink; struct tcon_link *tlink;
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;
int referral_walks_count = 0; int referral_walks_count = 0;
try_mount_again: 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 #endif
rc = 0; rc = 0;
tcon = NULL; tcon = NULL;
...@@ -2910,46 +2970,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2910,46 +2970,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
convert_delimiter(cifs_sb->prepath, convert_delimiter(cifs_sb->prepath,
CIFS_DIR_SEP(cifs_sb)); 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) if (mount_data != mount_data_global)
kfree(mount_data); kfree(mount_data);
mount_data = cifs_compose_mount_options( rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb,
cifs_sb->mountdata, full_path + 1, &mount_data, true);
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 (tcon)
cifs_put_tcon(tcon);
else if (pSesInfo)
cifs_put_smb_ses(pSesInfo);
cleanup_volume_info(&volume_info); if (!rc) {
referral_walks_count++; referral_walks_count++;
FreeXid(xid);
goto try_mount_again; goto try_mount_again;
} }
mount_data = NULL;
goto mount_fail_check;
#else /* No DFS support, return error on mount */ #else /* No DFS support, return error on mount */
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment