aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/connect.c4
-rw-r--r--fs/cifs/smb2file.c24
-rw-r--r--fs/cifs/smb2inode.c3
-rw-r--r--fs/cifs/smb2ops.c34
-rw-r--r--fs/cifs/smb2pdu.c10
-rw-r--r--fs/cifs/smb2proto.h3
7 files changed, 68 insertions, 12 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9adf211ca95..3eb59ed6904 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -328,6 +328,8 @@ struct smb_version_operations {
328 struct cifs_fid *); 328 struct cifs_fid *);
329 /* calculate a size of SMB message */ 329 /* calculate a size of SMB message */
330 unsigned int (*calc_smb_size)(void *); 330 unsigned int (*calc_smb_size)(void *);
331 /* check for STATUS_PENDING and process it in a positive case */
332 bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
331}; 333};
332 334
333struct smb_version_values { 335struct smb_version_values {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c31b30b572e..549409b1c77 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -819,6 +819,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
819 cifs_dump_mem("Bad SMB: ", buf, 819 cifs_dump_mem("Bad SMB: ", buf,
820 min_t(unsigned int, server->total_read, 48)); 820 min_t(unsigned int, server->total_read, 48));
821 821
822 if (server->ops->is_status_pending &&
823 server->ops->is_status_pending(buf, server, length))
824 return -1;
825
822 if (!mid) 826 if (!mid)
823 return length; 827 return length;
824 828
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index a7618dfb771..5ff25e02521 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -34,6 +34,26 @@
34#include "fscache.h" 34#include "fscache.h"
35#include "smb2proto.h" 35#include "smb2proto.h"
36 36
37void
38smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
39{
40 oplock &= 0xFF;
41 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
42 cinode->clientCanCacheAll = true;
43 cinode->clientCanCacheRead = true;
44 cFYI(1, "Exclusive Oplock granted on inode %p",
45 &cinode->vfs_inode);
46 } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
47 cinode->clientCanCacheAll = false;
48 cinode->clientCanCacheRead = true;
49 cFYI(1, "Level II Oplock granted on inode %p",
50 &cinode->vfs_inode);
51 } else {
52 cinode->clientCanCacheAll = false;
53 cinode->clientCanCacheRead = false;
54 }
55}
56
37int 57int
38smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path, 58smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
39 int disposition, int desired_access, int create_options, 59 int disposition, int desired_access, int create_options,
@@ -58,10 +78,11 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
58 } 78 }
59 79
60 desired_access |= FILE_READ_ATTRIBUTES; 80 desired_access |= FILE_READ_ATTRIBUTES;
81 *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
61 82
62 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid, 83 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
63 &fid->volatile_fid, desired_access, disposition, 84 &fid->volatile_fid, desired_access, disposition,
64 0, 0, smb2_data); 85 0, 0, (__u8 *)oplock, smb2_data);
65 if (rc) 86 if (rc)
66 goto out; 87 goto out;
67 88
@@ -79,7 +100,6 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
79 } 100 }
80 101
81out: 102out:
82 *oplock = 0;
83 kfree(smb2_data); 103 kfree(smb2_data);
84 kfree(smb2_path); 104 kfree(smb2_path);
85 return rc; 105 return rc;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1bd6b0f0c10..706482452df 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
47 int rc, tmprc = 0; 47 int rc, tmprc = 0;
48 u64 persistent_fid, volatile_fid; 48 u64 persistent_fid, volatile_fid;
49 __le16 *utf16_path; 49 __le16 *utf16_path;
50 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
50 51
51 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 52 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
52 if (!utf16_path) 53 if (!utf16_path)
@@ -54,7 +55,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
54 55
55 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 56 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
56 desired_access, create_disposition, file_attributes, 57 desired_access, create_disposition, file_attributes,
57 create_options, NULL); 58 create_options, &oplock, NULL);
58 if (rc) { 59 if (rc) {
59 kfree(utf16_path); 60 kfree(utf16_path);
60 return rc; 61 return rc;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0fa086c1b5d..2d88c90ded0 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -23,6 +23,7 @@
23#include "smb2proto.h" 23#include "smb2proto.h"
24#include "cifsproto.h" 24#include "cifsproto.h"
25#include "cifs_debug.h" 25#include "cifs_debug.h"
26#include "smb2status.h"
26 27
27static int 28static int
28change_conf(struct TCP_Server_Info *server) 29change_conf(struct TCP_Server_Info *server)
@@ -207,13 +208,14 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
207 int rc; 208 int rc;
208 __u64 persistent_fid, volatile_fid; 209 __u64 persistent_fid, volatile_fid;
209 __le16 *utf16_path; 210 __le16 *utf16_path;
211 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
210 212
211 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); 213 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
212 if (!utf16_path) 214 if (!utf16_path)
213 return -ENOMEM; 215 return -ENOMEM;
214 216
215 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 217 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
216 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL); 218 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
217 if (rc) { 219 if (rc) {
218 kfree(utf16_path); 220 kfree(utf16_path);
219 return rc; 221 return rc;
@@ -358,10 +360,10 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
358static void 360static void
359smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) 361smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
360{ 362{
361 /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */ 363 struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
362 cfile->fid.persistent_fid = fid->persistent_fid; 364 cfile->fid.persistent_fid = fid->persistent_fid;
363 cfile->fid.volatile_fid = fid->volatile_fid; 365 cfile->fid.volatile_fid = fid->volatile_fid;
364 /* cifs_set_oplock_level(cinode, oplock); */ 366 smb2_set_oplock_level(cinode, oplock);
365 /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */ 367 /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
366} 368}
367 369
@@ -432,6 +434,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
432{ 434{
433 __le16 *utf16_path; 435 __le16 *utf16_path;
434 int rc; 436 int rc;
437 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
435 __u64 persistent_fid, volatile_fid; 438 __u64 persistent_fid, volatile_fid;
436 439
437 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 440 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
@@ -440,7 +443,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
440 443
441 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 444 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
442 FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0, 445 FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
443 NULL); 446 &oplock, NULL);
444 kfree(utf16_path); 447 kfree(utf16_path);
445 if (rc) { 448 if (rc) {
446 cERROR(1, "open dir failed"); 449 cERROR(1, "open dir failed");
@@ -477,6 +480,28 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
477 return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); 480 return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
478} 481}
479 482
483/*
484* If we negotiate SMB2 protocol and get STATUS_PENDING - update
485* the number of credits and return true. Otherwise - return false.
486*/
487static bool
488smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
489{
490 struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
491
492 if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
493 return false;
494
495 if (!length) {
496 spin_lock(&server->req_lock);
497 server->credits += le16_to_cpu(hdr->CreditRequest);
498 spin_unlock(&server->req_lock);
499 wake_up(&server->request_q);
500 }
501
502 return true;
503}
504
480struct smb_version_operations smb21_operations = { 505struct smb_version_operations smb21_operations = {
481 .setup_request = smb2_setup_request, 506 .setup_request = smb2_setup_request,
482 .setup_async_request = smb2_setup_async_request, 507 .setup_async_request = smb2_setup_async_request,
@@ -530,6 +555,7 @@ struct smb_version_operations smb21_operations = {
530 .query_dir_next = smb2_query_dir_next, 555 .query_dir_next = smb2_query_dir_next,
531 .close_dir = smb2_close_dir, 556 .close_dir = smb2_close_dir,
532 .calc_smb_size = smb2_calc_size, 557 .calc_smb_size = smb2_calc_size,
558 .is_status_pending = smb2_is_status_pending,
533}; 559};
534 560
535struct smb_version_values smb21_values = { 561struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 21b3a652e19..e97c256c8a4 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -872,7 +872,7 @@ int
872SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, 872SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
873 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, 873 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
874 __u32 create_disposition, __u32 file_attributes, __u32 create_options, 874 __u32 create_disposition, __u32 file_attributes, __u32 create_options,
875 struct smb2_file_all_info *buf) 875 __u8 *oplock, struct smb2_file_all_info *buf)
876{ 876{
877 struct smb2_create_req *req; 877 struct smb2_create_req *req;
878 struct smb2_create_rsp *rsp; 878 struct smb2_create_rsp *rsp;
@@ -895,9 +895,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
895 if (rc) 895 if (rc)
896 return rc; 896 return rc;
897 897
898 /* if (server->oplocks) 898 if (server->oplocks)
899 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH; 899 req->RequestedOplockLevel = *oplock;
900 else */ 900 else
901 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; 901 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
902 req->ImpersonationLevel = IL_IMPERSONATION; 902 req->ImpersonationLevel = IL_IMPERSONATION;
903 req->DesiredAccess = cpu_to_le32(desired_access); 903 req->DesiredAccess = cpu_to_le32(desired_access);
@@ -954,6 +954,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
954 buf->NumberOfLinks = cpu_to_le32(1); 954 buf->NumberOfLinks = cpu_to_le32(1);
955 buf->DeletePending = 0; 955 buf->DeletePending = 0;
956 } 956 }
957
958 *oplock = rsp->OplockLevel;
957creat_exit: 959creat_exit:
958 free_rsp_buf(resp_buftype, rsp); 960 free_rsp_buf(resp_buftype, rsp);
959 return rc; 961 return rc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 0d29db222a5..d18339fcc8a 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -82,6 +82,7 @@ extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
82 int desired_access, int create_options, 82 int desired_access, int create_options,
83 struct cifs_fid *fid, __u32 *oplock, 83 struct cifs_fid *fid, __u32 *oplock,
84 FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb); 84 FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
85extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
85 86
86/* 87/*
87 * SMB2 Worker functions - most of protocol specific implementation details 88 * SMB2 Worker functions - most of protocol specific implementation details
@@ -99,7 +100,7 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
99 __le16 *path, u64 *persistent_fid, u64 *volatile_fid, 100 __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
100 __u32 desired_access, __u32 create_disposition, 101 __u32 desired_access, __u32 create_disposition,
101 __u32 file_attributes, __u32 create_options, 102 __u32 file_attributes, __u32 create_options,
102 struct smb2_file_all_info *buf); 103 __u8 *oplock, struct smb2_file_all_info *buf);
103extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 104extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
104 u64 persistent_file_id, u64 volatile_file_id); 105 u64 persistent_file_id, u64 volatile_file_id);
105extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, 106extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,