summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-13 19:40:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-13 19:40:36 -0500
commitf3996e6ac6e2bd739d8a82cc9acae0653c2d5dca (patch)
tree2804b3df4d592ebe593b5b47dde58d80f9de79fa /fs/cifs
parente75cdf9898132f521df98a3ce1c280a2f85d360a (diff)
parent7b52e2793a58af61b5d349c2c080437a437a4edb (diff)
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull SMB3 updates from Steve French: "A collection of SMB3 patches adding some reliability features (persistent and resilient handles) and improving SMB3 copy offload. I will have some additional patches for SMB3 encryption and SMB3.1.1 signing (important security features), and also for improving SMB3 persistent handle reconnection (setting ChannelSequence number e.g.) that I am still working on but wanted to get this set in since they can stand alone" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: Allow copy offload (CopyChunk) across shares Add resilienthandles mount parm [SMB3] Send durable handle v2 contexts when use of persistent handles required [SMB3] Display persistenthandles in /proc/mounts for SMB3 shares if enabled [SMB3] Enable checking for continuous availability and persistent handle support [SMB3] Add parsing for new mount option controlling persistent handles Allow duplicate extents in SMB3 not just SMB3.1.1
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c16
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/connect.c78
-rw-r--r--fs/cifs/ioctl.c11
-rw-r--r--fs/cifs/smb2file.c19
-rw-r--r--fs/cifs/smb2ops.c10
-rw-r--r--fs/cifs/smb2pdu.c123
-rw-r--r--fs/cifs/smb2pdu.h45
-rw-r--r--fs/cifs/smbfsctl.h2
9 files changed, 287 insertions, 25 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e739950ca084..cbc0f4bca0c0 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -454,6 +454,10 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
454 seq_puts(s, ",nocase"); 454 seq_puts(s, ",nocase");
455 if (tcon->retry) 455 if (tcon->retry)
456 seq_puts(s, ",hard"); 456 seq_puts(s, ",hard");
457 if (tcon->use_persistent)
458 seq_puts(s, ",persistenthandles");
459 else if (tcon->use_resilient)
460 seq_puts(s, ",resilienthandles");
457 if (tcon->unix_ext) 461 if (tcon->unix_ext)
458 seq_puts(s, ",unix"); 462 seq_puts(s, ",unix");
459 else 463 else
@@ -921,9 +925,7 @@ const struct file_operations cifs_file_ops = {
921 .mmap = cifs_file_mmap, 925 .mmap = cifs_file_mmap,
922 .splice_read = generic_file_splice_read, 926 .splice_read = generic_file_splice_read,
923 .llseek = cifs_llseek, 927 .llseek = cifs_llseek,
924#ifdef CONFIG_CIFS_POSIX
925 .unlocked_ioctl = cifs_ioctl, 928 .unlocked_ioctl = cifs_ioctl,
926#endif /* CONFIG_CIFS_POSIX */
927 .setlease = cifs_setlease, 929 .setlease = cifs_setlease,
928 .fallocate = cifs_fallocate, 930 .fallocate = cifs_fallocate,
929}; 931};
@@ -939,9 +941,7 @@ const struct file_operations cifs_file_strict_ops = {
939 .mmap = cifs_file_strict_mmap, 941 .mmap = cifs_file_strict_mmap,
940 .splice_read = generic_file_splice_read, 942 .splice_read = generic_file_splice_read,
941 .llseek = cifs_llseek, 943 .llseek = cifs_llseek,
942#ifdef CONFIG_CIFS_POSIX
943 .unlocked_ioctl = cifs_ioctl, 944 .unlocked_ioctl = cifs_ioctl,
944#endif /* CONFIG_CIFS_POSIX */
945 .setlease = cifs_setlease, 945 .setlease = cifs_setlease,
946 .fallocate = cifs_fallocate, 946 .fallocate = cifs_fallocate,
947}; 947};
@@ -957,9 +957,7 @@ const struct file_operations cifs_file_direct_ops = {
957 .flush = cifs_flush, 957 .flush = cifs_flush,
958 .mmap = cifs_file_mmap, 958 .mmap = cifs_file_mmap,
959 .splice_read = generic_file_splice_read, 959 .splice_read = generic_file_splice_read,
960#ifdef CONFIG_CIFS_POSIX
961 .unlocked_ioctl = cifs_ioctl, 960 .unlocked_ioctl = cifs_ioctl,
962#endif /* CONFIG_CIFS_POSIX */
963 .llseek = cifs_llseek, 961 .llseek = cifs_llseek,
964 .setlease = cifs_setlease, 962 .setlease = cifs_setlease,
965 .fallocate = cifs_fallocate, 963 .fallocate = cifs_fallocate,
@@ -975,9 +973,7 @@ const struct file_operations cifs_file_nobrl_ops = {
975 .mmap = cifs_file_mmap, 973 .mmap = cifs_file_mmap,
976 .splice_read = generic_file_splice_read, 974 .splice_read = generic_file_splice_read,
977 .llseek = cifs_llseek, 975 .llseek = cifs_llseek,
978#ifdef CONFIG_CIFS_POSIX
979 .unlocked_ioctl = cifs_ioctl, 976 .unlocked_ioctl = cifs_ioctl,
980#endif /* CONFIG_CIFS_POSIX */
981 .setlease = cifs_setlease, 977 .setlease = cifs_setlease,
982 .fallocate = cifs_fallocate, 978 .fallocate = cifs_fallocate,
983}; 979};
@@ -992,9 +988,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
992 .mmap = cifs_file_strict_mmap, 988 .mmap = cifs_file_strict_mmap,
993 .splice_read = generic_file_splice_read, 989 .splice_read = generic_file_splice_read,
994 .llseek = cifs_llseek, 990 .llseek = cifs_llseek,
995#ifdef CONFIG_CIFS_POSIX
996 .unlocked_ioctl = cifs_ioctl, 991 .unlocked_ioctl = cifs_ioctl,
997#endif /* CONFIG_CIFS_POSIX */
998 .setlease = cifs_setlease, 992 .setlease = cifs_setlease,
999 .fallocate = cifs_fallocate, 993 .fallocate = cifs_fallocate,
1000}; 994};
@@ -1009,9 +1003,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
1009 .flush = cifs_flush, 1003 .flush = cifs_flush,
1010 .mmap = cifs_file_mmap, 1004 .mmap = cifs_file_mmap,
1011 .splice_read = generic_file_splice_read, 1005 .splice_read = generic_file_splice_read,
1012#ifdef CONFIG_CIFS_POSIX
1013 .unlocked_ioctl = cifs_ioctl, 1006 .unlocked_ioctl = cifs_ioctl,
1014#endif /* CONFIG_CIFS_POSIX */
1015 .llseek = cifs_llseek, 1007 .llseek = cifs_llseek,
1016 .setlease = cifs_setlease, 1008 .setlease = cifs_setlease,
1017 .fallocate = cifs_fallocate, 1009 .fallocate = cifs_fallocate,
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b406a32deb1f..2b510c537a0d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -493,7 +493,10 @@ struct smb_vol {
493 bool mfsymlinks:1; /* use Minshall+French Symlinks */ 493 bool mfsymlinks:1; /* use Minshall+French Symlinks */
494 bool multiuser:1; 494 bool multiuser:1;
495 bool rwpidforward:1; /* pid forward for read/write operations */ 495 bool rwpidforward:1; /* pid forward for read/write operations */
496 bool nosharesock; 496 bool nosharesock:1;
497 bool persistent:1;
498 bool nopersistent:1;
499 bool resilient:1; /* noresilient not required since not fored for CA */
497 unsigned int rsize; 500 unsigned int rsize;
498 unsigned int wsize; 501 unsigned int wsize;
499 bool sockopt_tcp_nodelay:1; 502 bool sockopt_tcp_nodelay:1;
@@ -895,6 +898,8 @@ struct cifs_tcon {
895 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ 898 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
896 bool broken_sparse_sup; /* if server or share does not support sparse */ 899 bool broken_sparse_sup; /* if server or share does not support sparse */
897 bool need_reconnect:1; /* connection reset, tid now invalid */ 900 bool need_reconnect:1; /* connection reset, tid now invalid */
901 bool use_resilient:1; /* use resilient instead of durable handles */
902 bool use_persistent:1; /* use persistent instead of durable handles */
898#ifdef CONFIG_CIFS_SMB2 903#ifdef CONFIG_CIFS_SMB2
899 bool print:1; /* set if connection to printer share */ 904 bool print:1; /* set if connection to printer share */
900 bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */ 905 bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
@@ -1015,6 +1020,7 @@ struct cifs_fid {
1015 __u64 persistent_fid; /* persist file id for smb2 */ 1020 __u64 persistent_fid; /* persist file id for smb2 */
1016 __u64 volatile_fid; /* volatile file id for smb2 */ 1021 __u64 volatile_fid; /* volatile file id for smb2 */
1017 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ 1022 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
1023 __u8 create_guid[16];
1018#endif 1024#endif
1019 struct cifs_pending_open *pending_open; 1025 struct cifs_pending_open *pending_open;
1020 unsigned int epoch; 1026 unsigned int epoch;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 3f2228570d44..ecb0803bdb0e 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -87,6 +87,8 @@ enum {
87 Opt_sign, Opt_seal, Opt_noac, 87 Opt_sign, Opt_seal, Opt_noac,
88 Opt_fsc, Opt_mfsymlinks, 88 Opt_fsc, Opt_mfsymlinks,
89 Opt_multiuser, Opt_sloppy, Opt_nosharesock, 89 Opt_multiuser, Opt_sloppy, Opt_nosharesock,
90 Opt_persistent, Opt_nopersistent,
91 Opt_resilient, Opt_noresilient,
90 92
91 /* Mount options which take numeric value */ 93 /* Mount options which take numeric value */
92 Opt_backupuid, Opt_backupgid, Opt_uid, 94 Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -169,6 +171,10 @@ static const match_table_t cifs_mount_option_tokens = {
169 { Opt_multiuser, "multiuser" }, 171 { Opt_multiuser, "multiuser" },
170 { Opt_sloppy, "sloppy" }, 172 { Opt_sloppy, "sloppy" },
171 { Opt_nosharesock, "nosharesock" }, 173 { Opt_nosharesock, "nosharesock" },
174 { Opt_persistent, "persistenthandles"},
175 { Opt_nopersistent, "nopersistenthandles"},
176 { Opt_resilient, "resilienthandles"},
177 { Opt_noresilient, "noresilienthandles"},
172 178
173 { Opt_backupuid, "backupuid=%s" }, 179 { Opt_backupuid, "backupuid=%s" },
174 { Opt_backupgid, "backupgid=%s" }, 180 { Opt_backupgid, "backupgid=%s" },
@@ -1497,6 +1503,33 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1497 case Opt_nosharesock: 1503 case Opt_nosharesock:
1498 vol->nosharesock = true; 1504 vol->nosharesock = true;
1499 break; 1505 break;
1506 case Opt_nopersistent:
1507 vol->nopersistent = true;
1508 if (vol->persistent) {
1509 cifs_dbg(VFS,
1510 "persistenthandles mount options conflict\n");
1511 goto cifs_parse_mount_err;
1512 }
1513 break;
1514 case Opt_persistent:
1515 vol->persistent = true;
1516 if ((vol->nopersistent) || (vol->resilient)) {
1517 cifs_dbg(VFS,
1518 "persistenthandles mount options conflict\n");
1519 goto cifs_parse_mount_err;
1520 }
1521 break;
1522 case Opt_resilient:
1523 vol->resilient = true;
1524 if (vol->persistent) {
1525 cifs_dbg(VFS,
1526 "persistenthandles mount options conflict\n");
1527 goto cifs_parse_mount_err;
1528 }
1529 break;
1530 case Opt_noresilient:
1531 vol->resilient = false; /* already the default */
1532 break;
1500 1533
1501 /* Numeric Values */ 1534 /* Numeric Values */
1502 case Opt_backupuid: 1535 case Opt_backupuid:
@@ -2655,6 +2688,42 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
2655 cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags); 2688 cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
2656 } 2689 }
2657 tcon->seal = volume_info->seal; 2690 tcon->seal = volume_info->seal;
2691 tcon->use_persistent = false;
2692 /* check if SMB2 or later, CIFS does not support persistent handles */
2693 if (volume_info->persistent) {
2694 if (ses->server->vals->protocol_id == 0) {
2695 cifs_dbg(VFS,
2696 "SMB3 or later required for persistent handles\n");
2697 rc = -EOPNOTSUPP;
2698 goto out_fail;
2699#ifdef CONFIG_CIFS_SMB2
2700 } else if (ses->server->capabilities &
2701 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
2702 tcon->use_persistent = true;
2703 else /* persistent handles requested but not supported */ {
2704 cifs_dbg(VFS,
2705 "Persistent handles not supported on share\n");
2706 rc = -EOPNOTSUPP;
2707 goto out_fail;
2708#endif /* CONFIG_CIFS_SMB2 */
2709 }
2710#ifdef CONFIG_CIFS_SMB2
2711 } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
2712 && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
2713 && (volume_info->nopersistent == false)) {
2714 cifs_dbg(FYI, "enabling persistent handles\n");
2715 tcon->use_persistent = true;
2716#endif /* CONFIG_CIFS_SMB2 */
2717 } else if (volume_info->resilient) {
2718 if (ses->server->vals->protocol_id == 0) {
2719 cifs_dbg(VFS,
2720 "SMB2.1 or later required for resilient handles\n");
2721 rc = -EOPNOTSUPP;
2722 goto out_fail;
2723 }
2724 tcon->use_resilient = true;
2725 }
2726
2658 /* 2727 /*
2659 * We can have only one retry value for a connection to a share so for 2728 * We can have only one retry value for a connection to a share so for
2660 * resources mounted more than once to the same server share the last 2729 * resources mounted more than once to the same server share the last
@@ -3503,6 +3572,15 @@ try_mount_again:
3503 goto mount_fail_check; 3572 goto mount_fail_check;
3504 } 3573 }
3505 3574
3575#ifdef CONFIG_CIFS_SMB2
3576 if ((volume_info->persistent == true) && ((ses->server->capabilities &
3577 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) == 0)) {
3578 cifs_dbg(VFS, "persistent handles not supported by server\n");
3579 rc = -EOPNOTSUPP;
3580 goto mount_fail_check;
3581 }
3582#endif /* CONFIG_CIFS_SMB2*/
3583
3506 /* search for existing tcon to this server share */ 3584 /* search for existing tcon to this server share */
3507 tcon = cifs_get_tcon(ses, volume_info); 3585 tcon = cifs_get_tcon(ses, volume_info);
3508 if (IS_ERR(tcon)) { 3586 if (IS_ERR(tcon)) {
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 28a77bf1d559..35cf990f87d3 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -85,9 +85,14 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
85 src_tcon = tlink_tcon(smb_file_src->tlink); 85 src_tcon = tlink_tcon(smb_file_src->tlink);
86 target_tcon = tlink_tcon(smb_file_target->tlink); 86 target_tcon = tlink_tcon(smb_file_target->tlink);
87 87
88 /* check if source and target are on same tree connection */ 88 /* check source and target on same server (or volume if dup_extents) */
89 if (src_tcon != target_tcon) { 89 if (dup_extents && (src_tcon != target_tcon)) {
90 cifs_dbg(VFS, "file copy src and target on different volume\n"); 90 cifs_dbg(VFS, "source and target of copy not on same share\n");
91 goto out_fput;
92 }
93
94 if (!dup_extents && (src_tcon->ses != target_tcon->ses)) {
95 cifs_dbg(VFS, "source and target of copy not on same server\n");
91 goto out_fput; 96 goto out_fput;
92 } 97 }
93 98
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 2ab297dae5a7..f9e766f464be 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -43,6 +43,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
43 struct smb2_file_all_info *smb2_data = NULL; 43 struct smb2_file_all_info *smb2_data = NULL;
44 __u8 smb2_oplock[17]; 44 __u8 smb2_oplock[17];
45 struct cifs_fid *fid = oparms->fid; 45 struct cifs_fid *fid = oparms->fid;
46 struct network_resiliency_req nr_ioctl_req;
46 47
47 smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); 48 smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
48 if (smb2_path == NULL) { 49 if (smb2_path == NULL) {
@@ -67,6 +68,24 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
67 if (rc) 68 if (rc)
68 goto out; 69 goto out;
69 70
71
72 if (oparms->tcon->use_resilient) {
73 nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
74 nr_ioctl_req.Reserved = 0;
75 rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
76 fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true,
77 (char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
78 NULL, NULL /* no return info */);
79 if (rc == -EOPNOTSUPP) {
80 cifs_dbg(VFS,
81 "resiliency not supported by server, disabling\n");
82 oparms->tcon->use_resilient = false;
83 } else if (rc)
84 cifs_dbg(FYI, "error %d setting resiliency\n", rc);
85
86 rc = 0;
87 }
88
70 if (buf) { 89 if (buf) {
71 /* open response does not have IndexNumber field - get it */ 90 /* open response does not have IndexNumber field - get it */
72 rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid, 91 rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 18da19f4f811..53ccdde6ff18 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -810,7 +810,6 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
810 cfile->fid.volatile_fid, cfile->pid, &eof, false); 810 cfile->fid.volatile_fid, cfile->pid, &eof, false);
811} 811}
812 812
813#ifdef CONFIG_CIFS_SMB311
814static int 813static int
815smb2_duplicate_extents(const unsigned int xid, 814smb2_duplicate_extents(const unsigned int xid,
816 struct cifsFileInfo *srcfile, 815 struct cifsFileInfo *srcfile,
@@ -854,8 +853,6 @@ smb2_duplicate_extents(const unsigned int xid,
854duplicate_extents_out: 853duplicate_extents_out:
855 return rc; 854 return rc;
856} 855}
857#endif /* CONFIG_CIFS_SMB311 */
858
859 856
860static int 857static int
861smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, 858smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
@@ -1703,6 +1700,7 @@ struct smb_version_operations smb30_operations = {
1703 .create_lease_buf = smb3_create_lease_buf, 1700 .create_lease_buf = smb3_create_lease_buf,
1704 .parse_lease_buf = smb3_parse_lease_buf, 1701 .parse_lease_buf = smb3_parse_lease_buf,
1705 .clone_range = smb2_clone_range, 1702 .clone_range = smb2_clone_range,
1703 .duplicate_extents = smb2_duplicate_extents,
1706 .validate_negotiate = smb3_validate_negotiate, 1704 .validate_negotiate = smb3_validate_negotiate,
1707 .wp_retry_size = smb2_wp_retry_size, 1705 .wp_retry_size = smb2_wp_retry_size,
1708 .dir_needs_close = smb2_dir_needs_close, 1706 .dir_needs_close = smb2_dir_needs_close,
@@ -1840,7 +1838,7 @@ struct smb_version_values smb21_values = {
1840struct smb_version_values smb30_values = { 1838struct smb_version_values smb30_values = {
1841 .version_string = SMB30_VERSION_STRING, 1839 .version_string = SMB30_VERSION_STRING,
1842 .protocol_id = SMB30_PROT_ID, 1840 .protocol_id = SMB30_PROT_ID,
1843 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU, 1841 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
1844 .large_lock_type = 0, 1842 .large_lock_type = 0,
1845 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, 1843 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
1846 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, 1844 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
@@ -1860,7 +1858,7 @@ struct smb_version_values smb30_values = {
1860struct smb_version_values smb302_values = { 1858struct smb_version_values smb302_values = {
1861 .version_string = SMB302_VERSION_STRING, 1859 .version_string = SMB302_VERSION_STRING,
1862 .protocol_id = SMB302_PROT_ID, 1860 .protocol_id = SMB302_PROT_ID,
1863 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU, 1861 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
1864 .large_lock_type = 0, 1862 .large_lock_type = 0,
1865 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, 1863 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
1866 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, 1864 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
@@ -1881,7 +1879,7 @@ struct smb_version_values smb302_values = {
1881struct smb_version_values smb311_values = { 1879struct smb_version_values smb311_values = {
1882 .version_string = SMB311_VERSION_STRING, 1880 .version_string = SMB311_VERSION_STRING,
1883 .protocol_id = SMB311_PROT_ID, 1881 .protocol_id = SMB311_PROT_ID,
1884 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU, 1882 .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
1885 .large_lock_type = 0, 1883 .large_lock_type = 0,
1886 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, 1884 .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
1887 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, 1885 .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 61276929d139..767555518d40 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1151,13 +1151,130 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
1151 return 0; 1151 return 0;
1152} 1152}
1153 1153
1154static struct create_durable_v2 *
1155create_durable_v2_buf(struct cifs_fid *pfid)
1156{
1157 struct create_durable_v2 *buf;
1158
1159 buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
1160 if (!buf)
1161 return NULL;
1162
1163 buf->ccontext.DataOffset = cpu_to_le16(offsetof
1164 (struct create_durable_v2, dcontext));
1165 buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
1166 buf->ccontext.NameOffset = cpu_to_le16(offsetof
1167 (struct create_durable_v2, Name));
1168 buf->ccontext.NameLength = cpu_to_le16(4);
1169
1170 buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
1171 buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
1172 get_random_bytes(buf->dcontext.CreateGuid, 16);
1173 memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
1174
1175 /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
1176 buf->Name[0] = 'D';
1177 buf->Name[1] = 'H';
1178 buf->Name[2] = '2';
1179 buf->Name[3] = 'Q';
1180 return buf;
1181}
1182
1183static struct create_durable_handle_reconnect_v2 *
1184create_reconnect_durable_v2_buf(struct cifs_fid *fid)
1185{
1186 struct create_durable_handle_reconnect_v2 *buf;
1187
1188 buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
1189 GFP_KERNEL);
1190 if (!buf)
1191 return NULL;
1192
1193 buf->ccontext.DataOffset =
1194 cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
1195 dcontext));
1196 buf->ccontext.DataLength =
1197 cpu_to_le32(sizeof(struct durable_reconnect_context_v2));
1198 buf->ccontext.NameOffset =
1199 cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
1200 Name));
1201 buf->ccontext.NameLength = cpu_to_le16(4);
1202
1203 buf->dcontext.Fid.PersistentFileId = fid->persistent_fid;
1204 buf->dcontext.Fid.VolatileFileId = fid->volatile_fid;
1205 buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
1206 memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
1207
1208 /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
1209 buf->Name[0] = 'D';
1210 buf->Name[1] = 'H';
1211 buf->Name[2] = '2';
1212 buf->Name[3] = 'C';
1213 return buf;
1214}
1215
1154static int 1216static int
1155add_durable_context(struct kvec *iov, unsigned int *num_iovec, 1217add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
1156 struct cifs_open_parms *oparms) 1218 struct cifs_open_parms *oparms)
1157{ 1219{
1158 struct smb2_create_req *req = iov[0].iov_base; 1220 struct smb2_create_req *req = iov[0].iov_base;
1159 unsigned int num = *num_iovec; 1221 unsigned int num = *num_iovec;
1160 1222
1223 iov[num].iov_base = create_durable_v2_buf(oparms->fid);
1224 if (iov[num].iov_base == NULL)
1225 return -ENOMEM;
1226 iov[num].iov_len = sizeof(struct create_durable_v2);
1227 if (!req->CreateContextsOffset)
1228 req->CreateContextsOffset =
1229 cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
1230 iov[1].iov_len);
1231 le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
1232 inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2));
1233 *num_iovec = num + 1;
1234 return 0;
1235}
1236
1237static int
1238add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
1239 struct cifs_open_parms *oparms)
1240{
1241 struct smb2_create_req *req = iov[0].iov_base;
1242 unsigned int num = *num_iovec;
1243
1244 /* indicate that we don't need to relock the file */
1245 oparms->reconnect = false;
1246
1247 iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid);
1248 if (iov[num].iov_base == NULL)
1249 return -ENOMEM;
1250 iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
1251 if (!req->CreateContextsOffset)
1252 req->CreateContextsOffset =
1253 cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
1254 iov[1].iov_len);
1255 le32_add_cpu(&req->CreateContextsLength,
1256 sizeof(struct create_durable_handle_reconnect_v2));
1257 inc_rfc1001_len(&req->hdr,
1258 sizeof(struct create_durable_handle_reconnect_v2));
1259 *num_iovec = num + 1;
1260 return 0;
1261}
1262
1263static int
1264add_durable_context(struct kvec *iov, unsigned int *num_iovec,
1265 struct cifs_open_parms *oparms, bool use_persistent)
1266{
1267 struct smb2_create_req *req = iov[0].iov_base;
1268 unsigned int num = *num_iovec;
1269
1270 if (use_persistent) {
1271 if (oparms->reconnect)
1272 return add_durable_reconnect_v2_context(iov, num_iovec,
1273 oparms);
1274 else
1275 return add_durable_v2_context(iov, num_iovec, oparms);
1276 }
1277
1161 if (oparms->reconnect) { 1278 if (oparms->reconnect) {
1162 iov[num].iov_base = create_reconnect_durable_buf(oparms->fid); 1279 iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
1163 /* indicate that we don't need to relock the file */ 1280 /* indicate that we don't need to relock the file */
@@ -1275,7 +1392,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1275 ccontext->Next = 1392 ccontext->Next =
1276 cpu_to_le32(server->vals->create_lease_size); 1393 cpu_to_le32(server->vals->create_lease_size);
1277 } 1394 }
1278 rc = add_durable_context(iov, &num_iovecs, oparms); 1395
1396 rc = add_durable_context(iov, &num_iovecs, oparms,
1397 tcon->use_persistent);
1279 if (rc) { 1398 if (rc) {
1280 cifs_small_buf_release(req); 1399 cifs_small_buf_release(req);
1281 kfree(copy_path); 1400 kfree(copy_path);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 451108284a2f..4af52780ec35 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -590,6 +590,44 @@ struct create_durable {
590 } Data; 590 } Data;
591} __packed; 591} __packed;
592 592
593/* See MS-SMB2 2.2.13.2.11 */
594/* Flags */
595#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
596struct durable_context_v2 {
597 __le32 Timeout;
598 __le32 Flags;
599 __u64 Reserved;
600 __u8 CreateGuid[16];
601} __packed;
602
603struct create_durable_v2 {
604 struct create_context ccontext;
605 __u8 Name[8];
606 struct durable_context_v2 dcontext;
607} __packed;
608
609/* See MS-SMB2 2.2.13.2.12 */
610struct durable_reconnect_context_v2 {
611 struct {
612 __u64 PersistentFileId;
613 __u64 VolatileFileId;
614 } Fid;
615 __u8 CreateGuid[16];
616 __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
617} __packed;
618
619/* See MS-SMB2 2.2.14.2.12 */
620struct durable_reconnect_context_v2_rsp {
621 __le32 Timeout;
622 __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
623} __packed;
624
625struct create_durable_handle_reconnect_v2 {
626 struct create_context ccontext;
627 __u8 Name[8];
628 struct durable_reconnect_context_v2 dcontext;
629} __packed;
630
593#define COPY_CHUNK_RES_KEY_SIZE 24 631#define COPY_CHUNK_RES_KEY_SIZE 24
594struct resume_key_req { 632struct resume_key_req {
595 char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; 633 char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
@@ -643,6 +681,13 @@ struct fsctl_get_integrity_information_rsp {
643/* Integrity flags for above */ 681/* Integrity flags for above */
644#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 682#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001
645 683
684/* See MS-SMB2 2.2.31.3 */
685struct network_resiliency_req {
686 __le32 Timeout;
687 __le32 Reserved;
688} __packed;
689/* There is no buffer for the response ie no struct network_resiliency_rsp */
690
646 691
647struct validate_negotiate_info_req { 692struct validate_negotiate_info_req {
648 __le32 Capabilities; 693 __le32 Capabilities;
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index a639d0dab453..f996daeea271 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -90,7 +90,7 @@
90#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064 90#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064
91/* Retrieve an opaque file reference for server-side data movement ie copy */ 91/* Retrieve an opaque file reference for server-side data movement ie copy */
92#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078 92#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078
93#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ 93#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4
94#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ 94#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
95#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ 95#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
96#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 96#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204