mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
cifs: Refactor out cifs_mount()
* Split and refactor the very large function cifs_mount() in multiple functions: - tcp, ses and tcon setup to mount_get_conns() - tcp, ses and tcon cleanup in mount_put_conns() - tcon tlink setup to mount_setup_tlink() - remote path checking to is_path_remote() * Implement 2 version of cifs_mount() for DFS-enabled builds and non-DFS-enabled builds (CONFIG_CIFS_DFS_UPCALL). In preparation for DFS failover support. Signed-off-by: Paulo Alcantara <palcantara@suse.de> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
9a596f5b39
commit
56c762eb9b
2 changed files with 272 additions and 193 deletions
|
@ -213,7 +213,7 @@ extern int cifs_match_super(struct super_block *, void *);
|
||||||
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
|
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
|
||||||
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
|
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
|
||||||
const char *devname, bool is_smb3);
|
const char *devname, bool is_smb3);
|
||||||
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
|
extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol);
|
||||||
extern void cifs_umount(struct cifs_sb_info *);
|
extern void cifs_umount(struct cifs_sb_info *);
|
||||||
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
|
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
|
||||||
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
|
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
|
||||||
|
@ -524,6 +524,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
||||||
const struct nls_table *codepage);
|
const struct nls_table *codepage);
|
||||||
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||||
unsigned char *p24);
|
unsigned char *p24);
|
||||||
|
extern void
|
||||||
|
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
|
||||||
|
|
||||||
void cifs_readdata_release(struct kref *refcount);
|
void cifs_readdata_release(struct kref *refcount);
|
||||||
int cifs_async_readv(struct cifs_readdata *rdata);
|
int cifs_async_readv(struct cifs_readdata *rdata);
|
||||||
|
|
|
@ -3747,8 +3747,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
cleanup_volume_info_contents(struct smb_vol *volume_info)
|
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info)
|
||||||
{
|
{
|
||||||
kfree(volume_info->username);
|
kfree(volume_info->username);
|
||||||
kzfree(volume_info->password);
|
kzfree(volume_info->password);
|
||||||
|
@ -3763,10 +3763,136 @@ cifs_cleanup_volume_info(struct smb_vol *volume_info)
|
||||||
{
|
{
|
||||||
if (!volume_info)
|
if (!volume_info)
|
||||||
return;
|
return;
|
||||||
cleanup_volume_info_contents(volume_info);
|
cifs_cleanup_volume_info_contents(volume_info);
|
||||||
kfree(volume_info);
|
kfree(volume_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Release all succeed connections */
|
||||||
|
static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
|
||||||
|
unsigned int xid,
|
||||||
|
struct TCP_Server_Info *server,
|
||||||
|
struct cifs_ses *ses, struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (tcon)
|
||||||
|
cifs_put_tcon(tcon);
|
||||||
|
else if (ses)
|
||||||
|
cifs_put_smb_ses(ses);
|
||||||
|
else if (server)
|
||||||
|
cifs_put_tcp_session(server, 0);
|
||||||
|
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
|
||||||
|
free_xid(xid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get connections for tcp, ses and tcon */
|
||||||
|
static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
|
||||||
|
unsigned int *xid,
|
||||||
|
struct TCP_Server_Info **nserver,
|
||||||
|
struct cifs_ses **nses, struct cifs_tcon **ntcon)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
struct cifs_ses *ses;
|
||||||
|
struct cifs_tcon *tcon;
|
||||||
|
|
||||||
|
*nserver = NULL;
|
||||||
|
*nses = NULL;
|
||||||
|
*ntcon = NULL;
|
||||||
|
|
||||||
|
*xid = get_xid();
|
||||||
|
|
||||||
|
/* get a reference to a tcp session */
|
||||||
|
server = cifs_get_tcp_session(vol);
|
||||||
|
if (IS_ERR(server)) {
|
||||||
|
rc = PTR_ERR(server);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nserver = server;
|
||||||
|
|
||||||
|
if ((vol->max_credits < 20) || (vol->max_credits > 60000))
|
||||||
|
server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
|
||||||
|
else
|
||||||
|
server->max_credits = vol->max_credits;
|
||||||
|
|
||||||
|
/* get a reference to a SMB session */
|
||||||
|
ses = cifs_get_smb_ses(server, vol);
|
||||||
|
if (IS_ERR(ses)) {
|
||||||
|
rc = PTR_ERR(ses);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nses = ses;
|
||||||
|
|
||||||
|
if ((vol->persistent == true) && (!(ses->server->capabilities &
|
||||||
|
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
|
||||||
|
cifs_dbg(VFS, "persistent handles not supported by server\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search for existing tcon to this server share */
|
||||||
|
tcon = cifs_get_tcon(ses, vol);
|
||||||
|
if (IS_ERR(tcon)) {
|
||||||
|
rc = PTR_ERR(tcon);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ntcon = tcon;
|
||||||
|
|
||||||
|
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
||||||
|
if (tcon->posix_extensions)
|
||||||
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||||
|
|
||||||
|
/* tell server which Unix caps we support */
|
||||||
|
if (cap_unix(tcon->ses)) {
|
||||||
|
/*
|
||||||
|
* reset of caps checks mount to see if unix extensions disabled
|
||||||
|
* for just this mount.
|
||||||
|
*/
|
||||||
|
reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol);
|
||||||
|
if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
|
||||||
|
(le64_to_cpu(tcon->fsUnixInfo.Capability) &
|
||||||
|
CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
|
||||||
|
return -EACCES;
|
||||||
|
} else
|
||||||
|
tcon->unix_ext = 0; /* server does not support them */
|
||||||
|
|
||||||
|
/* do not care if a following call succeed - informational */
|
||||||
|
if (!tcon->pipe && server->ops->qfs_tcon)
|
||||||
|
server->ops->qfs_tcon(*xid, tcon);
|
||||||
|
|
||||||
|
cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
|
||||||
|
cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
struct tcon_link *tlink;
|
||||||
|
|
||||||
|
/* hang the tcon off of the superblock */
|
||||||
|
tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
|
||||||
|
if (tlink == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
tlink->tl_uid = ses->linux_uid;
|
||||||
|
tlink->tl_tcon = tcon;
|
||||||
|
tlink->tl_time = jiffies;
|
||||||
|
set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
|
||||||
|
set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
|
||||||
|
|
||||||
|
cifs_sb->master_tlink = tlink;
|
||||||
|
spin_lock(&cifs_sb->tlink_tree_lock);
|
||||||
|
tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
|
||||||
|
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||||
|
|
||||||
|
queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
|
||||||
|
TLINK_IDLE_EXPIRE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
/*
|
/*
|
||||||
|
@ -3846,7 +3972,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
|
||||||
rc = PTR_ERR(mdata);
|
rc = PTR_ERR(mdata);
|
||||||
mdata = NULL;
|
mdata = NULL;
|
||||||
} else {
|
} else {
|
||||||
cleanup_volume_info_contents(volume_info);
|
cifs_cleanup_volume_info_contents(volume_info);
|
||||||
rc = cifs_setup_volume_info(volume_info, mdata,
|
rc = cifs_setup_volume_info(volume_info, mdata,
|
||||||
fake_devname, false);
|
fake_devname, false);
|
||||||
}
|
}
|
||||||
|
@ -3955,107 +4081,77 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/*
|
||||||
cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
|
* Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
|
||||||
|
* otherwise 0.
|
||||||
|
*/
|
||||||
|
static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
|
||||||
|
const unsigned int xid,
|
||||||
|
struct TCP_Server_Info *server,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
char *full_path;
|
||||||
|
|
||||||
|
if (!server->ops->is_path_accessible)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cifs_build_path_to_root works only when we have a valid tcon
|
||||||
|
*/
|
||||||
|
full_path = cifs_build_path_to_root(vol, cifs_sb, tcon,
|
||||||
|
tcon->Flags & SMB_SHARE_IS_IN_DFS);
|
||||||
|
if (full_path == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
|
||||||
|
|
||||||
|
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
|
||||||
|
full_path);
|
||||||
|
if (rc != 0 && rc != -EREMOTE) {
|
||||||
|
kfree(full_path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != -EREMOTE) {
|
||||||
|
rc = cifs_are_all_path_components_accessible(server, xid, tcon,
|
||||||
|
cifs_sb,
|
||||||
|
full_path);
|
||||||
|
if (rc != 0) {
|
||||||
|
cifs_dbg(VFS, "cannot query dirs between root and final path, "
|
||||||
|
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
|
||||||
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(full_path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
unsigned int xid;
|
unsigned int xid;
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon = NULL;
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
char *full_path;
|
char *old_mountdata;
|
||||||
struct tcon_link *tlink;
|
int count;
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
int referral_walks_count = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
|
||||||
try_mount_again:
|
if (!rc && tcon) {
|
||||||
/* cleanup activities if we're chasing a referral */
|
rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
|
||||||
if (referral_walks_count) {
|
if (!rc)
|
||||||
if (tcon)
|
goto out;
|
||||||
cifs_put_tcon(tcon);
|
if (rc != -EREMOTE)
|
||||||
else if (ses)
|
goto error;
|
||||||
cifs_put_smb_ses(ses);
|
|
||||||
|
|
||||||
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
|
|
||||||
|
|
||||||
free_xid(xid);
|
|
||||||
}
|
}
|
||||||
#endif
|
if ((rc == -EACCES) || (rc == -EOPNOTSUPP) || (ses == NULL) || (server == NULL))
|
||||||
rc = 0;
|
goto error;
|
||||||
tcon = NULL;
|
|
||||||
ses = NULL;
|
|
||||||
server = NULL;
|
|
||||||
full_path = NULL;
|
|
||||||
tlink = NULL;
|
|
||||||
|
|
||||||
xid = get_xid();
|
|
||||||
|
|
||||||
/* get a reference to a tcp session */
|
|
||||||
server = cifs_get_tcp_session(volume_info);
|
|
||||||
if (IS_ERR(server)) {
|
|
||||||
rc = PTR_ERR(server);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if ((volume_info->max_credits < 20) ||
|
|
||||||
(volume_info->max_credits > 60000))
|
|
||||||
server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
|
|
||||||
else
|
|
||||||
server->max_credits = volume_info->max_credits;
|
|
||||||
/* get a reference to a SMB session */
|
|
||||||
ses = cifs_get_smb_ses(server, volume_info);
|
|
||||||
if (IS_ERR(ses)) {
|
|
||||||
rc = PTR_ERR(ses);
|
|
||||||
ses = NULL;
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((volume_info->persistent == true) && ((ses->server->capabilities &
|
|
||||||
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) == 0)) {
|
|
||||||
cifs_dbg(VFS, "persistent handles not supported by server\n");
|
|
||||||
rc = -EOPNOTSUPP;
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* search for existing tcon to this server share */
|
|
||||||
tcon = cifs_get_tcon(ses, volume_info);
|
|
||||||
if (IS_ERR(tcon)) {
|
|
||||||
rc = PTR_ERR(tcon);
|
|
||||||
tcon = NULL;
|
|
||||||
if (rc == -EACCES)
|
|
||||||
goto mount_fail_check;
|
|
||||||
|
|
||||||
goto remote_path_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
|
|
||||||
if (tcon->posix_extensions)
|
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
|
||||||
|
|
||||||
/* tell server which Unix caps we support */
|
|
||||||
if (cap_unix(tcon->ses)) {
|
|
||||||
/* reset of caps checks mount to see if unix extensions
|
|
||||||
disabled for just this mount */
|
|
||||||
reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
|
|
||||||
if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
|
|
||||||
(le64_to_cpu(tcon->fsUnixInfo.Capability) &
|
|
||||||
CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
|
|
||||||
rc = -EACCES;
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
tcon->unix_ext = 0; /* server does not support them */
|
|
||||||
|
|
||||||
/* do not care if a following call succeed - informational */
|
|
||||||
if (!tcon->pipe && server->ops->qfs_tcon)
|
|
||||||
server->ops->qfs_tcon(xid, tcon);
|
|
||||||
|
|
||||||
cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
|
|
||||||
cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
|
|
||||||
|
|
||||||
remote_path_check:
|
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
/*
|
/*
|
||||||
* Perform an unconditional check for whether there are DFS
|
* Perform an unconditional check for whether there are DFS
|
||||||
* referrals for this path without prefix, to provide support
|
* referrals for this path without prefix, to provide support
|
||||||
|
@ -4063,119 +4159,100 @@ remote_path_check:
|
||||||
* with PATH_NOT_COVERED to requests that include the prefix.
|
* with PATH_NOT_COVERED to requests that include the prefix.
|
||||||
* Chase the referral if found, otherwise continue normally.
|
* Chase the referral if found, otherwise continue normally.
|
||||||
*/
|
*/
|
||||||
if (referral_walks_count == 0) {
|
old_mountdata = cifs_sb->mountdata;
|
||||||
int refrc = expand_dfs_referral(xid, ses, volume_info, cifs_sb,
|
(void)expand_dfs_referral(xid, ses, vol, cifs_sb, false);
|
||||||
false);
|
|
||||||
if (!refrc) {
|
|
||||||
referral_walks_count++;
|
|
||||||
goto try_mount_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* check if a whole path is not remote */
|
if (cifs_sb->mountdata == NULL) {
|
||||||
if (!rc && tcon) {
|
rc = -ENOENT;
|
||||||
if (!server->ops->is_path_accessible) {
|
goto error;
|
||||||
rc = -ENOSYS;
|
}
|
||||||
goto mount_fail_check;
|
|
||||||
|
if (cifs_sb->mountdata != old_mountdata) {
|
||||||
|
/* If we were redirected, reconnect to new target server */
|
||||||
|
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||||
|
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
|
||||||
|
}
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -EACCES || rc == -EOPNOTSUPP)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 1; ;) {
|
||||||
|
if (!rc && tcon) {
|
||||||
|
rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
|
||||||
|
if (!rc || rc != -EREMOTE)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* cifs_build_path_to_root works only when we have a valid tcon
|
* BB: when we implement proper loop detection,
|
||||||
|
* we will remove this check. But now we need it
|
||||||
|
* to prevent an indefinite loop if 'DFS tree' is
|
||||||
|
* misconfigured (i.e. has loops).
|
||||||
*/
|
*/
|
||||||
full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon,
|
if (count++ > MAX_NESTED_LINKS) {
|
||||||
tcon->Flags & SMB_SHARE_IS_IN_DFS);
|
|
||||||
if (full_path == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
|
|
||||||
full_path);
|
|
||||||
if (rc != 0 && rc != -EREMOTE) {
|
|
||||||
kfree(full_path);
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc != -EREMOTE) {
|
|
||||||
rc = cifs_are_all_path_components_accessible(server,
|
|
||||||
xid, tcon, cifs_sb,
|
|
||||||
full_path);
|
|
||||||
if (rc != 0) {
|
|
||||||
cifs_dbg(VFS, "cannot query dirs between root and final path, "
|
|
||||||
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
|
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
|
||||||
rc = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kfree(full_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get referral if needed */
|
|
||||||
if (rc == -EREMOTE) {
|
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
|
||||||
if (referral_walks_count > MAX_NESTED_LINKS) {
|
|
||||||
/*
|
|
||||||
* BB: when we implement proper loop detection,
|
|
||||||
* we will remove this check. But now we need it
|
|
||||||
* to prevent an indefinite loop if 'DFS tree' is
|
|
||||||
* misconfigured (i.e. has loops).
|
|
||||||
*/
|
|
||||||
rc = -ELOOP;
|
rc = -ELOOP;
|
||||||
goto mount_fail_check;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, true);
|
old_mountdata = cifs_sb->mountdata;
|
||||||
|
rc = expand_dfs_referral(xid, tcon->ses, vol, cifs_sb,
|
||||||
|
true);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
|
||||||
if (!rc) {
|
if (cifs_sb->mountdata != old_mountdata) {
|
||||||
referral_walks_count++;
|
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||||
goto try_mount_again;
|
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses,
|
||||||
|
&tcon);
|
||||||
|
}
|
||||||
|
if (rc) {
|
||||||
|
if (rc == -EACCES || rc == -EOPNOTSUPP || !server ||
|
||||||
|
!ses)
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
goto mount_fail_check;
|
|
||||||
#else /* No DFS support, return error on mount */
|
|
||||||
rc = -EOPNOTSUPP;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto mount_fail_check;
|
goto error;
|
||||||
|
|
||||||
/* now, hang the tcon off of the superblock */
|
|
||||||
tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
|
|
||||||
if (tlink == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto mount_fail_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
tlink->tl_uid = ses->linux_uid;
|
|
||||||
tlink->tl_tcon = tcon;
|
|
||||||
tlink->tl_time = jiffies;
|
|
||||||
set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
|
|
||||||
set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
|
|
||||||
|
|
||||||
cifs_sb->master_tlink = tlink;
|
|
||||||
spin_lock(&cifs_sb->tlink_tree_lock);
|
|
||||||
tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
|
|
||||||
spin_unlock(&cifs_sb->tlink_tree_lock);
|
|
||||||
|
|
||||||
queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
|
|
||||||
TLINK_IDLE_EXPIRE);
|
|
||||||
|
|
||||||
mount_fail_check:
|
|
||||||
/* on error free sesinfo and tcon struct if needed */
|
|
||||||
if (rc) {
|
|
||||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
|
||||||
/* up accidentally freeing someone elses tcon struct */
|
|
||||||
if (tcon)
|
|
||||||
cifs_put_tcon(tcon);
|
|
||||||
else if (ses)
|
|
||||||
cifs_put_smb_ses(ses);
|
|
||||||
else
|
|
||||||
cifs_put_tcp_session(server, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free_xid(xid);
|
free_xid(xid);
|
||||||
|
return mount_setup_tlink(cifs_sb, ses, tcon);
|
||||||
|
|
||||||
|
error:
|
||||||
|
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
unsigned int xid;
|
||||||
|
struct cifs_ses *ses;
|
||||||
|
struct cifs_tcon *tcon;
|
||||||
|
struct TCP_Server_Info *server;
|
||||||
|
|
||||||
|
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
|
||||||
|
if (rc)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (tcon) {
|
||||||
|
rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
|
||||||
|
if (rc == -EREMOTE)
|
||||||
|
rc = -EOPNOTSUPP;
|
||||||
|
if (rc)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_xid(xid);
|
||||||
|
|
||||||
|
return mount_setup_tlink(cifs_sb, ses, tcon);
|
||||||
|
|
||||||
|
error:
|
||||||
|
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue a TREE_CONNECT request.
|
* Issue a TREE_CONNECT request.
|
||||||
|
|
Loading…
Add table
Reference in a new issue