Skip to content

Commit daad00c

Browse files
committed
Merge tag '6.15-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - fix posix mkdir error to ksmbd (also avoids crash in cifs_destroy_request_bufs) - two smb1 fixes: fixing querypath info and setpathinfo to old servers - fix rsize/wsize when not multiple of page size to address DIO reads/writes * tag '6.15-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: ensure aligned IO sizes cifs: Fix changing times and read-only attr over SMB1 smb_set_file_info() function cifs: Fix and improve cifs_query_path_info() and cifs_query_file_info() smb: client: fix zero length for mkdir POSIX create context
2 parents 6de6674 + c59f7c9 commit daad00c

File tree

9 files changed

+324
-75
lines changed

9 files changed

+324
-75
lines changed

fs/smb/client/cifspdu.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,10 +1266,9 @@ typedef struct smb_com_query_information_rsp {
12661266
typedef struct smb_com_setattr_req {
12671267
struct smb_hdr hdr; /* wct = 8 */
12681268
__le16 attr;
1269-
__le16 time_low;
1270-
__le16 time_high;
1269+
__le32 last_write_time;
12711270
__le16 reserved[5]; /* must be zero */
1272-
__u16 ByteCount;
1271+
__le16 ByteCount;
12731272
__u8 BufferFormat; /* 4 = ASCII */
12741273
unsigned char fileName[];
12751274
} __attribute__((packed)) SETATTR_REQ;

fs/smb/client/cifsproto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,10 @@ extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
395395
extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
396396
struct kstatfs *FSData);
397397

398+
extern int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
399+
const char *fileName, __le32 attributes, __le64 write_time,
400+
const struct nls_table *nls_codepage,
401+
struct cifs_sb_info *cifs_sb);
398402
extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
399403
const char *fileName, const FILE_BASIC_INFO *data,
400404
const struct nls_table *nls_codepage,

fs/smb/client/cifssmb.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5171,6 +5171,63 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
51715171
return rc;
51725172
}
51735173

5174+
int
5175+
SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
5176+
const char *fileName, __le32 attributes, __le64 write_time,
5177+
const struct nls_table *nls_codepage,
5178+
struct cifs_sb_info *cifs_sb)
5179+
{
5180+
SETATTR_REQ *pSMB;
5181+
SETATTR_RSP *pSMBr;
5182+
struct timespec64 ts;
5183+
int bytes_returned;
5184+
int name_len;
5185+
int rc;
5186+
5187+
cifs_dbg(FYI, "In %s path %s\n", __func__, fileName);
5188+
5189+
retry:
5190+
rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5191+
(void **) &pSMBr);
5192+
if (rc)
5193+
return rc;
5194+
5195+
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5196+
name_len =
5197+
cifsConvertToUTF16((__le16 *) pSMB->fileName,
5198+
fileName, PATH_MAX, nls_codepage,
5199+
cifs_remap(cifs_sb));
5200+
name_len++; /* trailing null */
5201+
name_len *= 2;
5202+
} else {
5203+
name_len = copy_path_name(pSMB->fileName, fileName);
5204+
}
5205+
/* Only few attributes can be set by this command, others are not accepted by Win9x. */
5206+
pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) &
5207+
(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE));
5208+
/* Zero write time value (in both NT and SETATTR formats) means to not change it. */
5209+
if (le64_to_cpu(write_time) != 0) {
5210+
ts = cifs_NTtimeToUnix(write_time);
5211+
pSMB->last_write_time = cpu_to_le32(ts.tv_sec);
5212+
}
5213+
pSMB->BufferFormat = 0x04;
5214+
name_len++; /* account for buffer type byte */
5215+
inc_rfc1001_len(pSMB, (__u16)name_len);
5216+
pSMB->ByteCount = cpu_to_le16(name_len);
5217+
5218+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5219+
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
5220+
if (rc)
5221+
cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc);
5222+
5223+
cifs_buf_release(pSMB);
5224+
5225+
if (rc == -EAGAIN)
5226+
goto retry;
5227+
5228+
return rc;
5229+
}
5230+
51745231
/* Some legacy servers such as NT4 require that the file times be set on
51755232
an open handle, rather than by pathname - this is awkward due to
51765233
potential access conflicts on the open, but it is unavoidable for these

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

0 commit comments

Comments
 (0)