[PATCH 5/9] smb/client: retry change notify after invalid cached handle

ChenXiaoSong <[email protected]>
Newsgroups org.kernel.vger.linux-cifs
Message-ID <[email protected]>
From: ChenXiaoSong <[email protected]>

The notify ioctl caches a separate FID in cifsFileInfo. That
handle is not reopened by cifs_reopen_file(), so it can become
stale across reconnects. If the server returns STATUS_INVALID_HANDLE
for the cached FID, SMB2_change_notify() maps it to -EBADF, but
smb3_notify() kept reusing the bad handle.

Invalidate the cached notify FID on -EBADF and retry once so the
next attempt opens a fresh handle. Clear only if the cached FID
still matches the failed one to avoid racing with another thread
that reopened it.

Signed-off-by: ChenXiaoSong <[email protected]>
---
 fs/smb/client/smb2ops.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index d6a33acc62ff..9c2455b5fb03 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2365,7 +2365,21 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-
+static void
+smb3_notify_invalidate_fid(struct cifsFileInfo *cfile,
+			   const struct cifs_fid *fid)
+{
+	mutex_lock(&cfile->notify_fid_mutex);
+	if (cfile->has_notify_fid &&
+	    cfile->notify_fid.persistent_fid == fid->persistent_fid &&
+	    cfile->notify_fid.volatile_fid == fid->volatile_fid) {
+		cfile->has_notify_fid = false;
+		memset(&cfile->notify_fid, 0, sizeof(cfile->notify_fid));
+		cifs_put_tlink(cfile->notify_tlink);
+		cfile->notify_tlink = NULL;
+	}
+	mutex_unlock(&cfile->notify_fid_mutex);
+}
 
 static int
 smb3_notify(const unsigned int xid, struct file *pfile,
@@ -2388,6 +2402,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	int rc = 0;
 	__u32 ret_len = 0;
+	bool retry = false;
 
 	if (return_changes) {
 		if (copy_from_user(&notify, ioc_buf, sizeof(struct smb3_notify_info))) {
@@ -2418,6 +2433,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 		cfile = pfile->private_data;
 	}
 
+retry_notify:
 	mutex_lock(&cfile->notify_fid_mutex);
 	if (!cfile->has_notify_fid) {
 		page = alloc_dentry_path();
@@ -2468,7 +2484,23 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 	rc = SMB2_change_notify(xid, tcon, fid.persistent_fid, fid.volatile_fid,
 				notify.watch_tree, notify.completion_filter,
 				notify.data_len, &returned_ioctl_info, &ret_len);
-
+	if (rc == -EBADF) {
+		smb3_notify_invalidate_fid(cfile, &fid);
+		if (retry)
+			goto notify_done;
+
+		kfree(returned_ioctl_info);
+		returned_ioctl_info = NULL;
+		free_dentry_path(page);
+		page = NULL;
+		kfree(utf16_path);
+		utf16_path = NULL;
+		ret_len = 0;
+		retry = true;
+		goto retry_notify;
+	}
+
+notify_done:
 	cifs_dbg(FYI, "change notify for %pd rc %d\n", dentry, rc);
 	if (return_changes && (ret_len > 0) && (notify.data_len > 0)) {
 		if (ret_len > notify.data_len)
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.