Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

CIFS: Fix SMB2 oplock break processing

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>

authored by

Pavel Shilovsky and committed by
Steve French
fa9c2362 3591bb83

+3 -4
+3 -4
fs/cifs/smb2misc.c
··· 667 667 spin_lock(&cifs_tcp_ses_lock); 668 668 list_for_each(tmp, &server->smb_ses_list) { 669 669 ses = list_entry(tmp, struct cifs_ses, smb_ses_list); 670 + 670 671 list_for_each(tmp1, &ses->tcon_list) { 671 672 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); 672 673 673 - cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 674 674 spin_lock(&tcon->open_file_lock); 675 675 list_for_each(tmp2, &tcon->openFileList) { 676 676 cfile = list_entry(tmp2, struct cifsFileInfo, ··· 682 682 continue; 683 683 684 684 cifs_dbg(FYI, "file id match, oplock break\n"); 685 + cifs_stats_inc( 686 + &tcon->stats.cifs_stats.num_oplock_brks); 685 687 cinode = CIFS_I(d_inode(cfile->dentry)); 686 688 spin_lock(&cfile->file_info_lock); 687 689 if (!CIFS_CACHE_WRITE(cinode) && ··· 716 714 return true; 717 715 } 718 716 spin_unlock(&tcon->open_file_lock); 719 - spin_unlock(&cifs_tcp_ses_lock); 720 - cifs_dbg(FYI, "No matching file for oplock break\n"); 721 - return true; 722 717 } 723 718 } 724 719 spin_unlock(&cifs_tcp_ses_lock);