cifs: add multichannel mount options and data structs

adds:
- [no]multichannel to enable/disable multichannel
- max_channels=N to control how many channels to create

these options are then stored in the volume struct.

- store channels and max_channels in cifs_ses

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Aurelien Aptel 2019-09-20 04:32:20 +02:00 committed by Steve French
parent 35adffed07
commit bcc8880115
3 changed files with 56 additions and 2 deletions

View File

@ -613,6 +613,10 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
/* convert actimeo and display it in seconds */
seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
if (tcon->ses->chan_max > 1)
seq_printf(s, ",multichannel,max_channel=%zu",
tcon->ses->chan_max);
return 0;
}

View File

@ -591,6 +591,10 @@ struct smb_vol {
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
bool rdma:1;
bool multichannel:1;
bool use_client_guid:1;
/* reuse existing guid for multichannel */
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
unsigned int bsize;
unsigned int rsize;
unsigned int wsize;
@ -607,6 +611,7 @@ struct smb_vol {
__u64 snapshot_time; /* needed for timewarp tokens */
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
unsigned int max_channels;
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
bool rootfs:1; /* if it's a SMB root file system */
};
@ -953,6 +958,11 @@ struct cifs_server_iface {
struct sockaddr_storage sockaddr;
};
struct cifs_chan {
struct TCP_Server_Info *server;
__u8 signkey[SMB3_SIGN_KEY_SIZE];
};
/*
* Session structure. One of these for each uid session with a particular host
*/
@ -1002,6 +1012,12 @@ struct cifs_ses {
struct cifs_server_iface *iface_list;
size_t iface_count;
unsigned long iface_last_update; /* jiffies */
#define CIFS_MAX_CHANNELS 16
struct cifs_chan chans[CIFS_MAX_CHANNELS];
size_t chan_count;
size_t chan_max;
atomic_t chan_seq; /* round robin state */
};
static inline bool

View File

@ -97,6 +97,7 @@ enum {
Opt_persistent, Opt_nopersistent,
Opt_resilient, Opt_noresilient,
Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs,
Opt_multichannel, Opt_nomultichannel,
Opt_compress,
/* Mount options which take numeric value */
@ -106,7 +107,7 @@ enum {
Opt_min_enc_offload,
Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
Opt_snapshot,
Opt_snapshot, Opt_max_channels,
/* Mount options which take string value */
Opt_user, Opt_pass, Opt_ip,
@ -199,6 +200,8 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_noresilient, "noresilienthandles"},
{ Opt_domainauto, "domainauto"},
{ Opt_rdma, "rdma"},
{ Opt_multichannel, "multichannel" },
{ Opt_nomultichannel, "nomultichannel" },
{ Opt_backupuid, "backupuid=%s" },
{ Opt_backupgid, "backupgid=%s" },
@ -218,6 +221,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_echo_interval, "echo_interval=%s" },
{ Opt_max_credits, "max_credits=%s" },
{ Opt_snapshot, "snapshot=%s" },
{ Opt_max_channels, "max_channels=%s" },
{ Opt_compress, "compress=%s" },
{ Opt_blank_user, "user=" },
@ -1681,6 +1685,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
/* default to no multichannel (single server connection) */
vol->multichannel = false;
vol->max_channels = 1;
if (!mountdata)
goto cifs_parse_mount_err;
@ -1974,6 +1982,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
case Opt_rdma:
vol->rdma = true;
break;
case Opt_multichannel:
vol->multichannel = true;
break;
case Opt_nomultichannel:
vol->multichannel = false;
break;
case Opt_compress:
vol->compression = UNKNOWN_TYPE;
cifs_dbg(VFS,
@ -2137,6 +2151,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
}
vol->max_credits = option;
break;
case Opt_max_channels:
if (get_option_ul(args, &option) || option < 1 ||
option > CIFS_MAX_CHANNELS) {
cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n",
__func__, CIFS_MAX_CHANNELS);
goto cifs_parse_mount_err;
}
vol->max_channels = option;
break;
/* String Arguments */
@ -2781,7 +2804,11 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
sizeof(tcp_ses->dstaddr));
generate_random_uuid(tcp_ses->client_guid);
if (volume_info->use_client_guid)
memcpy(tcp_ses->client_guid, volume_info->client_guid,
SMB2_CLIENT_GUID_SIZE);
else
generate_random_uuid(tcp_ses->client_guid);
/*
* at this point we are the only ones with the pointer
* to the struct since the kernel thread not created yet
@ -2870,6 +2897,13 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
vol->sectype != ses->sectype)
return 0;
/*
* If an existing session is limited to less channels than
* requested, it should not be reused
*/
if (ses->chan_max < vol->max_channels)
return 0;
switch (ses->sectype) {
case Kerberos:
if (!uid_eq(vol->cred_uid, ses->cred_uid))