CIFS: Simplify byte range locking code
authorPavel Shilovsky <piastryyy@gmail.com>
Tue, 17 Aug 2010 07:26:00 +0000 (11:26 +0400)
committerSteve French <smfrench@gmail.com>
Thu, 13 Oct 2011 22:16:28 +0000 (17:16 -0500)
Split cifs_lock into several functions and let CIFSSMBLock get pid
as an argument.

Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/file.c

index 3b83fe7bfe601a31a40cbceb15b499330c68a634..1f265ffe7e638bdccdf7b4eca509572f2900d2c5 100644 (file)
@@ -492,6 +492,7 @@ struct cifsLockInfo {
        struct list_head llist; /* pointer to next cifsLockInfo */
        __u64 offset;
        __u64 length;
+       __u32 pid;
        __u8 type;
 };
 
index 9ddb1eccde69c8cf6f1b4514fcdbbfbf42d43823..94834dbb46dabbb0829a0d3dcffbc80af1591815 100644 (file)
@@ -361,7 +361,7 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
                        int remap_special_chars);
 
 extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
-                       const __u16 netfid, const __u64 len,
+                       const __u16 netfid, const __u32 netpid, const __u64 len,
                        const __u64 offset, const __u32 numUnlock,
                        const __u32 numLock, const __u8 lockType,
                        const bool waitFlag, const __u8 oplock_level);
index 602326fa4a4f5b3e35d6225be0f10387277a1638..e33093f7ef0deb7bef258e261ad48f8c68566b4f 100644 (file)
@@ -1963,7 +1963,7 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
 
 int
 CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
-           const __u16 smb_file_id, const __u64 len,
+           const __u16 smb_file_id, const __u32 netpid, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
            const __u32 numLock, const __u8 lockType,
            const bool waitFlag, const __u8 oplock_level)
@@ -1999,7 +1999,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
        if ((numLock != 0) || (numUnlock != 0)) {
-               pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+               pSMB->Locks[0].Pid = cpu_to_le16(netpid);
                /* BB where to store pid high? */
                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
                pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
index 237192ae7587b444dfcc1c659bc981baa062f74f..ab85699c565346663fd515cb45d598804e75dc9f 100644 (file)
@@ -639,8 +639,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
        return rc;
 }
 
-static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
-                               __u64 offset, __u8 lockType)
+static int store_file_lock(struct cifsFileInfo *cfile, __u64 len,
+                          __u64 offset, __u8 type, __u16 netfid)
 {
        struct cifsLockInfo *li =
                kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
@@ -648,210 +648,241 @@ static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
                return -ENOMEM;
        li->offset = offset;
        li->length = len;
-       li->type = lockType;
-       mutex_lock(&fid->lock_mutex);
-       list_add(&li->llist, &fid->llist);
-       mutex_unlock(&fid->lock_mutex);
+       li->type = type;
+       li->pid = current->tgid;
+       mutex_lock(&cfile->lock_mutex);
+       list_add_tail(&li->llist, &cfile->llist);
+       mutex_unlock(&cfile->lock_mutex);
        return 0;
 }
 
-int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
+static void
+cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
+               bool *wait_flag)
 {
-       int rc, xid;
-       __u32 numLock = 0;
-       __u32 numUnlock = 0;
-       __u64 length;
-       bool wait_flag = false;
-       struct cifs_sb_info *cifs_sb;
-       struct cifs_tcon *tcon;
-       __u16 netfid;
-       __u8 lockType = LOCKING_ANDX_LARGE_FILES;
-       bool posix_locking = 0;
-
-       length = 1 + pfLock->fl_end - pfLock->fl_start;
-       rc = -EACCES;
-       xid = GetXid();
-
-       cFYI(1, "Lock parm: 0x%x flockflags: "
-                "0x%x flocktype: 0x%x start: %lld end: %lld",
-               cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
-               pfLock->fl_end);
-
-       if (pfLock->fl_flags & FL_POSIX)
+       if (flock->fl_flags & FL_POSIX)
                cFYI(1, "Posix");
-       if (pfLock->fl_flags & FL_FLOCK)
+       if (flock->fl_flags & FL_FLOCK)
                cFYI(1, "Flock");
-       if (pfLock->fl_flags & FL_SLEEP) {
+       if (flock->fl_flags & FL_SLEEP) {
                cFYI(1, "Blocking lock");
-               wait_flag = true;
+               *wait_flag = true;
        }
-       if (pfLock->fl_flags & FL_ACCESS)
+       if (flock->fl_flags & FL_ACCESS)
                cFYI(1, "Process suspended by mandatory locking - "
-                        "not implemented yet");
-       if (pfLock->fl_flags & FL_LEASE)
+                       "not implemented yet");
+       if (flock->fl_flags & FL_LEASE)
                cFYI(1, "Lease on file - not implemented yet");
-       if (pfLock->fl_flags &
+       if (flock->fl_flags &
            (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
-               cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags);
+               cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
 
-       if (pfLock->fl_type == F_WRLCK) {
+       *type = LOCKING_ANDX_LARGE_FILES;
+       if (flock->fl_type == F_WRLCK) {
                cFYI(1, "F_WRLCK ");
-               numLock = 1;
-       } else if (pfLock->fl_type == F_UNLCK) {
+               *lock = 1;
+       } else if (flock->fl_type == F_UNLCK) {
                cFYI(1, "F_UNLCK");
-               numUnlock = 1;
-               /* Check if unlock includes more than
-               one lock range */
-       } else if (pfLock->fl_type == F_RDLCK) {
+               *unlock = 1;
+               /* Check if unlock includes more than one lock range */
+       } else if (flock->fl_type == F_RDLCK) {
                cFYI(1, "F_RDLCK");
-               lockType |= LOCKING_ANDX_SHARED_LOCK;
-               numLock = 1;
-       } else if (pfLock->fl_type == F_EXLCK) {
+               *type |= LOCKING_ANDX_SHARED_LOCK;
+               *lock = 1;
+       } else if (flock->fl_type == F_EXLCK) {
                cFYI(1, "F_EXLCK");
-               numLock = 1;
-       } else if (pfLock->fl_type == F_SHLCK) {
+               *lock = 1;
+       } else if (flock->fl_type == F_SHLCK) {
                cFYI(1, "F_SHLCK");
-               lockType |= LOCKING_ANDX_SHARED_LOCK;
-               numLock = 1;
+               *type |= LOCKING_ANDX_SHARED_LOCK;
+               *lock = 1;
        } else
                cFYI(1, "Unknown type of lock");
+}
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-       tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
-       netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
-
-       if ((tcon->ses->capabilities & CAP_UNIX) &&
-           (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
-           ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
-               posix_locking = 1;
-       /* BB add code here to normalize offset and length to
-       account for negative length which we can not accept over the
-       wire */
-       if (IS_GETLK(cmd)) {
-               if (posix_locking) {
-                       int posix_lock_type;
-                       if (lockType & LOCKING_ANDX_SHARED_LOCK)
-                               posix_lock_type = CIFS_RDLCK;
-                       else
-                               posix_lock_type = CIFS_WRLCK;
-                       rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
-                                       length, pfLock, posix_lock_type,
-                                       wait_flag);
-                       FreeXid(xid);
-                       return rc;
-               }
-
-               /* BB we could chain these into one lock request BB */
-               rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
-                                0, 1, lockType, 0 /* wait flag */, 0);
-               if (rc == 0) {
-                       rc = CIFSSMBLock(xid, tcon, netfid, length,
-                                        pfLock->fl_start, 1 /* numUnlock */ ,
-                                        0 /* numLock */ , lockType,
-                                        0 /* wait flag */, 0);
-                       pfLock->fl_type = F_UNLCK;
-                       if (rc != 0)
-                               cERROR(1, "Error unlocking previously locked "
-                                          "range %d during test of lock", rc);
-                       rc = 0;
-
-               } else {
-                       /* if rc == ERR_SHARING_VIOLATION ? */
-                       rc = 0;
+static int
+cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
+          bool wait_flag, bool posix_lck, int xid)
+{
+       int rc = 0;
+       __u64 length = 1 + flock->fl_end - flock->fl_start;
+       __u16 netfid = cfile->netfid;
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
-                       if (lockType & LOCKING_ANDX_SHARED_LOCK) {
-                               pfLock->fl_type = F_WRLCK;
-                       } else {
-                               rc = CIFSSMBLock(xid, tcon, netfid, length,
-                                       pfLock->fl_start, 0, 1,
-                                       lockType | LOCKING_ANDX_SHARED_LOCK,
-                                       0 /* wait flag */, 0);
-                               if (rc == 0) {
-                                       rc = CIFSSMBLock(xid, tcon, netfid,
-                                               length, pfLock->fl_start, 1, 0,
-                                               lockType |
-                                               LOCKING_ANDX_SHARED_LOCK,
-                                               0 /* wait flag */, 0);
-                                       pfLock->fl_type = F_RDLCK;
-                                       if (rc != 0)
-                                               cERROR(1, "Error unlocking "
-                                               "previously locked range %d "
-                                               "during test of lock", rc);
-                                       rc = 0;
-                               } else {
-                                       pfLock->fl_type = F_WRLCK;
-                                       rc = 0;
-                               }
-                       }
-               }
+       if (posix_lck) {
+               int posix_lock_type;
+               if (type & LOCKING_ANDX_SHARED_LOCK)
+                       posix_lock_type = CIFS_RDLCK;
+               else
+                       posix_lock_type = CIFS_WRLCK;
+               rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
+                                     length, flock, posix_lock_type,
+                                     wait_flag);
+               return rc;
+       }
 
-               FreeXid(xid);
+       /* BB we could chain these into one lock request BB */
+       rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+                        flock->fl_start, 0, 1, type, 0, 0);
+       if (rc == 0) {
+               rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
+                                length, flock->fl_start, 1, 0,
+                                type, 0, 0);
+               flock->fl_type = F_UNLCK;
+               if (rc != 0)
+                       cERROR(1, "Error unlocking previously locked "
+                                  "range %d during test of lock", rc);
+               rc = 0;
                return rc;
        }
 
-       if (!numLock && !numUnlock) {
-               /* if no lock or unlock then nothing
-               to do since we do not know what it is */
-               FreeXid(xid);
-               return -EOPNOTSUPP;
+       if (type & LOCKING_ANDX_SHARED_LOCK) {
+               flock->fl_type = F_WRLCK;
+               rc = 0;
+               return rc;
        }
 
-       if (posix_locking) {
+       rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+                        flock->fl_start, 0, 1,
+                        type | LOCKING_ANDX_SHARED_LOCK, 0, 0);
+       if (rc == 0) {
+               rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
+                                length, flock->fl_start, 1, 0,
+                                type | LOCKING_ANDX_SHARED_LOCK,
+                                0, 0);
+               flock->fl_type = F_RDLCK;
+               if (rc != 0)
+                       cERROR(1, "Error unlocking previously locked "
+                                 "range %d during test of lock", rc);
+       } else
+               flock->fl_type = F_WRLCK;
+
+       rc = 0;
+       return rc;
+}
+
+static int
+cifs_setlk(struct file *file,  struct file_lock *flock, __u8 type,
+          bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
+{
+       int rc = 0;
+       __u64 length = 1 + flock->fl_end - flock->fl_start;
+       struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+       __u16 netfid = cfile->netfid;
+
+       if (posix_lck) {
                int posix_lock_type;
-               if (lockType & LOCKING_ANDX_SHARED_LOCK)
+               if (type & LOCKING_ANDX_SHARED_LOCK)
                        posix_lock_type = CIFS_RDLCK;
                else
                        posix_lock_type = CIFS_WRLCK;
 
-               if (numUnlock == 1)
+               if (unlock == 1)
                        posix_lock_type = CIFS_UNLCK;
 
-               rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
-                                     length, pfLock, posix_lock_type,
-                                     wait_flag);
-       } else {
-               struct cifsFileInfo *fid = file->private_data;
-
-               if (numLock) {
-                       rc = CIFSSMBLock(xid, tcon, netfid, length,
-                                        pfLock->fl_start, 0, numLock, lockType,
-                                        wait_flag, 0);
-
-                       if (rc == 0) {
-                               /* For Windows locks we must store them. */
-                               rc = store_file_lock(fid, length,
-                                               pfLock->fl_start, lockType);
-                       }
-               } else if (numUnlock) {
-                       /* For each stored lock that this unlock overlaps
-                          completely, unlock it. */
-                       int stored_rc = 0;
-                       struct cifsLockInfo *li, *tmp;
+               rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length,
+                                     flock, posix_lock_type, wait_flag);
+               goto out;
+       }
 
-                       rc = 0;
-                       mutex_lock(&fid->lock_mutex);
-                       list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
-                               if (pfLock->fl_start <= li->offset &&
-                                               (pfLock->fl_start + length) >=
-                                               (li->offset + li->length)) {
-                                       stored_rc = CIFSSMBLock(xid, tcon,
-                                                       netfid, li->length,
-                                                       li->offset, 1, 0,
-                                                       li->type, false, 0);
-                                       if (stored_rc)
-                                               rc = stored_rc;
-                                       else {
-                                               list_del(&li->llist);
-                                               kfree(li);
-                                       }
-                               }
+       if (lock) {
+               rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
+                                flock->fl_start, 0, lock, type, wait_flag, 0);
+               if (rc == 0) {
+                       /* For Windows locks we must store them. */
+                       rc = store_file_lock(cfile, length, flock->fl_start,
+                                            type, netfid);
+               }
+       } else if (unlock) {
+               /*
+                * For each stored lock that this unlock overlaps completely,
+                * unlock it.
+                */
+               int stored_rc = 0;
+               struct cifsLockInfo *li, *tmp;
+
+               mutex_lock(&cfile->lock_mutex);
+               list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
+                       if (flock->fl_start > li->offset ||
+                           (flock->fl_start + length) <
+                           (li->offset + li->length))
+                               continue;
+                       if (current->tgid != li->pid)
+                               continue;
+
+                       stored_rc = CIFSSMBLock(xid, tcon, netfid,
+                                               current->tgid, li->length,
+                                               li->offset, 1, 0, li->type,
+                                               0, 0);
+                       if (stored_rc)
+                               rc = stored_rc;
+                       else {
+                               list_del(&li->llist);
+                               kfree(li);
                        }
-                       mutex_unlock(&fid->lock_mutex);
                }
+               mutex_unlock(&cfile->lock_mutex);
+       }
+out:
+       if (flock->fl_flags & FL_POSIX)
+               posix_lock_file_wait(file, flock);
+       return rc;
+}
+
+int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
+{
+       int rc, xid;
+       int lock = 0, unlock = 0;
+       bool wait_flag = false;
+       bool posix_lck = false;
+       struct cifs_sb_info *cifs_sb;
+       struct cifs_tcon *tcon;
+       struct cifsInodeInfo *cinode;
+       struct cifsFileInfo *cfile;
+       __u16 netfid;
+       __u8 type;
+
+       rc = -EACCES;
+       xid = GetXid();
+
+       cFYI(1, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld "
+               "end: %lld", cmd, flock->fl_flags, flock->fl_type,
+               flock->fl_start, flock->fl_end);
+
+       cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag);
+
+       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       cfile = (struct cifsFileInfo *)file->private_data;
+       tcon = tlink_tcon(cfile->tlink);
+       netfid = cfile->netfid;
+       cinode = CIFS_I(file->f_path.dentry->d_inode);
+
+       if ((tcon->ses->capabilities & CAP_UNIX) &&
+           (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+           ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+               posix_lck = true;
+       /*
+        * BB add code here to normalize offset and length to account for
+        * negative length which we can not accept over the wire.
+        */
+       if (IS_GETLK(cmd)) {
+               rc = cifs_getlk(cfile, flock, type, wait_flag, posix_lck, xid);
+               FreeXid(xid);
+               return rc;
+       }
+
+       if (!lock && !unlock) {
+               /*
+                * if no lock or unlock then nothing to do since we do not
+                * know what it is
+                */
+               FreeXid(xid);
+               return -EOPNOTSUPP;
        }
 
-       if (pfLock->fl_flags & FL_POSIX)
-               posix_lock_file_wait(file, pfLock);
+       rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
+                       xid);
        FreeXid(xid);
        return rc;
 }
@@ -2423,8 +2454,9 @@ void cifs_oplock_break(struct work_struct *work)
         * disconnected since oplock already released by the server
         */
        if (!cfile->oplock_break_cancelled) {
-               rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
-                                0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
+               rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
+                                current->tgid, 0, 0, 0, 0,
+                                LOCKING_ANDX_OPLOCK_RELEASE, false,
                                 cinode->clientCanCacheRead ? 1 : 0);
                cFYI(1, "Oplock release rc = %d", rc);
        }