mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
CIFS: Do not reset lease state to NONE on lease break
commit7b9b9edb49
upstream. Currently on lease break the client sets a caching level twice: when oplock is detected and when oplock is processed. While the 1st attempt sets the level to the value provided by the server, the 2nd one resets the level to None unconditionally. This happens because the oplock/lease processing code was changed to avoid races between page cache flushes and oplock breaks. The commitc11f1df500
("cifs: Wait for writebacks to complete before attempting write.") fixed the races for oplocks but didn't apply the same changes for leases resulting in overwriting the server granted value to None. Fix this by properly processing lease breaks. Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> CC: Stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9a0eec8d4d
commit
f8a0d9ccf2
2 changed files with 26 additions and 6 deletions
|
@ -474,7 +474,6 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
||||||
__u8 lease_state;
|
__u8 lease_state;
|
||||||
struct list_head *tmp;
|
struct list_head *tmp;
|
||||||
struct cifsFileInfo *cfile;
|
struct cifsFileInfo *cfile;
|
||||||
struct TCP_Server_Info *server = tcon->ses->server;
|
|
||||||
struct cifs_pending_open *open;
|
struct cifs_pending_open *open;
|
||||||
struct cifsInodeInfo *cinode;
|
struct cifsInodeInfo *cinode;
|
||||||
int ack_req = le32_to_cpu(rsp->Flags &
|
int ack_req = le32_to_cpu(rsp->Flags &
|
||||||
|
@ -494,13 +493,25 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
||||||
cifs_dbg(FYI, "lease key match, lease break 0x%x\n",
|
cifs_dbg(FYI, "lease key match, lease break 0x%x\n",
|
||||||
le32_to_cpu(rsp->NewLeaseState));
|
le32_to_cpu(rsp->NewLeaseState));
|
||||||
|
|
||||||
server->ops->set_oplock_level(cinode, lease_state, 0, NULL);
|
|
||||||
|
|
||||||
if (ack_req)
|
if (ack_req)
|
||||||
cfile->oplock_break_cancelled = false;
|
cfile->oplock_break_cancelled = false;
|
||||||
else
|
else
|
||||||
cfile->oplock_break_cancelled = true;
|
cfile->oplock_break_cancelled = true;
|
||||||
|
|
||||||
|
set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set or clear flags depending on the lease state being READ.
|
||||||
|
* HANDLE caching flag should be added when the client starts
|
||||||
|
* to defer closing remote file handles with HANDLE leases.
|
||||||
|
*/
|
||||||
|
if (lease_state & SMB2_LEASE_READ_CACHING_HE)
|
||||||
|
set_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
|
||||||
|
&cinode->flags);
|
||||||
|
else
|
||||||
|
clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
|
||||||
|
&cinode->flags);
|
||||||
|
|
||||||
queue_work(cifsoplockd_wq, &cfile->oplock_break);
|
queue_work(cifsoplockd_wq, &cfile->oplock_break);
|
||||||
kfree(lw);
|
kfree(lw);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1376,6 +1376,15 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server,
|
||||||
server->ops->set_oplock_level(cinode, 0, 0, NULL);
|
server->ops->set_oplock_level(cinode, 0, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb21_downgrade_oplock(struct TCP_Server_Info *server,
|
||||||
|
struct cifsInodeInfo *cinode, bool set_level2)
|
||||||
|
{
|
||||||
|
server->ops->set_oplock_level(cinode,
|
||||||
|
set_level2 ? SMB2_LEASE_READ_CACHING_HE :
|
||||||
|
0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
||||||
unsigned int epoch, bool *purge_cache)
|
unsigned int epoch, bool *purge_cache)
|
||||||
|
@ -1681,7 +1690,7 @@ struct smb_version_operations smb21_operations = {
|
||||||
.print_stats = smb2_print_stats,
|
.print_stats = smb2_print_stats,
|
||||||
.is_oplock_break = smb2_is_valid_oplock_break,
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
||||||
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
||||||
.downgrade_oplock = smb2_downgrade_oplock,
|
.downgrade_oplock = smb21_downgrade_oplock,
|
||||||
.need_neg = smb2_need_neg,
|
.need_neg = smb2_need_neg,
|
||||||
.negotiate = smb2_negotiate,
|
.negotiate = smb2_negotiate,
|
||||||
.negotiate_wsize = smb2_negotiate_wsize,
|
.negotiate_wsize = smb2_negotiate_wsize,
|
||||||
|
@ -1765,7 +1774,7 @@ struct smb_version_operations smb30_operations = {
|
||||||
.dump_share_caps = smb2_dump_share_caps,
|
.dump_share_caps = smb2_dump_share_caps,
|
||||||
.is_oplock_break = smb2_is_valid_oplock_break,
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
||||||
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
||||||
.downgrade_oplock = smb2_downgrade_oplock,
|
.downgrade_oplock = smb21_downgrade_oplock,
|
||||||
.need_neg = smb2_need_neg,
|
.need_neg = smb2_need_neg,
|
||||||
.negotiate = smb2_negotiate,
|
.negotiate = smb2_negotiate,
|
||||||
.negotiate_wsize = smb2_negotiate_wsize,
|
.negotiate_wsize = smb2_negotiate_wsize,
|
||||||
|
@ -1855,7 +1864,7 @@ struct smb_version_operations smb311_operations = {
|
||||||
.dump_share_caps = smb2_dump_share_caps,
|
.dump_share_caps = smb2_dump_share_caps,
|
||||||
.is_oplock_break = smb2_is_valid_oplock_break,
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
||||||
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
||||||
.downgrade_oplock = smb2_downgrade_oplock,
|
.downgrade_oplock = smb21_downgrade_oplock,
|
||||||
.need_neg = smb2_need_neg,
|
.need_neg = smb2_need_neg,
|
||||||
.negotiate = smb2_negotiate,
|
.negotiate = smb2_negotiate,
|
||||||
.negotiate_wsize = smb2_negotiate_wsize,
|
.negotiate_wsize = smb2_negotiate_wsize,
|
||||||
|
|
Loading…
Reference in a new issue