Commit d4fb4bfb authored by Linus Torvalds's avatar Linus Torvalds

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
parents e9a61afb 0fe0781f
...@@ -1891,7 +1891,8 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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));
......
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