Skip to content

Commit 5275580

Browse files
piastrysmfrench
authored andcommitted
CIFS: Fix SMB2 readdir error handling
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. Cc: <stable@vger.kernel.org> Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
1 parent 18f39e7 commit 5275580

File tree

7 files changed

+25
-8
lines changed

7 files changed

+25
-8
lines changed

fs/cifs/cifsglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ struct smb_version_operations {
409409
/* get mtu credits */
410410
int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
411411
unsigned int *, unsigned int *);
412+
/* check if we need to issue closedir */
413+
bool (*dir_needs_close)(struct cifsFileInfo *);
412414
};
413415

414416
struct smb_version_values {

fs/cifs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
762762

763763
cifs_dbg(FYI, "Freeing private data in close dir\n");
764764
spin_lock(&cifs_file_list_lock);
765-
if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
765+
if (server->ops->dir_needs_close(cfile)) {
766766
cfile->invalidHandle = true;
767767
spin_unlock(&cifs_file_list_lock);
768768
if (server->ops->close_dir)

fs/cifs/readdir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
593593
/* close and restart search */
594594
cifs_dbg(FYI, "search backing up - close and restart search\n");
595595
spin_lock(&cifs_file_list_lock);
596-
if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
596+
if (server->ops->dir_needs_close(cfile)) {
597597
cfile->invalidHandle = true;
598598
spin_unlock(&cifs_file_list_lock);
599599
if (server->ops->close)

fs/cifs/smb1ops.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,12 @@ cifs_wp_retry_size(struct inode *inode)
10151015
return CIFS_SB(inode->i_sb)->wsize;
10161016
}
10171017

1018+
static bool
1019+
cifs_dir_needs_close(struct cifsFileInfo *cfile)
1020+
{
1021+
return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
1022+
}
1023+
10181024
struct smb_version_operations smb1_operations = {
10191025
.send_cancel = send_nt_cancel,
10201026
.compare_fids = cifs_compare_fids,
@@ -1086,6 +1092,7 @@ struct smb_version_operations smb1_operations = {
10861092
.create_mf_symlink = cifs_create_mf_symlink,
10871093
.is_read_op = cifs_is_read_op,
10881094
.wp_retry_size = cifs_wp_retry_size,
1095+
.dir_needs_close = cifs_dir_needs_close,
10891096
#ifdef CONFIG_CIFS_XATTR
10901097
.query_all_EAs = CIFSSMBQAllEAs,
10911098
.set_EA = CIFSSMBSetEA,

fs/cifs/smb2maperror.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
214214
{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
215215
{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
216216
{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
217-
{STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"},
217+
{STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
218218
{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
219219
{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
220220
{STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},

fs/cifs/smb2ops.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,12 @@ smb2_wp_retry_size(struct inode *inode)
12221222
SMB2_MAX_BUFFER_SIZE);
12231223
}
12241224

1225+
static bool
1226+
smb2_dir_needs_close(struct cifsFileInfo *cfile)
1227+
{
1228+
return !cfile->invalidHandle;
1229+
}
1230+
12251231
struct smb_version_operations smb20_operations = {
12261232
.compare_fids = smb2_compare_fids,
12271233
.setup_request = smb2_setup_request,
@@ -1297,6 +1303,7 @@ struct smb_version_operations smb20_operations = {
12971303
.parse_lease_buf = smb2_parse_lease_buf,
12981304
.clone_range = smb2_clone_range,
12991305
.wp_retry_size = smb2_wp_retry_size,
1306+
.dir_needs_close = smb2_dir_needs_close,
13001307
};
13011308

13021309
struct smb_version_operations smb21_operations = {
@@ -1374,6 +1381,7 @@ struct smb_version_operations smb21_operations = {
13741381
.parse_lease_buf = smb2_parse_lease_buf,
13751382
.clone_range = smb2_clone_range,
13761383
.wp_retry_size = smb2_wp_retry_size,
1384+
.dir_needs_close = smb2_dir_needs_close,
13771385
};
13781386

13791387
struct smb_version_operations smb30_operations = {
@@ -1454,6 +1462,7 @@ struct smb_version_operations smb30_operations = {
14541462
.clone_range = smb2_clone_range,
14551463
.validate_negotiate = smb3_validate_negotiate,
14561464
.wp_retry_size = smb2_wp_retry_size,
1465+
.dir_needs_close = smb2_dir_needs_close,
14571466
};
14581467

14591468
struct smb_version_values smb20_values = {

fs/cifs/smb2pdu.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
21802180
rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
21812181

21822182
if (rc) {
2183+
if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
2184+
srch_inf->endOfSearch = true;
2185+
rc = 0;
2186+
}
21832187
cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
21842188
goto qdir_exit;
21852189
}
@@ -2217,11 +2221,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
22172221
else
22182222
cifs_dbg(VFS, "illegal search buffer type\n");
22192223

2220-
if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
2221-
srch_inf->endOfSearch = 1;
2222-
else
2223-
srch_inf->endOfSearch = 0;
2224-
22252224
return rc;
22262225

22272226
qdir_exit:

0 commit comments

Comments
 (0)