[PATCH 3.13.y-ckt 61/80] Complete oplock break jobs before closing file handle

Kamal Mostafa kamal at canonical.com
Thu Mar 19 22:35:49 UTC 2015

3.13.11-ckt17 -stable review patch.  If anyone has any objections, please let me know.


From: Sachin Prabhu <sprabhu at redhat.com>

commit ca7df8e0bb2a5ec79691de8a1a4c0e611fe04e60 upstream.

requires writers to wait for any pending oplock break handler to
complete before proceeding to write. This is done by waiting on bit
CIFS_INODE_PENDING_OPLOCK_BREAK in cifsFileInfo->flags. This bit is
cleared by the oplock break handler job queued on the workqueue once it
has completed handling the oplock break allowing writers to proceed with
writing to the file.

While testing, it was noticed that the filehandle could be closed while
there is a pending oplock break which results in the oplock break
handler on the cifsiod workqueue being cancelled before it has had a
chance to execute and clear the CIFS_INODE_PENDING_OPLOCK_BREAK bit.
Any subsequent attempt to write to this file hangs waiting for the

We fix this by ensuring that we also clear the bit
CIFS_INODE_PENDING_OPLOCK_BREAK when we remove the oplock break handler
from the workqueue.

The bug was found by Red Hat QA while testing using ltp's fsstress

Signed-off-by: Sachin Prabhu <sprabhu at redhat.com>
Acked-by: Shirish Pargaonkar <shirishpargaonkar at gmail.com>
Signed-off-by: Jeff Layton <jlayton at samba.org>
Signed-off-by: Steve French <steve.french at primarydata.com>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
 fs/cifs/file.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e157583..3530d7c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -366,6 +366,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 	struct cifsLockInfo *li, *tmp;
 	struct cifs_fid fid;
 	struct cifs_pending_open open;
+	bool oplock_break_cancelled;
 	if (--cifs_file->count > 0) {
@@ -397,7 +398,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
-	cancel_work_sync(&cifs_file->oplock_break);
+	oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
 	if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
 		struct TCP_Server_Info *server = tcon->ses->server;
@@ -409,6 +410,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
+	if (oplock_break_cancelled)
+		cifs_done_oplock_break(cifsi);

More information about the kernel-team mailing list