SMB3: parsing for new snapshot timestamp mount parm
authorSteve French <smfrench@gmail.com>
Sat, 12 Nov 2016 04:36:20 +0000 (22:36 -0600)
committerSteve French <smfrench@gmail.com>
Thu, 1 Dec 2016 06:23:20 +0000 (00:23 -0600)
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>
fs/cifs/cifsglob.h
fs/cifs/connect.c

index 1f17f6b..3e95191 100644 (file)
@@ -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;
index 4547aed..5563de3 100644 (file)
@@ -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);