]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
CIFS: Use brlock cache for SMB2
authorPavel Shilovsky <pshilovsky@etersoft.ru>
Wed, 29 Aug 2012 13:51:40 +0000 (17:51 +0400)
committerSteve French <sfrench@us.ibm.com>
Fri, 14 Sep 2012 16:43:22 +0000 (11:43 -0500)
Signed-off-by: Pavel Shilovsky <pshilovsky@etersoft.ru>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/smb2file.c
fs/cifs/smb2ops.c
fs/cifs/smb2proto.h

index a25ea02149e75974e6f5f6422b3296f42e6d951b..181e13d9f9dbaae8770df561f8fe4dc9078ad873 100644 (file)
@@ -201,3 +201,94 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
        kfree(buf);
        return rc;
 }
+
+static int
+smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
+                      struct smb2_lock_element *buf, unsigned int max_num)
+{
+       int rc = 0, stored_rc;
+       struct cifsFileInfo *cfile = fdlocks->cfile;
+       struct cifsLockInfo *li;
+       unsigned int num = 0;
+       struct smb2_lock_element *cur = buf;
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+
+       list_for_each_entry(li, &fdlocks->locks, llist) {
+               cur->Length = cpu_to_le64(li->length);
+               cur->Offset = cpu_to_le64(li->offset);
+               cur->Flags = cpu_to_le32(li->type |
+                                               SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
+               if (++num == max_num) {
+                       stored_rc = smb2_lockv(xid, tcon,
+                                              cfile->fid.persistent_fid,
+                                              cfile->fid.volatile_fid,
+                                              current->tgid, num, buf);
+                       if (stored_rc)
+                               rc = stored_rc;
+                       cur = buf;
+                       num = 0;
+               } else
+                       cur++;
+       }
+       if (num) {
+               stored_rc = smb2_lockv(xid, tcon,
+                                      cfile->fid.persistent_fid,
+                                      cfile->fid.volatile_fid,
+                                      current->tgid, num, buf);
+               if (stored_rc)
+                       rc = stored_rc;
+       }
+
+       return rc;
+}
+
+int
+smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
+{
+       int rc = 0, stored_rc;
+       unsigned int xid;
+       unsigned int max_num, max_buf;
+       struct smb2_lock_element *buf;
+       struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+       struct cifs_fid_locks *fdlocks;
+
+       xid = get_xid();
+       mutex_lock(&cinode->lock_mutex);
+       if (!cinode->can_cache_brlcks) {
+               mutex_unlock(&cinode->lock_mutex);
+               free_xid(xid);
+               return rc;
+       }
+
+       /*
+        * Accessing maxBuf is racy with cifs_reconnect - need to store value
+        * and check it for zero before using.
+        */
+       max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
+       if (!max_buf) {
+               mutex_unlock(&cinode->lock_mutex);
+               free_xid(xid);
+               return -EINVAL;
+       }
+
+       max_num = max_buf / sizeof(struct smb2_lock_element);
+       buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
+       if (!buf) {
+               mutex_unlock(&cinode->lock_mutex);
+               free_xid(xid);
+               return -ENOMEM;
+       }
+
+       list_for_each_entry(fdlocks, &cinode->llist, llist) {
+               stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
+               if (stored_rc)
+                       rc = stored_rc;
+       }
+
+       cinode->can_cache_brlcks = false;
+       kfree(buf);
+
+       mutex_unlock(&cinode->lock_mutex);
+       free_xid(xid);
+       return rc;
+}
index caed2c57896d859f763d1cfe71add88beae89b00..0808b238219b08d0b7dd80a3d9d3ab2f2e1ffb2f 100644 (file)
@@ -371,7 +371,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
        cfile->fid.persistent_fid = fid->persistent_fid;
        cfile->fid.volatile_fid = fid->volatile_fid;
        smb2_set_oplock_level(cinode, oplock);
-       /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
+       cinode->can_cache_brlcks = cinode->clientCanCacheAll;
 }
 
 static int
@@ -615,6 +615,7 @@ struct smb_version_operations smb21_operations = {
        .queryfs = smb2_queryfs,
        .mand_lock = smb2_mand_lock,
        .mand_unlock_range = smb2_unlock_range,
+       .push_mand_locks = smb2_push_mandatory_locks,
 };
 
 struct smb_version_values smb21_values = {
index ab19152b092b8e63b59beebf0f1eab96210cf7ce..8b4d3712255bc98316f7f23d1e75514a14408e64 100644 (file)
@@ -86,6 +86,7 @@ extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
 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);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details