CIFS: Fix SMB2 oplock break processing
commit fa9c236249
upstream.
Even when mounting modern protocol version the server may be
configured without supporting SMB2.1 leases and the client
uses SMB2 oplock to optimize IO performance through local caching.
However there is a problem in oplock break handling that leads
to missing a break notification on the client who has a file
opened. It latter causes big latencies to other clients that
are trying to open the same file.
The problem reproduces when there are multiple shares from the
same server mounted on the client. The processing code tries to
match persistent and volatile file ids from the break notification
with an open file but it skips all share besides the first one.
Fix this by looking up in all shares belonging to the server that
issued the oplock break.
Cc: Stable <stable@vger.kernel.org>
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ee4f281989
commit
b1dd777a27
|
@ -673,10 +673,10 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
list_for_each(tmp, &server->smb_ses_list) {
|
list_for_each(tmp, &server->smb_ses_list) {
|
||||||
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
|
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
|
||||||
|
|
||||||
list_for_each(tmp1, &ses->tcon_list) {
|
list_for_each(tmp1, &ses->tcon_list) {
|
||||||
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
|
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
|
||||||
|
|
||||||
cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
|
|
||||||
spin_lock(&tcon->open_file_lock);
|
spin_lock(&tcon->open_file_lock);
|
||||||
list_for_each(tmp2, &tcon->openFileList) {
|
list_for_each(tmp2, &tcon->openFileList) {
|
||||||
cfile = list_entry(tmp2, struct cifsFileInfo,
|
cfile = list_entry(tmp2, struct cifsFileInfo,
|
||||||
|
@ -688,6 +688,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cifs_dbg(FYI, "file id match, oplock break\n");
|
cifs_dbg(FYI, "file id match, oplock break\n");
|
||||||
|
cifs_stats_inc(
|
||||||
|
&tcon->stats.cifs_stats.num_oplock_brks);
|
||||||
cinode = CIFS_I(d_inode(cfile->dentry));
|
cinode = CIFS_I(d_inode(cfile->dentry));
|
||||||
spin_lock(&cfile->file_info_lock);
|
spin_lock(&cfile->file_info_lock);
|
||||||
if (!CIFS_CACHE_WRITE(cinode) &&
|
if (!CIFS_CACHE_WRITE(cinode) &&
|
||||||
|
@ -720,9 +722,6 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
spin_unlock(&tcon->open_file_lock);
|
spin_unlock(&tcon->open_file_lock);
|
||||||
spin_unlock(&cifs_tcp_ses_lock);
|
|
||||||
cifs_dbg(FYI, "No matching file for oplock break\n");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&cifs_tcp_ses_lock);
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
|
|
Loading…
Reference in New Issue