Five cifs/smb3 fixes, 3 for DFS, one for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl6lIA4ACgkQiiy9cAdy T1FI6QwAg4mCQPvqebKd0/OaJAPne/dzS+iDpxGhCHWjyRYfXwttSHj6HTDjbb20 OMrvOpKR4plV8LQOXyzbI7rJvDcL1UFbcBxUQUEp9I7BuVbKhE/7CWcBPc2bMiKF 1yJhUHUjsSMP35H4f3w8J+eKzXcJnXljsruI61FVn4kagRzsUrTOfyhtdfcobPHA 0o0eZPPhAmoN2Vaf8jpVDEECHotbIKRr6hwN4/lPiOjVvqmHbi42RFmn06rlKqWA FBJqYKHK9VyL6458nTego5BXoJ4DSVf28Ow367sYFekpqA2eENfKRIHZ/feBzTH+ GOn44GJqMcpMXkGgMuR7qMk8wi+nYTBrGXgpXjD3Yw/mHLiPbmscrudwZ30HQ5Rr 1tgEgFd064gCzA/sm8MmAzSo5Du9oGyabuDewoatKHztNLZA9jMCO/kvuYoCtnLW vwlPcnedl4fUir3sdzU9JwHxhcoiAREktqQCXWVew9FGedvdfxVDuPMejayrND9k KK6zbll3 =x+F1 -----END PGP SIGNATURE----- Merge tag '5.7-rc2-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs fixes from Steve French: "Five cifs/smb3 fixes:two for DFS reconnect failover, one lease fix for stable and the others to fix a missing spinlock during reconnect" * tag '5.7-rc2-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: fix uninitialised lease_key in open_shroot() cifs: ensure correct super block for DFS reconnect cifs: do not share tcons with DFS cifs: minor update to comments around the cifs_tcp_ses_lock mutex cifs: protect updating server->dstaddr with a spinlock
This commit is contained in:
commit
d4fb4bfb37
|
@ -1891,7 +1891,8 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
|
||||||
/*
|
/*
|
||||||
* This lock protects the cifs_tcp_ses_list, the list of smb sessions per
|
* This lock protects the cifs_tcp_ses_list, the list of smb sessions per
|
||||||
* tcp session, and the list of tcon's per smb session. It also protects
|
* tcp session, and the list of tcon's per smb session. It also protects
|
||||||
* the reference counters for the server, smb session, and tcon. Finally,
|
* the reference counters for the server, smb session, and tcon. It also
|
||||||
|
* protects some fields in the TCP_Server_Info struct such as dstaddr. Finally,
|
||||||
* changes to the tcon->tidStatus should be done while holding this lock.
|
* changes to the tcon->tidStatus should be done while holding this lock.
|
||||||
* generally the locks should be taken in order tcp_ses_lock before
|
* generally the locks should be taken in order tcp_ses_lock before
|
||||||
* tcon->open_file_lock and that before file->file_info_lock since the
|
* tcon->open_file_lock and that before file->file_info_lock since the
|
||||||
|
|
|
@ -375,8 +375,10 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
|
rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
|
||||||
strlen(ipaddr));
|
strlen(ipaddr));
|
||||||
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
kfree(ipaddr);
|
kfree(ipaddr);
|
||||||
|
|
||||||
return !rc ? -1 : 0;
|
return !rc ? -1 : 0;
|
||||||
|
@ -3373,6 +3375,10 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
list_for_each(tmp, &ses->tcon_list) {
|
list_for_each(tmp, &ses->tcon_list) {
|
||||||
tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
|
tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
if (tcon->dfs_path)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
if (!match_tcon(tcon, volume_info))
|
if (!match_tcon(tcon, volume_info))
|
||||||
continue;
|
continue;
|
||||||
++tcon->tc_count;
|
++tcon->tc_count;
|
||||||
|
|
|
@ -1025,51 +1025,99 @@ int copy_path_name(char *dst, const char *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct super_cb_data {
|
struct super_cb_data {
|
||||||
struct TCP_Server_Info *server;
|
void *data;
|
||||||
struct super_block *sb;
|
struct super_block *sb;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void super_cb(struct super_block *sb, void *arg)
|
static void tcp_super_cb(struct super_block *sb, void *arg)
|
||||||
{
|
{
|
||||||
struct super_cb_data *d = arg;
|
struct super_cb_data *sd = arg;
|
||||||
|
struct TCP_Server_Info *server = sd->data;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
|
|
||||||
if (d->sb)
|
if (sd->sb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(sb);
|
cifs_sb = CIFS_SB(sb);
|
||||||
tcon = cifs_sb_master_tcon(cifs_sb);
|
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
if (tcon->ses->server == d->server)
|
if (tcon->ses->server == server)
|
||||||
d->sb = sb;
|
sd->sb = sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
|
static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *),
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct super_cb_data d = {
|
struct super_cb_data sd = {
|
||||||
.server = server,
|
.data = data,
|
||||||
.sb = NULL,
|
.sb = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
iterate_supers_type(&cifs_fs_type, super_cb, &d);
|
iterate_supers_type(&cifs_fs_type, f, &sd);
|
||||||
|
|
||||||
if (unlikely(!d.sb))
|
if (!sd.sb)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-EINVAL);
|
||||||
/*
|
/*
|
||||||
* Grab an active reference in order to prevent automounts (DFS links)
|
* Grab an active reference in order to prevent automounts (DFS links)
|
||||||
* of expiring and then freeing up our cifs superblock pointer while
|
* of expiring and then freeing up our cifs superblock pointer while
|
||||||
* we're doing failover.
|
* we're doing failover.
|
||||||
*/
|
*/
|
||||||
cifs_sb_active(d.sb);
|
cifs_sb_active(sd.sb);
|
||||||
return d.sb;
|
return sd.sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cifs_put_tcp_super(struct super_block *sb)
|
static void __cifs_put_super(struct super_block *sb)
|
||||||
{
|
{
|
||||||
if (!IS_ERR_OR_NULL(sb))
|
if (!IS_ERR_OR_NULL(sb))
|
||||||
cifs_sb_deactive(sb);
|
cifs_sb_deactive(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
|
||||||
|
{
|
||||||
|
return __cifs_get_super(tcp_super_cb, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cifs_put_tcp_super(struct super_block *sb)
|
||||||
|
{
|
||||||
|
__cifs_put_super(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
static void tcon_super_cb(struct super_block *sb, void *arg)
|
||||||
|
{
|
||||||
|
struct super_cb_data *sd = arg;
|
||||||
|
struct cifs_tcon *tcon = sd->data;
|
||||||
|
struct cifs_sb_info *cifs_sb;
|
||||||
|
|
||||||
|
if (sd->sb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cifs_sb = CIFS_SB(sb);
|
||||||
|
if (tcon->dfs_path && cifs_sb->origin_fullpath &&
|
||||||
|
!strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
|
||||||
|
sd->sb = sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
return __cifs_get_super(tcon_super_cb, tcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cifs_put_tcon_super(struct super_block *sb)
|
||||||
|
{
|
||||||
|
__cifs_put_super(sb);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cifs_put_tcon_super(struct super_block *sb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
|
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
|
||||||
size_t prefix_len)
|
size_t prefix_len)
|
||||||
{
|
{
|
||||||
|
@ -1077,7 +1125,7 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
sb = cifs_get_tcp_super(tcon->ses->server);
|
sb = cifs_get_tcon_super(tcon);
|
||||||
if (IS_ERR(sb))
|
if (IS_ERR(sb))
|
||||||
return PTR_ERR(sb);
|
return PTR_ERR(sb);
|
||||||
|
|
||||||
|
@ -1099,6 +1147,6 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
|
||||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cifs_put_tcp_super(sb);
|
cifs_put_tcon_super(sb);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -687,6 +687,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
|
||||||
if (smb3_encryption_required(tcon))
|
if (smb3_encryption_required(tcon))
|
||||||
flags |= CIFS_TRANSFORM_REQ;
|
flags |= CIFS_TRANSFORM_REQ;
|
||||||
|
|
||||||
|
if (!server->ops->new_lease_key)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
server->ops->new_lease_key(pfid);
|
||||||
|
|
||||||
memset(rqst, 0, sizeof(rqst));
|
memset(rqst, 0, sizeof(rqst));
|
||||||
resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
|
resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
|
||||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||||
|
|
Loading…
Reference in New Issue