Skip to content

Commit 287906b

Browse files
Wang ZhaolongSteve French
authored andcommitted
smb: client: Store original IO parameters and prevent zero IO sizes
During mount option processing and negotiation with the server, the original user-specified rsize/wsize values were being modified directly. This makes it impossible to recover these values after a connection reset, leading to potential degraded performance after reconnection. The other problem is that When negotiating read and write sizes, there are cases where the negotiated values might calculate to zero, especially during reconnection when server->max_read or server->max_write might be reset. In general, these values come from the negotiation response. According to MS-SMB2 specification, these values should be at least 65536 bytes. This patch improves IO parameter handling: 1. Adds vol_rsize and vol_wsize fields to store the original user-specified values separately from the negotiated values 2. Uses got_rsize/got_wsize flags to determine if values were user-specified rather than checking for non-zero values, which is more reliable 3. Adds a prevent_zero_iosize() helper function to ensure IO sizes are never negotiated down to zero, which could happen in edge cases like when server->max_read/write is zero The changes make the CIFS client more resilient to unusual server responses and reconnection scenarios, preventing potential failures when IO sizes are calculated to be zero. Signed-off-by: Wang Zhaolong <wangzhaolong1@huawei.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent a091d97 commit 287906b

File tree

5 files changed

+30
-11
lines changed

5 files changed

+30
-11
lines changed

fs/smb/client/fs_context.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13331333
case Opt_rsize:
13341334
ctx->rsize = result.uint_32;
13351335
ctx->got_rsize = true;
1336+
ctx->vol_rsize = ctx->rsize;
13361337
break;
13371338
case Opt_wsize:
13381339
ctx->wsize = result.uint_32;
@@ -1348,6 +1349,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13481349
ctx->wsize, PAGE_SIZE);
13491350
}
13501351
}
1352+
ctx->vol_wsize = ctx->wsize;
13511353
break;
13521354
case Opt_acregmax:
13531355
if (result.uint_32 > CIFS_MAX_ACTIMEO / HZ) {

fs/smb/client/fs_context.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ struct smb3_fs_context {
280280
bool use_client_guid:1;
281281
/* reuse existing guid for multichannel */
282282
u8 client_guid[SMB2_CLIENT_GUID_SIZE];
283+
/* User-specified original r/wsize value */
284+
unsigned int vol_rsize;
285+
unsigned int vol_wsize;
283286
unsigned int bsize;
284287
unsigned int rasize;
285288
unsigned int rsize;

fs/smb/client/smb1ops.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,8 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
444444
unsigned int wsize;
445445

446446
/* start with specified wsize, or default */
447-
if (ctx->wsize)
448-
wsize = ctx->wsize;
447+
if (ctx->got_wsize)
448+
wsize = ctx->vol_wsize;
449449
else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
450450
wsize = CIFS_DEFAULT_IOSIZE;
451451
else
@@ -497,7 +497,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
497497
else
498498
defsize = server->maxBuf - sizeof(READ_RSP);
499499

500-
rsize = ctx->rsize ? ctx->rsize : defsize;
500+
rsize = ctx->got_rsize ? ctx->vol_rsize : defsize;
501501

502502
/*
503503
* no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to

fs/smb/client/smb2ops.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -470,19 +470,30 @@ smb2_negotiate(const unsigned int xid,
470470
return rc;
471471
}
472472

473+
static inline unsigned int
474+
prevent_zero_iosize(unsigned int size, const char *type)
475+
{
476+
if (size == 0) {
477+
cifs_dbg(VFS, "SMB: Zero %ssize calculated, using minimum value %u\n",
478+
type, CIFS_MIN_DEFAULT_IOSIZE);
479+
return CIFS_MIN_DEFAULT_IOSIZE;
480+
}
481+
return size;
482+
}
483+
473484
static unsigned int
474485
smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
475486
{
476487
struct TCP_Server_Info *server = tcon->ses->server;
477488
unsigned int wsize;
478489

479490
/* start with specified wsize, or default */
480-
wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE;
491+
wsize = ctx->got_wsize ? ctx->vol_wsize : CIFS_DEFAULT_IOSIZE;
481492
wsize = min_t(unsigned int, wsize, server->max_write);
482493
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
483494
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
484495

485-
return wsize;
496+
return prevent_zero_iosize(wsize, "w");
486497
}
487498

488499
static unsigned int
@@ -492,7 +503,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
492503
unsigned int wsize;
493504

494505
/* start with specified wsize, or default */
495-
wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE;
506+
wsize = ctx->got_wsize ? ctx->vol_wsize : SMB3_DEFAULT_IOSIZE;
496507
wsize = min_t(unsigned int, wsize, server->max_write);
497508
#ifdef CONFIG_CIFS_SMB_DIRECT
498509
if (server->rdma) {
@@ -514,7 +525,7 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
514525
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
515526
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
516527

517-
return wsize;
528+
return prevent_zero_iosize(wsize, "w");
518529
}
519530

520531
static unsigned int
@@ -524,13 +535,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
524535
unsigned int rsize;
525536

526537
/* start with specified rsize, or default */
527-
rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE;
538+
rsize = ctx->got_rsize ? ctx->vol_rsize : CIFS_DEFAULT_IOSIZE;
528539
rsize = min_t(unsigned int, rsize, server->max_read);
529540

530541
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
531542
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
532543

533-
return rsize;
544+
return prevent_zero_iosize(rsize, "r");
534545
}
535546

536547
static unsigned int
@@ -540,7 +551,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
540551
unsigned int rsize;
541552

542553
/* start with specified rsize, or default */
543-
rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE;
554+
rsize = ctx->got_rsize ? ctx->vol_rsize : SMB3_DEFAULT_IOSIZE;
544555
rsize = min_t(unsigned int, rsize, server->max_read);
545556
#ifdef CONFIG_CIFS_SMB_DIRECT
546557
if (server->rdma) {
@@ -563,7 +574,7 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
563574
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
564575
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
565576

566-
return rsize;
577+
return prevent_zero_iosize(rsize, "r");
567578
}
568579

569580
/*

fs/smb/common/smb2pdu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@
9595
*/
9696
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
9797

98+
/* According to MS-SMB2 specification The minimum recommended value is 65536.*/
99+
#define CIFS_MIN_DEFAULT_IOSIZE (65536)
100+
98101
/*
99102
* SMB2 Header Definition
100103
*

0 commit comments

Comments
 (0)