forked from Minki/linux
CIFS: Fix oplock break handling (try #2)
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>
This commit is contained in:
parent
c56eb8fb6d
commit
12fed00de9
@ -347,7 +347,7 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
const __u16 netfid, const __u64 len,
|
const __u16 netfid, const __u64 len,
|
||||||
const __u64 offset, const __u32 numUnlock,
|
const __u64 offset, const __u32 numUnlock,
|
||||||
const __u32 numLock, const __u8 lockType,
|
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,
|
extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
||||||
const __u16 smb_file_id, const int get_flag,
|
const __u16 smb_file_id, const int get_flag,
|
||||||
const __u64 len, struct file_lock *,
|
const __u64 len, struct file_lock *,
|
||||||
|
@ -1663,7 +1663,8 @@ int
|
|||||||
CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
||||||
const __u16 smb_file_id, const __u64 len,
|
const __u16 smb_file_id, const __u64 len,
|
||||||
const __u64 offset, const __u32 numUnlock,
|
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;
|
int rc = 0;
|
||||||
LOCK_REQ *pSMB = NULL;
|
LOCK_REQ *pSMB = NULL;
|
||||||
@ -1691,6 +1692,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
pSMB->NumberOfLocks = cpu_to_le16(numLock);
|
pSMB->NumberOfLocks = cpu_to_le16(numLock);
|
||||||
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
|
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
|
||||||
pSMB->LockType = lockType;
|
pSMB->LockType = lockType;
|
||||||
|
pSMB->OplockLevel = oplock_level;
|
||||||
pSMB->AndXCommand = 0xFF; /* none */
|
pSMB->AndXCommand = 0xFF; /* none */
|
||||||
pSMB->Fid = smb_file_id; /* netfid stays le */
|
pSMB->Fid = smb_file_id; /* netfid stays le */
|
||||||
|
|
||||||
|
@ -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 */
|
/* BB we could chain these into one lock request BB */
|
||||||
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
|
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) {
|
if (rc == 0) {
|
||||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||||
pfLock->fl_start, 1 /* numUnlock */ ,
|
pfLock->fl_start, 1 /* numUnlock */ ,
|
||||||
0 /* numLock */ , lockType,
|
0 /* numLock */ , lockType,
|
||||||
0 /* wait flag */ );
|
0 /* wait flag */, 0);
|
||||||
pfLock->fl_type = F_UNLCK;
|
pfLock->fl_type = F_UNLCK;
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
cERROR(1, "Error unlocking previously locked "
|
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,
|
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||||
pfLock->fl_start, 0, 1,
|
pfLock->fl_start, 0, 1,
|
||||||
lockType | LOCKING_ANDX_SHARED_LOCK,
|
lockType | LOCKING_ANDX_SHARED_LOCK,
|
||||||
0 /* wait flag */);
|
0 /* wait flag */, 0);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
rc = CIFSSMBLock(xid, tcon, netfid,
|
rc = CIFSSMBLock(xid, tcon, netfid,
|
||||||
length, pfLock->fl_start, 1, 0,
|
length, pfLock->fl_start, 1, 0,
|
||||||
lockType |
|
lockType |
|
||||||
LOCKING_ANDX_SHARED_LOCK,
|
LOCKING_ANDX_SHARED_LOCK,
|
||||||
0 /* wait flag */);
|
0 /* wait flag */, 0);
|
||||||
pfLock->fl_type = F_RDLCK;
|
pfLock->fl_type = F_RDLCK;
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
cERROR(1, "Error unlocking "
|
cERROR(1, "Error unlocking "
|
||||||
@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||||||
|
|
||||||
if (numLock) {
|
if (numLock) {
|
||||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||||
pfLock->fl_start,
|
pfLock->fl_start, 0, numLock, lockType,
|
||||||
0, numLock, lockType, wait_flag);
|
wait_flag, 0);
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
/* For Windows locks we must store them. */
|
/* 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) >=
|
(pfLock->fl_start + length) >=
|
||||||
(li->offset + li->length)) {
|
(li->offset + li->length)) {
|
||||||
stored_rc = CIFSSMBLock(xid, tcon,
|
stored_rc = CIFSSMBLock(xid, tcon,
|
||||||
netfid,
|
netfid, li->length,
|
||||||
li->length, li->offset,
|
li->offset, 1, 0,
|
||||||
1, 0, li->type, false);
|
li->type, false, 0);
|
||||||
if (stored_rc)
|
if (stored_rc)
|
||||||
rc = stored_rc;
|
rc = stored_rc;
|
||||||
else {
|
else {
|
||||||
@ -2192,7 +2192,8 @@ void cifs_oplock_break(struct work_struct *work)
|
|||||||
*/
|
*/
|
||||||
if (!cfile->oplock_break_cancelled) {
|
if (!cfile->oplock_break_cancelled) {
|
||||||
rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
|
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);
|
cFYI(1, "Oplock release rc = %d", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
|||||||
pCifsInode = CIFS_I(netfile->dentry->d_inode);
|
pCifsInode = CIFS_I(netfile->dentry->d_inode);
|
||||||
|
|
||||||
cifs_set_oplock_level(pCifsInode,
|
cifs_set_oplock_level(pCifsInode,
|
||||||
pSMB->OplockLevel);
|
pSMB->OplockLevel ? OPLOCK_READ : 0);
|
||||||
/*
|
/*
|
||||||
* cifs_oplock_break_put() can't be called
|
* cifs_oplock_break_put() can't be called
|
||||||
* from here. Get reference after queueing
|
* from here. Get reference after queueing
|
||||||
|
Loading…
Reference in New Issue
Block a user