diff options
author | Steve French <smfrench@gmail.com> | 2016-11-11 22:36:20 -0600 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2016-12-01 00:23:20 -0600 |
commit | 8b217fe7fcadd162944a88b14990b9723c27419f (patch) | |
tree | 62758e7afa8e799256c362c69ebd15ce43f48c84 /fs/cifs | |
parent | 43c4f67c966deb1478dc9acbf66ab547287d530f (diff) |
SMB3: parsing for new snapshot timestamp mount parm
New mount option "snapshot=<time>" to allow mounting an earlier
version of the remote volume (if such a snapshot exists on
the server).
Note that eventually specifying a snapshot time of 1 will allow
the user to mount the oldest snapshot. A subsequent patch
add the processing for that and another for actually specifying
the "time warp" create context on SMB2/SMB3 open.
Check to make sure SMB2 negotiated, and ensure that
we use a different tcon if mount same share twice
but with different snaphshot times
Signed-off-by: Steve French <smfrench@gmail.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/connect.c | 38 |
2 files changed, 37 insertions, 3 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1f17f6bd7a60..3e95191fcb95 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -525,6 +525,7 @@ struct smb_vol { struct sockaddr_storage srcaddr; /* allow binding to a local IP */ struct nls_table *local_nls; unsigned int echo_interval; /* echo interval in secs */ + __u64 snapshot_time; /* needed for timewarp tokens */ unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ }; @@ -932,6 +933,7 @@ struct cifs_tcon { __u32 maximal_access; __u32 vol_serial_number; __le64 vol_create_time; + __u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */ __u32 ss_flags; /* sector size flags */ __u32 perf_sector_size; /* best sector size for perf */ __u32 max_chunks; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4547aeddd12b..5563de3c64fd 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -95,6 +95,7 @@ enum { Opt_dirmode, Opt_port, Opt_rsize, Opt_wsize, Opt_actimeo, Opt_echo_interval, Opt_max_credits, + Opt_snapshot, /* Mount options which take string value */ Opt_user, Opt_pass, Opt_ip, @@ -191,6 +192,7 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_actimeo, "actimeo=%s" }, { Opt_echo_interval, "echo_interval=%s" }, { Opt_max_credits, "max_credits=%s" }, + { Opt_snapshot, "snapshot=%s" }, { Opt_blank_user, "user=" }, { Opt_blank_user, "username=" }, @@ -1601,6 +1603,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } vol->echo_interval = option; break; + case Opt_snapshot: + if (get_option_ul(args, &option)) { + cifs_dbg(VFS, "%s: Invalid snapshot time\n", + __func__); + goto cifs_parse_mount_err; + } + vol->snapshot_time = option; + break; case Opt_max_credits: if (get_option_ul(args, &option) || (option < 20) || (option > 60000)) { @@ -2586,7 +2596,7 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc) } static struct cifs_tcon * -cifs_find_tcon(struct cifs_ses *ses, const char *unc) +cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) { struct list_head *tmp; struct cifs_tcon *tcon; @@ -2594,8 +2604,14 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc) spin_lock(&cifs_tcp_ses_lock); list_for_each(tmp, &ses->tcon_list) { tcon = list_entry(tmp, struct cifs_tcon, tcon_list); - if (!match_tcon(tcon, unc)) + if (!match_tcon(tcon, volume_info->UNC)) continue; + +#ifdef CONFIG_CIFS_SMB2 + if (tcon->snapshot_time != volume_info->snapshot_time) + continue; +#endif /* CONFIG_CIFS_SMB2 */ + ++tcon->tc_count; spin_unlock(&cifs_tcp_ses_lock); return tcon; @@ -2636,7 +2652,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) int rc, xid; struct cifs_tcon *tcon; - tcon = cifs_find_tcon(ses, volume_info->UNC); + tcon = cifs_find_tcon(ses, volume_info); if (tcon) { cifs_dbg(FYI, "Found match on UNC path\n"); /* existing tcon already has a reference */ @@ -2657,6 +2673,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) goto out_fail; } + if (volume_info->snapshot_time) { +#ifdef CONFIG_CIFS_SMB2 + if (ses->server->vals->protocol_id == 0) { + cifs_dbg(VFS, + "Use SMB2 or later for snapshot mount option\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } else + tcon->snapshot_time = volume_info->snapshot_time; +#else + cifs_dbg(VFS, "Snapshot mount option requires SMB2 support\n"); + rc = -EOPNOTSUPP; + goto out_fail; +#endif /* CONFIG_CIFS_SMB2 */ + } + tcon->ses = ses; if (volume_info->password) { tcon->password = kstrdup(volume_info->password, GFP_KERNEL); |