diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-13 19:40:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-13 19:40:36 -0500 |
commit | f3996e6ac6e2bd739d8a82cc9acae0653c2d5dca (patch) | |
tree | 2804b3df4d592ebe593b5b47dde58d80f9de79fa /fs/cifs | |
parent | e75cdf9898132f521df98a3ce1c280a2f85d360a (diff) | |
parent | 7b52e2793a58af61b5d349c2c080437a437a4edb (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.c | 16 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/connect.c | 78 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 11 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 19 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 10 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 123 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 45 | ||||
-rw-r--r-- | fs/cifs/smbfsctl.h | 2 |
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 | ||
814 | static int | 813 | static int |
815 | smb2_duplicate_extents(const unsigned int xid, | 814 | smb2_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, | |||
854 | duplicate_extents_out: | 853 | duplicate_extents_out: |
855 | return rc; | 854 | return rc; |
856 | } | 855 | } |
857 | #endif /* CONFIG_CIFS_SMB311 */ | ||
858 | |||
859 | 856 | ||
860 | static int | 857 | static int |
861 | smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, | 858 | smb2_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 = { | |||
1840 | struct smb_version_values smb30_values = { | 1838 | struct 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 = { | |||
1860 | struct smb_version_values smb302_values = { | 1858 | struct 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 = { | |||
1881 | struct smb_version_values smb311_values = { | 1879 | struct 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 | ||
1154 | static struct create_durable_v2 * | ||
1155 | create_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 | |||
1183 | static struct create_durable_handle_reconnect_v2 * | ||
1184 | create_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 | |||
1154 | static int | 1216 | static int |
1155 | add_durable_context(struct kvec *iov, unsigned int *num_iovec, | 1217 | add_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 | |||
1237 | static int | ||
1238 | add_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 | |||
1263 | static int | ||
1264 | add_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 | ||
596 | struct durable_context_v2 { | ||
597 | __le32 Timeout; | ||
598 | __le32 Flags; | ||
599 | __u64 Reserved; | ||
600 | __u8 CreateGuid[16]; | ||
601 | } __packed; | ||
602 | |||
603 | struct 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 */ | ||
610 | struct 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 */ | ||
620 | struct durable_reconnect_context_v2_rsp { | ||
621 | __le32 Timeout; | ||
622 | __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ | ||
623 | } __packed; | ||
624 | |||
625 | struct 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 |
594 | struct resume_key_req { | 632 | struct 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 */ | ||
685 | struct 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 | ||
647 | struct validate_negotiate_info_req { | 692 | struct 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 |