Skip to content

Commit c59f7c9

Browse files
Paulo AlcantaraSteve French
authored andcommitted
smb: client: ensure aligned IO sizes
Make all IO sizes multiple of PAGE_SIZE, either negotiated by the server or passed through rsize, wsize and bsize mount options, to prevent from breaking DIO reads and writes against servers that enforce alignment as specified in MS-FSA 2.1.5.3 and 2.1.5.4. Cc: linux-cifs@vger.kernel.org Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent f122121 commit c59f7c9

File tree

6 files changed

+62
-55
lines changed

6 files changed

+62
-55
lines changed

fs/smb/client/connect.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,28 +3753,7 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
37533753
}
37543754
}
37553755

3756-
/*
3757-
* Clamp the rsize/wsize mount arguments if they are too big for the server
3758-
* and set the rsize/wsize to the negotiated values if not passed in by
3759-
* the user on mount
3760-
*/
3761-
if ((cifs_sb->ctx->wsize == 0) ||
3762-
(cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) {
3763-
cifs_sb->ctx->wsize =
3764-
round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
3765-
/*
3766-
* in the very unlikely event that the server sent a max write size under PAGE_SIZE,
3767-
* (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096
3768-
*/
3769-
if (cifs_sb->ctx->wsize == 0) {
3770-
cifs_sb->ctx->wsize = PAGE_SIZE;
3771-
cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n");
3772-
}
3773-
}
3774-
if ((cifs_sb->ctx->rsize == 0) ||
3775-
(cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
3776-
cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
3777-
3756+
cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
37783757
/*
37793758
* The cookie is initialized from volume info returned above.
37803759
* Inside cifs_fscache_get_super_cookie it checks

fs/smb/client/file.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,8 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq)
160160
server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses);
161161
rdata->server = server;
162162

163-
if (cifs_sb->ctx->rsize == 0)
164-
cifs_sb->ctx->rsize =
165-
server->ops->negotiate_rsize(tlink_tcon(req->cfile->tlink),
166-
cifs_sb->ctx);
163+
cifs_negotiate_rsize(server, cifs_sb->ctx,
164+
tlink_tcon(req->cfile->tlink));
167165

168166
rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
169167
&size, &rdata->credits);

fs/smb/client/fs_context.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,7 @@ static int smb3_reconfigure(struct fs_context *fc)
10211021
struct dentry *root = fc->root;
10221022
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
10231023
struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
1024+
unsigned int rsize = ctx->rsize, wsize = ctx->wsize;
10241025
char *new_password = NULL, *new_password2 = NULL;
10251026
bool need_recon = false;
10261027
int rc;
@@ -1103,11 +1104,8 @@ static int smb3_reconfigure(struct fs_context *fc)
11031104
STEAL_STRING(cifs_sb, ctx, iocharset);
11041105

11051106
/* if rsize or wsize not passed in on remount, use previous values */
1106-
if (ctx->rsize == 0)
1107-
ctx->rsize = cifs_sb->ctx->rsize;
1108-
if (ctx->wsize == 0)
1109-
ctx->wsize = cifs_sb->ctx->wsize;
1110-
1107+
ctx->rsize = rsize ? CIFS_ALIGN_RSIZE(fc, rsize) : cifs_sb->ctx->rsize;
1108+
ctx->wsize = wsize ? CIFS_ALIGN_WSIZE(fc, wsize) : cifs_sb->ctx->wsize;
11111109

11121110
smb3_cleanup_fs_context_contents(cifs_sb->ctx);
11131111
rc = smb3_fs_context_dup(cifs_sb->ctx, ctx);
@@ -1312,7 +1310,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13121310
__func__);
13131311
goto cifs_parse_mount_err;
13141312
}
1315-
ctx->bsize = result.uint_32;
1313+
ctx->bsize = CIFS_ALIGN_BSIZE(fc, result.uint_32);
13161314
ctx->got_bsize = true;
13171315
break;
13181316
case Opt_rasize:
@@ -1336,24 +1334,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13361334
ctx->rasize = result.uint_32;
13371335
break;
13381336
case Opt_rsize:
1339-
ctx->rsize = result.uint_32;
1337+
ctx->rsize = CIFS_ALIGN_RSIZE(fc, result.uint_32);
13401338
ctx->got_rsize = true;
13411339
ctx->vol_rsize = ctx->rsize;
13421340
break;
13431341
case Opt_wsize:
1344-
ctx->wsize = result.uint_32;
1342+
ctx->wsize = CIFS_ALIGN_WSIZE(fc, result.uint_32);
13451343
ctx->got_wsize = true;
1346-
if (ctx->wsize % PAGE_SIZE != 0) {
1347-
ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
1348-
if (ctx->wsize == 0) {
1349-
ctx->wsize = PAGE_SIZE;
1350-
cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
1351-
} else {
1352-
cifs_dbg(VFS,
1353-
"wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
1354-
ctx->wsize, PAGE_SIZE);
1355-
}
1356-
}
13571344
ctx->vol_wsize = ctx->wsize;
13581345
break;
13591346
case Opt_acregmax:

fs/smb/client/fs_context.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@
2020
cifs_dbg(VFS, fmt, ## __VA_ARGS__); \
2121
} while (0)
2222

23+
static inline size_t cifs_io_align(struct fs_context *fc,
24+
const char *name, size_t size)
25+
{
26+
if (!size || !IS_ALIGNED(size, PAGE_SIZE)) {
27+
cifs_errorf(fc, "unaligned %s, making it a multiple of %lu bytes\n",
28+
name, PAGE_SIZE);
29+
size = umax(round_down(size, PAGE_SIZE), PAGE_SIZE);
30+
}
31+
return size;
32+
}
33+
34+
#define CIFS_ALIGN_WSIZE(_fc, _size) cifs_io_align(_fc, "wsize", _size)
35+
#define CIFS_ALIGN_RSIZE(_fc, _size) cifs_io_align(_fc, "rsize", _size)
36+
#define CIFS_ALIGN_BSIZE(_fc, _size) cifs_io_align(_fc, "bsize", _size)
37+
2338
enum smb_version {
2439
Smb_1 = 1,
2540
Smb_20,
@@ -361,4 +376,36 @@ static inline void cifs_mount_unlock(void)
361376
mutex_unlock(&cifs_mount_mutex);
362377
}
363378

379+
static inline void cifs_negotiate_rsize(struct TCP_Server_Info *server,
380+
struct smb3_fs_context *ctx,
381+
struct cifs_tcon *tcon)
382+
{
383+
unsigned int size;
384+
385+
size = umax(server->ops->negotiate_rsize(tcon, ctx), PAGE_SIZE);
386+
if (ctx->rsize)
387+
size = umax(umin(ctx->rsize, size), PAGE_SIZE);
388+
ctx->rsize = round_down(size, PAGE_SIZE);
389+
}
390+
391+
static inline void cifs_negotiate_wsize(struct TCP_Server_Info *server,
392+
struct smb3_fs_context *ctx,
393+
struct cifs_tcon *tcon)
394+
{
395+
unsigned int size;
396+
397+
size = umax(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
398+
if (ctx->wsize)
399+
size = umax(umin(ctx->wsize, size), PAGE_SIZE);
400+
ctx->wsize = round_down(size, PAGE_SIZE);
401+
}
402+
403+
static inline void cifs_negotiate_iosize(struct TCP_Server_Info *server,
404+
struct smb3_fs_context *ctx,
405+
struct cifs_tcon *tcon)
406+
{
407+
cifs_negotiate_rsize(server, ctx, tcon);
408+
cifs_negotiate_wsize(server, ctx, tcon);
409+
}
410+
364411
#endif

fs/smb/client/smb1ops.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ cifs_negotiate(const unsigned int xid,
432432
}
433433

434434
static unsigned int
435-
cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
435+
smb1_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
436436
{
437437
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
438438
struct TCP_Server_Info *server = tcon->ses->server;
@@ -467,7 +467,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
467467
}
468468

469469
static unsigned int
470-
cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
470+
smb1_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
471471
{
472472
__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
473473
struct TCP_Server_Info *server = tcon->ses->server;
@@ -1342,8 +1342,8 @@ struct smb_version_operations smb1_operations = {
13421342
.check_trans2 = cifs_check_trans2,
13431343
.need_neg = cifs_need_neg,
13441344
.negotiate = cifs_negotiate,
1345-
.negotiate_wsize = cifs_negotiate_wsize,
1346-
.negotiate_rsize = cifs_negotiate_rsize,
1345+
.negotiate_wsize = smb1_negotiate_wsize,
1346+
.negotiate_rsize = smb1_negotiate_rsize,
13471347
.sess_setup = CIFS_SessSetup,
13481348
.logoff = CIFSSMBLogoff,
13491349
.tree_connect = CIFSTCon,

fs/smb/client/smb2pdu.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4093,12 +4093,8 @@ static void cifs_renegotiate_iosize(struct TCP_Server_Info *server,
40934093
return;
40944094

40954095
spin_lock(&tcon->sb_list_lock);
4096-
list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link) {
4097-
cifs_sb->ctx->rsize =
4098-
server->ops->negotiate_rsize(tcon, cifs_sb->ctx);
4099-
cifs_sb->ctx->wsize =
4100-
server->ops->negotiate_wsize(tcon, cifs_sb->ctx);
4101-
}
4096+
list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link)
4097+
cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
41024098
spin_unlock(&tcon->sb_list_lock);
41034099
}
41044100

0 commit comments

Comments
 (0)