CIFS: Store lease state itself rather than a mapped oplock value
authorPavel Shilovsky <pshilovsky@samba.org>
Thu, 5 Sep 2013 12:11:28 +0000 (16:11 +0400)
committerSteve French <smfrench@gmail.com>
Tue, 10 Sep 2013 03:52:05 +0000 (22:52 -0500)
and separate smb20_operations struct.

Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/smb1ops.c
fs/cifs/smb2file.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h

index fe739bd8246d5dc9fcda144ed2e08e57ca50abd8..e87f89f778f47697be02ef99d2dca5a5cc61f9dc 100644 (file)
@@ -367,11 +367,13 @@ struct smb_version_operations {
        /* generate new lease key */
        void (*new_lease_key)(struct cifs_fid *fid);
        int (*generate_signingkey)(struct cifs_ses *);
-       int (*calc_signature)(struct smb_rqst *rqst,
-                                  struct TCP_Server_Info *server);
-       int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
-                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
-                       unsigned int xid);
+       int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
+       int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *,
+                               struct cifs_sb_info *, unsigned int);
+       /* if we can do cache read operations */
+       bool (*is_read_op)(__u32);
+       /* set oplock level for the inode */
+       void (*set_oplock_level)(struct cifsInodeInfo *, __u32);
 };
 
 struct smb_version_values {
@@ -389,7 +391,6 @@ struct smb_version_values {
        unsigned int    cap_unix;
        unsigned int    cap_nt_find;
        unsigned int    cap_large_files;
-       unsigned int    oplock_read;
        __u16           signing_enabled;
        __u16           signing_required;
 };
@@ -1036,6 +1037,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
 #define CIFS_CACHE_WRITE_FLG   4
 
 #define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG)
+#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
 #define CIFS_CACHE_WRITE(cinode) (cinode->oplock & CIFS_CACHE_WRITE_FLG)
 
 /*
@@ -1507,7 +1509,7 @@ extern mempool_t *cifs_mid_poolp;
 extern struct smb_version_operations smb1_operations;
 extern struct smb_version_values smb1_values;
 #define SMB20_VERSION_STRING   "2.0"
-/*extern struct smb_version_operations smb20_operations; */ /* not needed yet */
+extern struct smb_version_operations smb20_operations;
 extern struct smb_version_values smb20_values;
 #define SMB21_VERSION_STRING   "2.1"
 extern struct smb_version_operations smb21_operations;
index 688f48ec9abc6345b50c2877882e8c1a936d6435..a279ffc0bc29577ed447319467b2e92248f09149 100644 (file)
@@ -1116,7 +1116,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
                break;
 #ifdef CONFIG_CIFS_SMB2
        case Smb_20:
-               vol->ops = &smb21_operations; /* currently identical with 2.1 */
+               vol->ops = &smb20_operations;
                vol->vals = &smb20_values;
                break;
        case Smb_21:
index ad14d3c66b25d24abf71c7765fcbc5735534ca66..188b2470b1fbf633d643be1dec0c5b31d9c9d168 100644 (file)
@@ -313,8 +313,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
         * If the server returned a read oplock and we have mandatory brlocks,
         * set oplock level to None.
         */
-       if (oplock == server->vals->oplock_read &&
-                                               cifs_has_mand_locks(cinode)) {
+       if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) {
                cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n");
                oplock = 0;
        }
index 6fd0677915a07a1ef1f5b3ff4cbd648175694bc0..8233b174de3d62c6e5a3223919e83db8f7c57016 100644 (file)
@@ -912,6 +912,12 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
+static bool
+cifs_is_read_op(__u32 oplock)
+{
+       return oplock == OPLOCK_READ;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -977,6 +983,7 @@ struct smb_version_operations smb1_operations = {
        .mand_unlock_range = cifs_unlock_range,
        .push_mand_locks = cifs_push_mandatory_locks,
        .query_mf_symlink = open_query_close_cifs_symlink,
+       .is_read_op = cifs_is_read_op,
 };
 
 struct smb_version_values smb1_values = {
@@ -992,7 +999,6 @@ struct smb_version_values smb1_values = {
        .cap_unix = CAP_UNIX,
        .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
        .cap_large_files = CAP_LARGE_FILES,
-       .oplock_read = OPLOCK_READ,
        .signing_enabled = SECMODE_SIGN_ENABLED,
        .signing_required = SECMODE_SIGN_REQUIRED,
 };
index 4564787dc7d7dbe212189da43872697f130dca01..3f17b455083141c572fac5d88e95e56fbe54f89a 100644 (file)
 #include "fscache.h"
 #include "smb2proto.h"
 
-void
-smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
-{
-       oplock &= 0xFF;
-       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
-               return;
-       if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
-               cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG |
-                                CIFS_CACHE_HANDLE_FLG;
-               cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
-                        &cinode->vfs_inode);
-       } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
-               cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG;
-               cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
-                        &cinode->vfs_inode);
-       } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
-               cinode->oplock = CIFS_CACHE_READ_FLG;
-               cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
-                        &cinode->vfs_inode);
-       } else
-               cinode->oplock = 0;
-}
-
 int
 smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
               __u32 *oplock, FILE_ALL_INFO *buf)
index 8d1a8898fd13e2c3c977fbeb4d74f2eb9dfe2f4f..4aa59b34ec233806b4a94a85ae4435e813eae32b 100644 (file)
@@ -380,23 +380,15 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
 __le32
 smb2_get_lease_state(struct cifsInodeInfo *cinode)
 {
-       if (CIFS_CACHE_WRITE(cinode))
-               return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING;
-       else if (CIFS_CACHE_READ(cinode))
-               return SMB2_LEASE_READ_CACHING;
-       return 0;
-}
+       __le32 lease = 0;
 
-__u8 smb2_map_lease_to_oplock(__le32 lease_state)
-{
-       if (lease_state & SMB2_LEASE_WRITE_CACHING) {
-               if (lease_state & SMB2_LEASE_HANDLE_CACHING)
-                       return SMB2_OPLOCK_LEVEL_BATCH;
-               else
-                       return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
-       } else if (lease_state & SMB2_LEASE_READ_CACHING)
-               return SMB2_OPLOCK_LEVEL_II;
-       return 0;
+       if (CIFS_CACHE_WRITE(cinode))
+               lease |= SMB2_LEASE_WRITE_CACHING;
+       if (CIFS_CACHE_HANDLE(cinode))
+               lease |= SMB2_LEASE_HANDLE_CACHING;
+       if (CIFS_CACHE_READ(cinode))
+               lease |= SMB2_LEASE_READ_CACHING;
+       return lease;
 }
 
 struct smb2_lease_break_work {
@@ -433,7 +425,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
        int ack_req = le32_to_cpu(rsp->Flags &
                                  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
 
-       lease_state = smb2_map_lease_to_oplock(rsp->NewLeaseState);
+       lease_state = le32_to_cpu(rsp->NewLeaseState);
 
        list_for_each(tmp, &tcon->openFileList) {
                cfile = list_entry(tmp, struct cifsFileInfo, tlist);
@@ -447,7 +439,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
                cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
                         le32_to_cpu(rsp->NewLeaseState));
 
-               smb2_set_oplock_level(cinode, lease_state);
+               tcon->ses->server->ops->set_oplock_level(cinode, lease_state);
 
                if (ack_req)
                        cfile->oplock_break_cancelled = false;
@@ -582,7 +574,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
                                else
                                        cfile->oplock_break_cancelled = false;
 
-                               smb2_set_oplock_level(cinode,
+                               server->ops->set_oplock_level(cinode,
                                  rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
 
                                queue_work(cifsiod_wq, &cfile->oplock_break);
index 96c9d3da3f4166d61d0c1697d02dd99a358399bb..4656656d5c0f7b90d7c3a73aba193c548960249e 100644 (file)
@@ -377,9 +377,11 @@ static void
 smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 {
        struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+       struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
+
        cfile->fid.persistent_fid = fid->persistent_fid;
        cfile->fid.volatile_fid = fid->volatile_fid;
-       smb2_set_oplock_level(cinode, oplock);
+       server->ops->set_oplock_level(cinode, oplock);
        cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
 }
 
@@ -648,7 +650,71 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
-struct smb_version_operations smb21_operations = {
+static void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xFF;
+       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
+               return;
+       if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
+               cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG |
+                                CIFS_CACHE_HANDLE_FLG;
+               cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+               cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG;
+               cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+               cinode->oplock = CIFS_CACHE_READ_FLG;
+               cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else
+               cinode->oplock = 0;
+}
+
+static void
+smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       char message[5] = {0};
+
+       oplock &= 0xFF;
+       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
+               return;
+
+       cinode->oplock = 0;
+       if (oplock & SMB2_LEASE_READ_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_READ_FLG;
+               strcat(message, "R");
+       }
+       if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_HANDLE_FLG;
+               strcat(message, "H");
+       }
+       if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_WRITE_FLG;
+               strcat(message, "W");
+       }
+       if (!cinode->oplock)
+               strcat(message, "None");
+       cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
+                &cinode->vfs_inode);
+}
+
+static bool
+smb2_is_read_op(__u32 oplock)
+{
+       return oplock == SMB2_OPLOCK_LEVEL_II;
+}
+
+static bool
+smb21_is_read_op(__u32 oplock)
+{
+       return (oplock & SMB2_LEASE_READ_CACHING_HE) &&
+              !(oplock & SMB2_LEASE_WRITE_CACHING_HE);
+}
+
+struct smb_version_operations smb20_operations = {
        .compare_fids = smb2_compare_fids,
        .setup_request = smb2_setup_request,
        .setup_async_request = smb2_setup_async_request,
@@ -713,8 +779,78 @@ struct smb_version_operations smb21_operations = {
        .set_lease_key = smb2_set_lease_key,
        .new_lease_key = smb2_new_lease_key,
        .calc_signature = smb2_calc_signature,
+       .is_read_op = smb2_is_read_op,
+       .set_oplock_level = smb2_set_oplock_level,
 };
 
+struct smb_version_operations smb21_operations = {
+       .compare_fids = smb2_compare_fids,
+       .setup_request = smb2_setup_request,
+       .setup_async_request = smb2_setup_async_request,
+       .check_receive = smb2_check_receive,
+       .add_credits = smb2_add_credits,
+       .set_credits = smb2_set_credits,
+       .get_credits_field = smb2_get_credits_field,
+       .get_credits = smb2_get_credits,
+       .get_next_mid = smb2_get_next_mid,
+       .read_data_offset = smb2_read_data_offset,
+       .read_data_length = smb2_read_data_length,
+       .map_error = map_smb2_to_linux_error,
+       .find_mid = smb2_find_mid,
+       .check_message = smb2_check_message,
+       .dump_detail = smb2_dump_detail,
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+       .negotiate_rsize = smb2_negotiate_rsize,
+       .sess_setup = SMB2_sess_setup,
+       .logoff = SMB2_logoff,
+       .tree_connect = SMB2_tcon,
+       .tree_disconnect = SMB2_tdis,
+       .is_path_accessible = smb2_is_path_accessible,
+       .can_echo = smb2_can_echo,
+       .echo = SMB2_echo,
+       .query_path_info = smb2_query_path_info,
+       .get_srv_inum = smb2_get_srv_inum,
+       .query_file_info = smb2_query_file_info,
+       .set_path_size = smb2_set_path_size,
+       .set_file_size = smb2_set_file_size,
+       .set_file_info = smb2_set_file_info,
+       .mkdir = smb2_mkdir,
+       .mkdir_setinfo = smb2_mkdir_setinfo,
+       .rmdir = smb2_rmdir,
+       .unlink = smb2_unlink,
+       .rename = smb2_rename_path,
+       .create_hardlink = smb2_create_hardlink,
+       .query_symlink = smb2_query_symlink,
+       .open = smb2_open_file,
+       .set_fid = smb2_set_fid,
+       .close = smb2_close_file,
+       .flush = smb2_flush_file,
+       .async_readv = smb2_async_readv,
+       .async_writev = smb2_async_writev,
+       .sync_read = smb2_sync_read,
+       .sync_write = smb2_sync_write,
+       .query_dir_first = smb2_query_dir_first,
+       .query_dir_next = smb2_query_dir_next,
+       .close_dir = smb2_close_dir,
+       .calc_smb_size = smb2_calc_size,
+       .is_status_pending = smb2_is_status_pending,
+       .oplock_response = smb2_oplock_response,
+       .queryfs = smb2_queryfs,
+       .mand_lock = smb2_mand_lock,
+       .mand_unlock_range = smb2_unlock_range,
+       .push_mand_locks = smb2_push_mandatory_locks,
+       .get_lease_key = smb2_get_lease_key,
+       .set_lease_key = smb2_set_lease_key,
+       .new_lease_key = smb2_new_lease_key,
+       .calc_signature = smb2_calc_signature,
+       .is_read_op = smb21_is_read_op,
+       .set_oplock_level = smb21_set_oplock_level,
+};
 
 struct smb_version_operations smb30_operations = {
        .compare_fids = smb2_compare_fids,
@@ -783,6 +919,8 @@ struct smb_version_operations smb30_operations = {
        .new_lease_key = smb2_new_lease_key,
        .generate_signingkey = generate_smb3signingkey,
        .calc_signature = smb3_calc_signature,
+       .is_read_op = smb21_is_read_op,
+       .set_oplock_level = smb21_set_oplock_level,
 };
 
 struct smb_version_values smb20_values = {
@@ -800,7 +938,6 @@ struct smb_version_values smb20_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
@@ -820,7 +957,6 @@ struct smb_version_values smb21_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
@@ -840,7 +976,6 @@ struct smb_version_values smb30_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
@@ -860,7 +995,6 @@ struct smb_version_values smb302_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
index 0a945828271792cc7d07aeb4c92db6fb4406b2cd..fdf697bcdf9f3d50209998de025364987100ff12 100644 (file)
@@ -963,7 +963,7 @@ parse_lease_state(struct smb2_create_rsp *rsp)
        if (!found)
                return 0;
 
-       return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
+       return le32_to_cpu(lc->lcontext.LeaseState);
 }
 
 static int
index 40baeae60b081aa8e94757bf992f1f612f26a927..a2ec65ae626c20b1cec0c343f0aa654d0887905d 100644 (file)
@@ -476,6 +476,10 @@ struct create_context {
        __u8 Buffer[0];
 } __packed;
 
+#define SMB2_LEASE_READ_CACHING_HE     0x01
+#define SMB2_LEASE_HANDLE_CACHING_HE   0x02
+#define SMB2_LEASE_WRITE_CACHING_HE    0x04
+
 #define SMB2_LEASE_NONE                        __constant_cpu_to_le32(0x00)
 #define SMB2_LEASE_READ_CACHING                __constant_cpu_to_le32(0x01)
 #define SMB2_LEASE_HANDLE_CACHING      __constant_cpu_to_le32(0x02)
index 1db89fda1392be62d8a5dd09e4f30bad54346f0d..e3fb4801ee969295484fd8324bec855fc9600e0b 100644 (file)
@@ -53,7 +53,6 @@ extern int smb3_calc_signature(struct smb_rqst *rqst,
                                struct TCP_Server_Info *server);
 extern void smb2_echo_request(struct work_struct *work);
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
-extern __u8 smb2_map_lease_to_oplock(__le32 lease_state);
 extern bool smb2_is_valid_oplock_break(char *buffer,
                                       struct TCP_Server_Info *srv);
 
@@ -87,7 +86,6 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_open_file(const unsigned int xid,
                          struct cifs_open_parms *oparms,
                          __u32 *oplock, FILE_ALL_INFO *buf);
-extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
                             struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);