CIFS: Fix oplock break handling (try #2)
authorPavel Shilovsky <piastryyy@gmail.com>
Mon, 17 Jan 2011 17:15:44 +0000 (20:15 +0300)
committerSteve French <sfrench@us.ibm.com>
Wed, 19 Jan 2011 17:52:29 +0000 (17:52 +0000)
When we get oplock break notification we should set the appropriate
value of OplockLevel field in oplock break acknowledge according to
the oplock level held by the client in this time. As we only can have
level II oplock or no oplock in the case of oplock break, we should be
aware only about clientCanCacheRead field in cifsInodeInfo structure.

Also fix bug connected with wrong interpretation of OplockLevel field
during oplock break notification processing.

Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com>
Cc: <stable@kernel.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/cifs/misc.c

index e6d1481b16c1403cbe1c7fcae04e11abcc3f91f9..95d5dbbb4c7a90b926b899c2f8eb59190974c86c 100644 (file)
@@ -347,7 +347,7 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 netfid, const __u64 len,
                        const __u64 offset, const __u32 numUnlock,
                        const __u32 numLock, const __u8 lockType,
-                       const bool waitFlag);
+                       const bool waitFlag, const __u8 oplock_level);
 extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        const __u16 smb_file_id, const int get_flag,
                        const __u64 len, struct file_lock *,
index 2f6795e524d3f39c34c2a1dbed77e11149f9330c..3652cc60314ceea3f19ac3ec1714e93b94b85433 100644 (file)
@@ -1663,7 +1663,8 @@ int
 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
            const __u16 smb_file_id, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
-           const __u32 numLock, const __u8 lockType, const bool waitFlag)
+           const __u32 numLock, const __u8 lockType,
+           const bool waitFlag, const __u8 oplock_level)
 {
        int rc = 0;
        LOCK_REQ *pSMB = NULL;
@@ -1691,6 +1692,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->NumberOfLocks = cpu_to_le16(numLock);
        pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
        pSMB->LockType = lockType;
+       pSMB->OplockLevel = oplock_level;
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
index d843631c028d5939f57992701e95943318fe14ab..af371910f543906eb59f0c1efdb7f5436e40ffd6 100644 (file)
@@ -726,12 +726,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
                /* 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, 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 /* wait flag */, 0);
                        pfLock->fl_type = F_UNLCK;
                        if (rc != 0)
                                cERROR(1, "Error unlocking previously locked "
@@ -748,13 +748,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                                rc = CIFSSMBLock(xid, tcon, netfid, length,
                                        pfLock->fl_start, 0, 1,
                                        lockType | LOCKING_ANDX_SHARED_LOCK,
-                                       0 /* wait flag */);
+                                       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 /* wait flag */, 0);
                                        pfLock->fl_type = F_RDLCK;
                                        if (rc != 0)
                                                cERROR(1, "Error unlocking "
@@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
                if (numLock) {
                        rc = CIFSSMBLock(xid, tcon, netfid, length,
-                                       pfLock->fl_start,
-                                       0, numLock, lockType, wait_flag);
+                                        pfLock->fl_start, 0, numLock, lockType,
+                                        wait_flag, 0);
 
                        if (rc == 0) {
                                /* For Windows locks we must store them. */
@@ -818,9 +818,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                                                (pfLock->fl_start + length) >=
                                                (li->offset + li->length)) {
                                        stored_rc = CIFSSMBLock(xid, tcon,
-                                                       netfid,
-                                                       li->length, li->offset,
-                                                       1, 0, li->type, false);
+                                                       netfid, li->length,
+                                                       li->offset, 1, 0,
+                                                       li->type, false, 0);
                                        if (stored_rc)
                                                rc = stored_rc;
                                        else {
@@ -2192,7 +2192,8 @@ void cifs_oplock_break(struct work_struct *work)
         */
        if (!cfile->oplock_break_cancelled) {
                rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
-                                0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
+                                0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
+                                cinode->clientCanCacheRead ? 1 : 0);
                cFYI(1, "Oplock release rc = %d", rc);
        }
 
index 43f10281bc19e80be48303e1bd9c974b4882cb37..09bfcf08a90ff7a9b05bec53abc34196f052106b 100644 (file)
@@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
 
                                cifs_set_oplock_level(pCifsInode,
-                                                     pSMB->OplockLevel);
+                                       pSMB->OplockLevel ? OPLOCK_READ : 0);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing