From bc07c0b65d1c25ba7826ad1a5e4a60c2b47d776e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 5 Oct 2014 17:08:41 -0700 Subject: [PATCH] 3.14-stable patches added patches: cifs-fix-smb2-readdir-error-handling.patch --- ...cifs-fix-smb2-readdir-error-handling.patch | 166 ++++++++++++++++++ queue-3.14/series | 1 + 2 files changed, 167 insertions(+) create mode 100644 queue-3.14/cifs-fix-smb2-readdir-error-handling.patch diff --git a/queue-3.14/cifs-fix-smb2-readdir-error-handling.patch b/queue-3.14/cifs-fix-smb2-readdir-error-handling.patch new file mode 100644 index 00000000000..470051fb4fb --- /dev/null +++ b/queue-3.14/cifs-fix-smb2-readdir-error-handling.patch @@ -0,0 +1,166 @@ +From 52755808d4525f4d5b86d112d36ffc7a46f3fb48 Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Mon, 18 Aug 2014 20:49:57 +0400 +Subject: CIFS: Fix SMB2 readdir error handling + +From: Pavel Shilovsky + +commit 52755808d4525f4d5b86d112d36ffc7a46f3fb48 upstream. + +SMB2 servers indicates the end of a directory search with +STATUS_NO_MORE_FILE error code that is not processed now. +This causes generic/257 xfstest to fail. Fix this by triggering +the end of search by this error code in SMB2_query_directory. + +Also when negotiating CIFS protocol we tell the server to close +the search automatically at the end and there is no need to do +it itself. In the case of SMB2 protocol, we need to close it +explicitly - separate close directory checks for different +protocols. + +Signed-off-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + + +--- + fs/cifs/cifsglob.h | 2 ++ + fs/cifs/file.c | 2 +- + fs/cifs/readdir.c | 2 +- + fs/cifs/smb1ops.c | 7 +++++++ + fs/cifs/smb2maperror.c | 2 +- + fs/cifs/smb2ops.c | 9 +++++++++ + fs/cifs/smb2pdu.c | 9 ++++----- + 7 files changed, 25 insertions(+), 8 deletions(-) + +--- a/fs/cifs/cifsglob.h ++++ b/fs/cifs/cifsglob.h +@@ -399,6 +399,8 @@ struct smb_version_operations { + const struct cifs_fid *, u32 *); + int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, + int); ++ /* check if we need to issue closedir */ ++ bool (*dir_needs_close)(struct cifsFileInfo *); + }; + + struct smb_version_values { +--- a/fs/cifs/file.c ++++ b/fs/cifs/file.c +@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, s + + cifs_dbg(FYI, "Freeing private data in close dir\n"); + spin_lock(&cifs_file_list_lock); +- if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { ++ if (server->ops->dir_needs_close(cfile)) { + cfile->invalidHandle = true; + spin_unlock(&cifs_file_list_lock); + if (server->ops->close_dir) +--- a/fs/cifs/readdir.c ++++ b/fs/cifs/readdir.c +@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, + /* close and restart search */ + cifs_dbg(FYI, "search backing up - close and restart search\n"); + spin_lock(&cifs_file_list_lock); +- if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { ++ if (server->ops->dir_needs_close(cfile)) { + cfile->invalidHandle = true; + spin_unlock(&cifs_file_list_lock); + if (server->ops->close_dir) +--- a/fs/cifs/smb1ops.c ++++ b/fs/cifs/smb1ops.c +@@ -1009,6 +1009,12 @@ cifs_is_read_op(__u32 oplock) + return oplock == OPLOCK_READ; + } + ++static bool ++cifs_dir_needs_close(struct cifsFileInfo *cfile) ++{ ++ return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; ++} ++ + struct smb_version_operations smb1_operations = { + .send_cancel = send_nt_cancel, + .compare_fids = cifs_compare_fids, +@@ -1078,6 +1084,7 @@ struct smb_version_operations smb1_opera + .query_mf_symlink = cifs_query_mf_symlink, + .create_mf_symlink = cifs_create_mf_symlink, + .is_read_op = cifs_is_read_op, ++ .dir_needs_close = cifs_dir_needs_close, + #ifdef CONFIG_CIFS_XATTR + .query_all_EAs = CIFSSMBQAllEAs, + .set_EA = CIFSSMBSetEA, +--- a/fs/cifs/smb2maperror.c ++++ b/fs/cifs/smb2maperror.c +@@ -214,7 +214,7 @@ static const struct status_to_posix_erro + {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, + {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, + {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, +- {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, ++ {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"}, + {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, + {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, + {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -1102,6 +1102,12 @@ smb3_parse_lease_buf(void *buf, unsigned + return le32_to_cpu(lc->lcontext.LeaseState); + } + ++static bool ++smb2_dir_needs_close(struct cifsFileInfo *cfile) ++{ ++ return !cfile->invalidHandle; ++} ++ + struct smb_version_operations smb20_operations = { + .compare_fids = smb2_compare_fids, + .setup_request = smb2_setup_request, +@@ -1175,6 +1181,7 @@ struct smb_version_operations smb20_oper + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, + .clone_range = smb2_clone_range, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_operations smb21_operations = { +@@ -1250,6 +1257,7 @@ struct smb_version_operations smb21_oper + .create_lease_buf = smb2_create_lease_buf, + .parse_lease_buf = smb2_parse_lease_buf, + .clone_range = smb2_clone_range, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_operations smb30_operations = { +@@ -1328,6 +1336,7 @@ struct smb_version_operations smb30_oper + .parse_lease_buf = smb3_parse_lease_buf, + .clone_range = smb2_clone_range, + .validate_negotiate = smb3_validate_negotiate, ++ .dir_needs_close = smb2_dir_needs_close, + }; + + struct smb_version_values smb20_values = { +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -2136,6 +2136,10 @@ SMB2_query_directory(const unsigned int + rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; + + if (rc) { ++ if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) { ++ srch_inf->endOfSearch = true; ++ rc = 0; ++ } + cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); + goto qdir_exit; + } +@@ -2173,11 +2177,6 @@ SMB2_query_directory(const unsigned int + else + cifs_dbg(VFS, "illegal search buffer type\n"); + +- if (rsp->hdr.Status == STATUS_NO_MORE_FILES) +- srch_inf->endOfSearch = 1; +- else +- srch_inf->endOfSearch = 0; +- + return rc; + + qdir_exit: diff --git a/queue-3.14/series b/queue-3.14/series index 6eeaaf503d7..b7cecfc758a 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -7,3 +7,4 @@ drm-i915-flush-the-ptes-after-updating-them-before-suspend.patch fix-problem-recognizing-symlinks.patch init-kconfig-fix-have_futex_cmpxchg-to-not-break-up-the-expert-menu.patch ring-buffer-fix-infinite-spin-in-reading-buffer.patch +cifs-fix-smb2-readdir-error-handling.patch -- 2.47.3