diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2013-07-04 10:41:09 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2013-07-10 14:08:39 -0400 |
commit | 63eb3def3267a5744863801e8221898b0ba9d41d (patch) | |
tree | 7ebc846f2e66303d0b7228ae9cedf498d9bc1999 /fs/cifs | |
parent | d22cbfecbd9047465d9067a6eedc43434c888593 (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.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 62 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 6 |
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 | ||
850 | static struct create_durable * | ||
851 | create_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 | |||
850 | static __u8 | 872 | static __u8 |
851 | parse_lease_state(struct smb2_create_rsp *rsp) | 873 | parse_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 | ||
926 | static int | ||
927 | add_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 | |||
904 | int | 948 | int |
905 | SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, | 949 | SMB2_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 | ||
488 | struct 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 */ |
489 | struct copychunk_ioctl { | 495 | struct copychunk_ioctl { |
490 | char SourceKey[24]; | 496 | char SourceKey[24]; |