diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a8e9738db691..8c4121da624e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -103,7 +103,7 @@ enum { Opt_cruid, Opt_gid, Opt_file_mode, Opt_dirmode, Opt_port, Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo, - Opt_echo_interval, Opt_max_credits, + Opt_echo_interval, Opt_max_credits, Opt_handletimeout, Opt_snapshot, /* Mount options which take string value */ @@ -208,6 +208,7 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_rsize, "rsize=%s" }, { Opt_wsize, "wsize=%s" }, { Opt_actimeo, "actimeo=%s" }, + { Opt_handletimeout, "handletimeout=%s" }, { Opt_echo_interval, "echo_interval=%s" }, { Opt_max_credits, "max_credits=%s" }, { Opt_snapshot, "snapshot=%s" }, @@ -322,8 +323,6 @@ static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); static void cifs_prune_tlinks(struct work_struct *work); -static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, - const char *devname, bool is_smb3); static char *extract_hostname(const char *unc); /* @@ -565,6 +564,12 @@ cifs_reconnect(struct TCP_Server_Info *server) mid_entry->callback(mid_entry); } + if (cifs_rdma_enabled(server)) { + mutex_lock(&server->srv_mutex); + smbd_destroy(server); + mutex_unlock(&server->srv_mutex); + } + do { try_to_freeze(); @@ -930,10 +935,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) wake_up_all(&server->request_q); /* give those requests time to exit */ msleep(125); - if (cifs_rdma_enabled(server) && server->smbd_conn) { - smbd_destroy(server->smbd_conn); - server->smbd_conn = NULL; - } + if (cifs_rdma_enabled(server)) + smbd_destroy(server); if (server->ssocket) { sock_release(server->ssocket); server->ssocket = NULL; @@ -1619,6 +1622,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, vol->actimeo = CIFS_DEF_ACTIMEO; + /* Most clients set timeout to 0, allows server to use its default */ + vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ + /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ vol->ops = &smb30_operations; vol->vals = &smbdefault_values; @@ -2017,6 +2023,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } break; + case Opt_handletimeout: + if (get_option_ul(args, &option)) { + cifs_dbg(VFS, "%s: Invalid handletimeout value\n", + __func__); + goto cifs_parse_mount_err; + } + vol->handle_timeout = option; + if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { + cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); + goto cifs_parse_mount_err; + } + break; case Opt_echo_interval: if (get_option_ul(args, &option)) { cifs_dbg(VFS, "%s: Invalid echo interval value\n", @@ -2428,6 +2446,10 @@ match_port(struct TCP_Server_Info *server, struct sockaddr *addr) { __be16 port, *sport; + /* SMBDirect manages its own ports, don't match it here */ + if (server->rdma) + return true; + switch (addr->sa_family) { case AF_INET: sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; @@ -2888,8 +2910,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) return NULL; } -static void -cifs_put_smb_ses(struct cifs_ses *ses) +void cifs_put_smb_ses(struct cifs_ses *ses) { unsigned int rc, xid; struct TCP_Server_Info *server = ses->server; @@ -3066,7 +3087,7 @@ cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), * already got a server reference (server refcount +1). See * cifs_get_tcon() for refcount explanations. */ -static struct cifs_ses * +struct cifs_ses * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) { int rc = -ENOMEM; @@ -3183,6 +3204,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info) return 0; if (tcon->snapshot_time != volume_info->snapshot_time) return 0; + if (tcon->handle_timeout != volume_info->handle_timeout) + return 0; return 1; } @@ -3297,6 +3320,16 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) tcon->snapshot_time = volume_info->snapshot_time; } + if (volume_info->handle_timeout) { + if (ses->server->vals->protocol_id == 0) { + cifs_dbg(VFS, + "Use SMB2.1 or later for handle timeout option\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } else + tcon->handle_timeout = volume_info->handle_timeout; + } + tcon->ses = ses; if (volume_info->password) { tcon->password = kstrdup(volume_info->password, GFP_KERNEL); @@ -4361,7 +4394,7 @@ static int mount_do_dfs_failover(const char *path, } #endif -static int +int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, const char *devname, bool is_smb3) { @@ -4515,7 +4548,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) struct cifs_tcon *tcon = NULL; struct TCP_Server_Info *server; char *root_path = NULL, *full_path = NULL; - char *old_mountdata; + char *old_mountdata, *origin_mountdata = NULL; int count; rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); @@ -4574,6 +4607,14 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) goto error; } + /* Save DFS root volume information for DFS refresh worker */ + origin_mountdata = kstrndup(cifs_sb->mountdata, + strlen(cifs_sb->mountdata), GFP_KERNEL); + if (!origin_mountdata) { + rc = -ENOMEM; + goto error; + } + if (cifs_sb->mountdata != old_mountdata) { /* If we were redirected, reconnect to new target server */ mount_put_conns(cifs_sb, xid, server, ses, tcon); @@ -4682,7 +4723,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) } spin_unlock(&cifs_tcp_ses_lock); - rc = dfs_cache_add_vol(vol, cifs_sb->origin_fullpath); + rc = dfs_cache_add_vol(origin_mountdata, vol, cifs_sb->origin_fullpath); if (rc) { kfree(cifs_sb->origin_fullpath); goto error; @@ -4700,6 +4741,7 @@ out: error: kfree(full_path); kfree(root_path); + kfree(origin_mountdata); mount_put_conns(cifs_sb, xid, server, ses, tcon); return rc; } |