Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+324 -75
+2 -3
fs/smb/client/cifspdu.h
··· 1266 1266 typedef struct smb_com_setattr_req { 1267 1267 struct smb_hdr hdr; /* wct = 8 */ 1268 1268 __le16 attr; 1269 - __le16 time_low; 1270 - __le16 time_high; 1269 + __le32 last_write_time; 1271 1270 __le16 reserved[5]; /* must be zero */ 1272 - __u16 ByteCount; 1271 + __le16 ByteCount; 1273 1272 __u8 BufferFormat; /* 4 = ASCII */ 1274 1273 unsigned char fileName[]; 1275 1274 } __attribute__((packed)) SETATTR_REQ;
+4
fs/smb/client/cifsproto.h
··· 395 395 extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, 396 396 struct kstatfs *FSData); 397 397 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); 398 402 extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 399 403 const char *fileName, const FILE_BASIC_INFO *data, 400 404 const struct nls_table *nls_codepage,
+57
fs/smb/client/cifssmb.c
··· 5171 5171 return rc; 5172 5172 } 5173 5173 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 + 5174 5231 /* Some legacy servers such as NT4 require that the file times be set on 5175 5232 an open handle, rather than by pathname - this is awkward due to 5176 5233 potential access conflicts on the open, but it is unavoidable for these
+1 -22
fs/smb/client/connect.c
··· 3753 3753 } 3754 3754 } 3755 3755 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); 3778 3757 /* 3779 3758 * The cookie is initialized from volume info returned above. 3780 3759 * Inside cifs_fscache_get_super_cookie it checks
+2 -4
fs/smb/client/file.c
··· 160 160 server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses); 161 161 rdata->server = server; 162 162 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)); 167 165 168 166 rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, 169 167 &size, &rdata->credits);
+6 -19
fs/smb/client/fs_context.c
··· 1021 1021 struct dentry *root = fc->root; 1022 1022 struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); 1023 1023 struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses; 1024 + unsigned int rsize = ctx->rsize, wsize = ctx->wsize; 1024 1025 char *new_password = NULL, *new_password2 = NULL; 1025 1026 bool need_recon = false; 1026 1027 int rc; ··· 1104 1103 STEAL_STRING(cifs_sb, ctx, iocharset); 1105 1104 1106 1105 /* if rsize or wsize not passed in on remount, use previous values */ 1107 - if (ctx->rsize == 0) 1108 - ctx->rsize = cifs_sb->ctx->rsize; 1109 - if (ctx->wsize == 0) 1110 - ctx->wsize = cifs_sb->ctx->wsize; 1111 - 1106 + ctx->rsize = rsize ? CIFS_ALIGN_RSIZE(fc, rsize) : cifs_sb->ctx->rsize; 1107 + ctx->wsize = wsize ? CIFS_ALIGN_WSIZE(fc, wsize) : cifs_sb->ctx->wsize; 1112 1108 1113 1109 smb3_cleanup_fs_context_contents(cifs_sb->ctx); 1114 1110 rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); ··· 1310 1312 __func__); 1311 1313 goto cifs_parse_mount_err; 1312 1314 } 1313 - ctx->bsize = result.uint_32; 1315 + ctx->bsize = CIFS_ALIGN_BSIZE(fc, result.uint_32); 1314 1316 ctx->got_bsize = true; 1315 1317 break; 1316 1318 case Opt_rasize: ··· 1334 1336 ctx->rasize = result.uint_32; 1335 1337 break; 1336 1338 case Opt_rsize: 1337 - ctx->rsize = result.uint_32; 1339 + ctx->rsize = CIFS_ALIGN_RSIZE(fc, result.uint_32); 1338 1340 ctx->got_rsize = true; 1339 1341 ctx->vol_rsize = ctx->rsize; 1340 1342 break; 1341 1343 case Opt_wsize: 1342 - ctx->wsize = result.uint_32; 1344 + ctx->wsize = CIFS_ALIGN_WSIZE(fc, result.uint_32); 1343 1345 ctx->got_wsize = true; 1344 - if (ctx->wsize % PAGE_SIZE != 0) { 1345 - ctx->wsize = round_down(ctx->wsize, PAGE_SIZE); 1346 - if (ctx->wsize == 0) { 1347 - ctx->wsize = PAGE_SIZE; 1348 - cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE); 1349 - } else { 1350 - cifs_dbg(VFS, 1351 - "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n", 1352 - ctx->wsize, PAGE_SIZE); 1353 - } 1354 - } 1355 1346 ctx->vol_wsize = ctx->wsize; 1356 1347 break; 1357 1348 case Opt_acregmax:
+47
fs/smb/client/fs_context.h
··· 20 20 cifs_dbg(VFS, fmt, ## __VA_ARGS__); \ 21 21 } while (0) 22 22 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 + 23 38 enum smb_version { 24 39 Smb_1 = 1, 25 40 Smb_20, ··· 374 359 static inline void cifs_mount_unlock(void) 375 360 { 376 361 mutex_unlock(&cifs_mount_mutex); 362 + } 363 + 364 + static inline void cifs_negotiate_rsize(struct TCP_Server_Info *server, 365 + struct smb3_fs_context *ctx, 366 + struct cifs_tcon *tcon) 367 + { 368 + unsigned int size; 369 + 370 + size = umax(server->ops->negotiate_rsize(tcon, ctx), PAGE_SIZE); 371 + if (ctx->rsize) 372 + size = umax(umin(ctx->rsize, size), PAGE_SIZE); 373 + ctx->rsize = round_down(size, PAGE_SIZE); 374 + } 375 + 376 + static inline void cifs_negotiate_wsize(struct TCP_Server_Info *server, 377 + struct smb3_fs_context *ctx, 378 + struct cifs_tcon *tcon) 379 + { 380 + unsigned int size; 381 + 382 + size = umax(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE); 383 + if (ctx->wsize) 384 + size = umax(umin(ctx->wsize, size), PAGE_SIZE); 385 + ctx->wsize = round_down(size, PAGE_SIZE); 386 + } 387 + 388 + static inline void cifs_negotiate_iosize(struct TCP_Server_Info *server, 389 + struct smb3_fs_context *ctx, 390 + struct cifs_tcon *tcon) 391 + { 392 + cifs_negotiate_rsize(server, ctx, tcon); 393 + cifs_negotiate_wsize(server, ctx, tcon); 377 394 } 378 395 379 396 #endif
+202 -21
fs/smb/client/smb1ops.c
··· 432 432 } 433 433 434 434 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) 436 436 { 437 437 __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); 438 438 struct TCP_Server_Info *server = tcon->ses->server; ··· 467 467 } 468 468 469 469 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) 471 471 { 472 472 __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); 473 473 struct TCP_Server_Info *server = tcon->ses->server; ··· 543 543 const char *full_path, 544 544 struct cifs_open_info_data *data) 545 545 { 546 - int rc; 546 + int rc = -EOPNOTSUPP; 547 547 FILE_ALL_INFO fi = {}; 548 + struct cifs_search_info search_info = {}; 549 + bool non_unicode_wildcard = false; 548 550 549 551 data->reparse_point = false; 550 552 data->adjust_tz = false; 551 553 552 - /* could do find first instead but this returns more info */ 553 - rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls, 554 - cifs_remap(cifs_sb)); 555 554 /* 556 - * BB optimize code so we do not make the above call when server claims 557 - * no NT SMB support and the above call failed at least once - set flag 558 - * in tcon or mount. 555 + * First try CIFSSMBQPathInfo() function which returns more info 556 + * (NumberOfLinks) than CIFSFindFirst() fallback function. 557 + * Some servers like Win9x do not support SMB_QUERY_FILE_ALL_INFO over 558 + * TRANS2_QUERY_PATH_INFORMATION, but supports it with filehandle over 559 + * TRANS2_QUERY_FILE_INFORMATION (function CIFSSMBQFileInfo(). But SMB 560 + * Open command on non-NT servers works only for files, does not work 561 + * for directories. And moreover Win9x SMB server returns bogus data in 562 + * SMB_QUERY_FILE_ALL_INFO Attributes field. So for non-NT servers, 563 + * do not even use CIFSSMBQPathInfo() or CIFSSMBQFileInfo() function. 559 564 */ 560 - if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { 565 + if (tcon->ses->capabilities & CAP_NT_SMBS) 566 + rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, 567 + cifs_sb->local_nls, cifs_remap(cifs_sb)); 568 + 569 + /* 570 + * Non-UNICODE variant of fallback functions below expands wildcards, 571 + * so they cannot be used for querying paths with wildcard characters. 572 + */ 573 + if (rc && !(tcon->ses->capabilities & CAP_UNICODE) && strpbrk(full_path, "*?\"><")) 574 + non_unicode_wildcard = true; 575 + 576 + /* 577 + * Then fallback to CIFSFindFirst() which works also with non-NT servers 578 + * but does not does not provide NumberOfLinks. 579 + */ 580 + if ((rc == -EOPNOTSUPP || rc == -EINVAL) && 581 + !non_unicode_wildcard) { 582 + if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) 583 + search_info.info_level = SMB_FIND_FILE_INFO_STANDARD; 584 + else 585 + search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; 586 + rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL, 587 + CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END, 588 + &search_info, false); 589 + if (rc == 0) { 590 + if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) { 591 + FIND_FILE_STANDARD_INFO *di; 592 + int offset = tcon->ses->server->timeAdj; 593 + 594 + di = (FIND_FILE_STANDARD_INFO *)search_info.srch_entries_start; 595 + fi.CreationTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( 596 + di->CreationDate, di->CreationTime, offset))); 597 + fi.LastAccessTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( 598 + di->LastAccessDate, di->LastAccessTime, offset))); 599 + fi.LastWriteTime = cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm( 600 + di->LastWriteDate, di->LastWriteTime, offset))); 601 + fi.ChangeTime = fi.LastWriteTime; 602 + fi.Attributes = cpu_to_le32(le16_to_cpu(di->Attributes)); 603 + fi.AllocationSize = cpu_to_le64(le32_to_cpu(di->AllocationSize)); 604 + fi.EndOfFile = cpu_to_le64(le32_to_cpu(di->DataSize)); 605 + } else { 606 + FILE_FULL_DIRECTORY_INFO *di; 607 + 608 + di = (FILE_FULL_DIRECTORY_INFO *)search_info.srch_entries_start; 609 + fi.CreationTime = di->CreationTime; 610 + fi.LastAccessTime = di->LastAccessTime; 611 + fi.LastWriteTime = di->LastWriteTime; 612 + fi.ChangeTime = di->ChangeTime; 613 + fi.Attributes = di->ExtFileAttributes; 614 + fi.AllocationSize = di->AllocationSize; 615 + fi.EndOfFile = di->EndOfFile; 616 + fi.EASize = di->EaSize; 617 + } 618 + fi.NumberOfLinks = cpu_to_le32(1); 619 + fi.DeletePending = 0; 620 + fi.Directory = !!(le32_to_cpu(fi.Attributes) & ATTR_DIRECTORY); 621 + cifs_buf_release(search_info.ntwrk_buf_start); 622 + } else if (!full_path[0]) { 623 + /* 624 + * CIFSFindFirst() does not work on root path if the 625 + * root path was exported on the server from the top 626 + * level path (drive letter). 627 + */ 628 + rc = -EOPNOTSUPP; 629 + } 630 + } 631 + 632 + /* 633 + * If everything failed then fallback to the legacy SMB command 634 + * SMB_COM_QUERY_INFORMATION which works with all servers, but 635 + * provide just few information. 636 + */ 637 + if ((rc == -EOPNOTSUPP || rc == -EINVAL) && !non_unicode_wildcard) { 561 638 rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls, 562 639 cifs_remap(cifs_sb)); 563 640 data->adjust_tz = true; 641 + } else if ((rc == -EOPNOTSUPP || rc == -EINVAL) && non_unicode_wildcard) { 642 + /* Path with non-UNICODE wildcard character cannot exist. */ 643 + rc = -ENOENT; 564 644 } 565 645 566 646 if (!rc) { ··· 718 638 { 719 639 int rc; 720 640 FILE_ALL_INFO fi = {}; 641 + 642 + /* 643 + * CIFSSMBQFileInfo() for non-NT servers returns bogus data in 644 + * Attributes fields. So do not use this command for non-NT servers. 645 + */ 646 + if (!(tcon->ses->capabilities & CAP_NT_SMBS)) 647 + return -EOPNOTSUPP; 721 648 722 649 if (cfile->symlink_target) { 723 650 data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); ··· 896 809 struct cifs_fid fid; 897 810 struct cifs_open_parms oparms; 898 811 struct cifsFileInfo *open_file; 812 + FILE_BASIC_INFO new_buf; 813 + struct cifs_open_info_data query_data; 814 + __le64 write_time = buf->LastWriteTime; 899 815 struct cifsInodeInfo *cinode = CIFS_I(inode); 900 816 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 901 817 struct tcon_link *tlink = NULL; ··· 906 816 907 817 /* if the file is already open for write, just use that fileid */ 908 818 open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); 819 + 909 820 if (open_file) { 910 821 fid.netfid = open_file->fid.netfid; 911 822 netpid = open_file->pid; 912 823 tcon = tlink_tcon(open_file->tlink); 913 - goto set_via_filehandle; 824 + } else { 825 + tlink = cifs_sb_tlink(cifs_sb); 826 + if (IS_ERR(tlink)) { 827 + rc = PTR_ERR(tlink); 828 + tlink = NULL; 829 + goto out; 830 + } 831 + tcon = tlink_tcon(tlink); 914 832 } 915 833 916 - tlink = cifs_sb_tlink(cifs_sb); 917 - if (IS_ERR(tlink)) { 918 - rc = PTR_ERR(tlink); 919 - tlink = NULL; 920 - goto out; 834 + /* 835 + * Non-NT servers interprets zero time value in SMB_SET_FILE_BASIC_INFO 836 + * over TRANS2_SET_FILE_INFORMATION as a valid time value. NT servers 837 + * interprets zero time value as do not change existing value on server. 838 + * API of ->set_file_info() callback expects that zero time value has 839 + * the NT meaning - do not change. Therefore if server is non-NT and 840 + * some time values in "buf" are zero, then fetch missing time values. 841 + */ 842 + if (!(tcon->ses->capabilities & CAP_NT_SMBS) && 843 + (!buf->CreationTime || !buf->LastAccessTime || 844 + !buf->LastWriteTime || !buf->ChangeTime)) { 845 + rc = cifs_query_path_info(xid, tcon, cifs_sb, full_path, &query_data); 846 + if (rc) { 847 + if (open_file) { 848 + cifsFileInfo_put(open_file); 849 + open_file = NULL; 850 + } 851 + goto out; 852 + } 853 + /* 854 + * Original write_time from buf->LastWriteTime is preserved 855 + * as SMBSetInformation() interprets zero as do not change. 856 + */ 857 + new_buf = *buf; 858 + buf = &new_buf; 859 + if (!buf->CreationTime) 860 + buf->CreationTime = query_data.fi.CreationTime; 861 + if (!buf->LastAccessTime) 862 + buf->LastAccessTime = query_data.fi.LastAccessTime; 863 + if (!buf->LastWriteTime) 864 + buf->LastWriteTime = query_data.fi.LastWriteTime; 865 + if (!buf->ChangeTime) 866 + buf->ChangeTime = query_data.fi.ChangeTime; 921 867 } 922 - tcon = tlink_tcon(tlink); 868 + 869 + if (open_file) 870 + goto set_via_filehandle; 923 871 924 872 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, 925 873 cifs_sb); ··· 978 850 .fid = &fid, 979 851 }; 980 852 981 - cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n"); 982 - rc = CIFS_open(xid, &oparms, &oplock, NULL); 853 + if (S_ISDIR(inode->i_mode) && !(tcon->ses->capabilities & CAP_NT_SMBS)) { 854 + /* Opening directory path is not possible on non-NT servers. */ 855 + rc = -EOPNOTSUPP; 856 + } else { 857 + /* 858 + * Use cifs_open_file() instead of CIFS_open() as the 859 + * cifs_open_file() selects the correct function which 860 + * works also on non-NT servers. 861 + */ 862 + rc = cifs_open_file(xid, &oparms, &oplock, NULL); 863 + /* 864 + * Opening path for writing on non-NT servers is not 865 + * possible when the read-only attribute is already set. 866 + * Non-NT server in this case returns -EACCES. For those 867 + * servers the only possible way how to clear the read-only 868 + * bit is via SMB_COM_SETATTR command. 869 + */ 870 + if (rc == -EACCES && 871 + (cinode->cifsAttrs & ATTR_READONLY) && 872 + le32_to_cpu(buf->Attributes) != 0 && /* 0 = do not change attrs */ 873 + !(le32_to_cpu(buf->Attributes) & ATTR_READONLY) && 874 + !(tcon->ses->capabilities & CAP_NT_SMBS)) 875 + rc = -EOPNOTSUPP; 876 + } 877 + 878 + /* Fallback to SMB_COM_SETATTR command when absolutelty needed. */ 879 + if (rc == -EOPNOTSUPP) { 880 + cifs_dbg(FYI, "calling SetInformation since SetPathInfo for attrs/times not supported by this server\n"); 881 + rc = SMBSetInformation(xid, tcon, full_path, 882 + buf->Attributes != 0 ? buf->Attributes : cpu_to_le32(cinode->cifsAttrs), 883 + write_time, 884 + cifs_sb->local_nls, cifs_sb); 885 + if (rc == 0) 886 + cinode->cifsAttrs = le32_to_cpu(buf->Attributes); 887 + else 888 + rc = -EACCES; 889 + goto out; 890 + } 891 + 983 892 if (rc != 0) { 984 893 if (rc == -EIO) 985 894 rc = -EINVAL; ··· 1024 859 } 1025 860 1026 861 netpid = current->tgid; 862 + cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for attrs/times not supported by this server\n"); 1027 863 1028 864 set_via_filehandle: 1029 865 rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid); ··· 1035 869 CIFSSMBClose(xid, tcon, fid.netfid); 1036 870 else 1037 871 cifsFileInfo_put(open_file); 872 + 873 + /* 874 + * Setting the read-only bit is not honered on non-NT servers when done 875 + * via open-semantics. So for setting it, use SMB_COM_SETATTR command. 876 + * This command works only after the file is closed, so use it only when 877 + * operation was called without the filehandle. 878 + */ 879 + if (open_file == NULL && 880 + !(tcon->ses->capabilities & CAP_NT_SMBS) && 881 + le32_to_cpu(buf->Attributes) & ATTR_READONLY) { 882 + SMBSetInformation(xid, tcon, full_path, 883 + buf->Attributes, 884 + 0 /* do not change write time */, 885 + cifs_sb->local_nls, cifs_sb); 886 + } 1038 887 out: 1039 888 if (tlink != NULL) 1040 889 cifs_put_tlink(tlink); ··· 1342 1161 .check_trans2 = cifs_check_trans2, 1343 1162 .need_neg = cifs_need_neg, 1344 1163 .negotiate = cifs_negotiate, 1345 - .negotiate_wsize = cifs_negotiate_wsize, 1346 - .negotiate_rsize = cifs_negotiate_rsize, 1164 + .negotiate_wsize = smb1_negotiate_wsize, 1165 + .negotiate_rsize = smb1_negotiate_rsize, 1347 1166 .sess_setup = CIFS_SessSetup, 1348 1167 .logoff = CIFSSMBLogoff, 1349 1168 .tree_connect = CIFSTCon,
+3 -6
fs/smb/client/smb2pdu.c
··· 2921 2921 req->CreateContextsOffset = cpu_to_le32( 2922 2922 sizeof(struct smb2_create_req) + 2923 2923 iov[1].iov_len); 2924 + le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len); 2924 2925 pc_buf = iov[n_iov-1].iov_base; 2925 2926 } 2926 2927 ··· 4093 4092 return; 4094 4093 4095 4094 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 - } 4095 + list_for_each_entry(cifs_sb, &tcon->cifs_sb_list, tcon_sb_link) 4096 + cifs_negotiate_iosize(server, cifs_sb->ctx, tcon); 4102 4097 spin_unlock(&tcon->sb_list_lock); 4103 4098 } 4104 4099