aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2013-07-04 10:41:09 -0400
committerSteve French <smfrench@gmail.com>2013-07-10 14:08:39 -0400
commit63eb3def3267a5744863801e8221898b0ba9d41d (patch)
tree7ebc846f2e66303d0b7228ae9cedf498d9bc1999 /fs/cifs
parentd22cbfecbd9047465d9067a6eedc43434c888593 (diff)
CIFS: Request durable open for SMB2 opens
by passing durable context together with a handle caching lease or batch oplock. Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steven French <steven@steven-GA-970A-DS3.(none)>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/smb2file.c2
-rw-r--r--fs/cifs/smb2pdu.c62
-rw-r--r--fs/cifs/smb2pdu.h6
3 files changed, 68 insertions, 2 deletions
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 46a4299b7ae8..150a9b1bc7fa 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -81,7 +81,7 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
81 } 81 }
82 82
83 desired_access |= FILE_READ_ATTRIBUTES; 83 desired_access |= FILE_READ_ATTRIBUTES;
84 *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 84 *smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
85 85
86 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) 86 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
87 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE); 87 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e65ccdb528cf..140a613073fb 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -847,6 +847,28 @@ create_lease_buf(u8 *lease_key, u8 oplock)
847 return buf; 847 return buf;
848} 848}
849 849
850static struct create_durable *
851create_durable_buf(void)
852{
853 struct create_durable *buf;
854
855 buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
856 if (!buf)
857 return NULL;
858
859 buf->ccontext.DataOffset = cpu_to_le16(offsetof
860 (struct create_durable, Reserved));
861 buf->ccontext.DataLength = cpu_to_le32(16);
862 buf->ccontext.NameOffset = cpu_to_le16(offsetof
863 (struct create_durable, Name));
864 buf->ccontext.NameLength = cpu_to_le16(4);
865 buf->Name[0] = 'D';
866 buf->Name[1] = 'H';
867 buf->Name[2] = 'n';
868 buf->Name[3] = 'Q';
869 return buf;
870}
871
850static __u8 872static __u8
851parse_lease_state(struct smb2_create_rsp *rsp) 873parse_lease_state(struct smb2_create_rsp *rsp)
852{ 874{
@@ -901,6 +923,28 @@ add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock)
901 return 0; 923 return 0;
902} 924}
903 925
926static int
927add_durable_context(struct kvec *iov, unsigned int *num_iovec)
928{
929 struct smb2_create_req *req = iov[0].iov_base;
930 unsigned int num = *num_iovec;
931
932 iov[num].iov_base = create_durable_buf();
933 if (iov[num].iov_base == NULL)
934 return -ENOMEM;
935 iov[num].iov_len = sizeof(struct create_durable);
936 if (!req->CreateContextsOffset)
937 req->CreateContextsOffset =
938 cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
939 iov[1].iov_len);
940 req->CreateContextsLength =
941 cpu_to_le32(le32_to_cpu(req->CreateContextsLength) +
942 sizeof(struct create_durable));
943 inc_rfc1001_len(&req->hdr, sizeof(struct create_durable));
944 *num_iovec = num + 1;
945 return 0;
946}
947
904int 948int
905SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, 949SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
906 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, 950 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
@@ -911,7 +955,7 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
911 struct smb2_create_rsp *rsp; 955 struct smb2_create_rsp *rsp;
912 struct TCP_Server_Info *server; 956 struct TCP_Server_Info *server;
913 struct cifs_ses *ses = tcon->ses; 957 struct cifs_ses *ses = tcon->ses;
914 struct kvec iov[3]; 958 struct kvec iov[4];
915 int resp_buftype; 959 int resp_buftype;
916 int uni_path_len; 960 int uni_path_len;
917 __le16 *copy_path = NULL; 961 __le16 *copy_path = NULL;
@@ -987,6 +1031,22 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
987 } 1031 }
988 } 1032 }
989 1033
1034 if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
1035 /* need to set Next field of lease context if we request it */
1036 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
1037 struct create_context *ccontext =
1038 (struct create_context *)iov[num_iovecs-1].iov_base;
1039 ccontext->Next = sizeof(struct create_lease);
1040 }
1041 rc = add_durable_context(iov, &num_iovecs);
1042 if (rc) {
1043 cifs_small_buf_release(req);
1044 kfree(copy_path);
1045 kfree(iov[num_iovecs-1].iov_base);
1046 return rc;
1047 }
1048 }
1049
990 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); 1050 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
991 rsp = (struct smb2_create_rsp *)iov[0].iov_base; 1051 rsp = (struct smb2_create_rsp *)iov[0].iov_base;
992 1052
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 8b1025f6f0da..3e30f0ad5749 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -485,6 +485,12 @@ struct create_lease {
485 struct lease_context lcontext; 485 struct lease_context lcontext;
486} __packed; 486} __packed;
487 487
488struct create_durable {
489 struct create_context ccontext;
490 __u8 Name[8];
491 __u8 Reserved[16];
492} __packed;
493
488/* this goes in the ioctl buffer when doing a copychunk request */ 494/* this goes in the ioctl buffer when doing a copychunk request */
489struct copychunk_ioctl { 495struct copychunk_ioctl {
490 char SourceKey[24]; 496 char SourceKey[24];