Skip to content

Commit 62b5a46

Browse files
committed
Merge tag '6.13-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - DFS fix (for race with tree disconnect and dfs cache worker) - Four fixes for SMB3.1.1 posix extensions: - improve special file support e.g. to Samba, retrieving the file type earlier - reduce roundtrips (e.g. on ls -l, in some cases) * tag '6.13-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: fix potential race in cifs_put_tcon() smb3.1.1: fix posix mounts to older servers fs/smb/client: cifs_prime_dcache() for SMB3 POSIX reparse points fs/smb/client: Implement new SMB3 POSIX type fs/smb/client: avoid querying SMB2_OP_QUERY_WSL_EA for SMB3 POSIX
2 parents c94cd02 + c32b624 commit 62b5a46

File tree

6 files changed

+175
-65
lines changed

6 files changed

+175
-65
lines changed

fs/smb/client/cifsproto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
669669
int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
670670
struct dentry *dentry, struct cifs_tcon *tcon,
671671
const char *full_path, umode_t mode, dev_t dev);
672+
umode_t wire_mode_to_posix(u32 wire, bool is_dir);
672673

673674
#ifdef CONFIG_CIFS_DFS_UPCALL
674675
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,

fs/smb/client/connect.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,16 +2532,14 @@ cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
25322532

25332533
list_del_init(&tcon->tcon_list);
25342534
tcon->status = TID_EXITING;
2535-
#ifdef CONFIG_CIFS_DFS_UPCALL
2536-
list_replace_init(&tcon->dfs_ses_list, &ses_list);
2537-
#endif
25382535
spin_unlock(&tcon->tc_lock);
25392536
spin_unlock(&cifs_tcp_ses_lock);
25402537

25412538
/* cancel polling of interfaces */
25422539
cancel_delayed_work_sync(&tcon->query_interfaces);
25432540
#ifdef CONFIG_CIFS_DFS_UPCALL
25442541
cancel_delayed_work_sync(&tcon->dfs_cache_work);
2542+
list_replace_init(&tcon->dfs_ses_list, &ses_list);
25452543
#endif
25462544

25472545
if (tcon->use_witness) {

fs/smb/client/inode.c

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,88 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
746746
#endif
747747
}
748748

749+
#define POSIX_TYPE_FILE 0
750+
#define POSIX_TYPE_DIR 1
751+
#define POSIX_TYPE_SYMLINK 2
752+
#define POSIX_TYPE_CHARDEV 3
753+
#define POSIX_TYPE_BLKDEV 4
754+
#define POSIX_TYPE_FIFO 5
755+
#define POSIX_TYPE_SOCKET 6
756+
757+
#define POSIX_X_OTH 0000001
758+
#define POSIX_W_OTH 0000002
759+
#define POSIX_R_OTH 0000004
760+
#define POSIX_X_GRP 0000010
761+
#define POSIX_W_GRP 0000020
762+
#define POSIX_R_GRP 0000040
763+
#define POSIX_X_USR 0000100
764+
#define POSIX_W_USR 0000200
765+
#define POSIX_R_USR 0000400
766+
#define POSIX_STICKY 0001000
767+
#define POSIX_SET_GID 0002000
768+
#define POSIX_SET_UID 0004000
769+
770+
#define POSIX_OTH_MASK 0000007
771+
#define POSIX_GRP_MASK 0000070
772+
#define POSIX_USR_MASK 0000700
773+
#define POSIX_PERM_MASK 0000777
774+
#define POSIX_FILETYPE_MASK 0070000
775+
776+
#define POSIX_FILETYPE_SHIFT 12
777+
778+
static u32 wire_perms_to_posix(u32 wire)
779+
{
780+
u32 mode = 0;
781+
782+
mode |= (wire & POSIX_X_OTH) ? S_IXOTH : 0;
783+
mode |= (wire & POSIX_W_OTH) ? S_IWOTH : 0;
784+
mode |= (wire & POSIX_R_OTH) ? S_IROTH : 0;
785+
mode |= (wire & POSIX_X_GRP) ? S_IXGRP : 0;
786+
mode |= (wire & POSIX_W_GRP) ? S_IWGRP : 0;
787+
mode |= (wire & POSIX_R_GRP) ? S_IRGRP : 0;
788+
mode |= (wire & POSIX_X_USR) ? S_IXUSR : 0;
789+
mode |= (wire & POSIX_W_USR) ? S_IWUSR : 0;
790+
mode |= (wire & POSIX_R_USR) ? S_IRUSR : 0;
791+
mode |= (wire & POSIX_STICKY) ? S_ISVTX : 0;
792+
mode |= (wire & POSIX_SET_GID) ? S_ISGID : 0;
793+
mode |= (wire & POSIX_SET_UID) ? S_ISUID : 0;
794+
795+
return mode;
796+
}
797+
798+
static u32 posix_filetypes[] = {
799+
S_IFREG,
800+
S_IFDIR,
801+
S_IFLNK,
802+
S_IFCHR,
803+
S_IFBLK,
804+
S_IFIFO,
805+
S_IFSOCK
806+
};
807+
808+
static u32 wire_filetype_to_posix(u32 wire_type)
809+
{
810+
if (wire_type >= ARRAY_SIZE(posix_filetypes)) {
811+
pr_warn("Unexpected type %u", wire_type);
812+
return 0;
813+
}
814+
return posix_filetypes[wire_type];
815+
}
816+
817+
umode_t wire_mode_to_posix(u32 wire, bool is_dir)
818+
{
819+
u32 wire_type;
820+
u32 mode;
821+
822+
wire_type = (wire & POSIX_FILETYPE_MASK) >> POSIX_FILETYPE_SHIFT;
823+
/* older servers do not set POSIX file type in the mode field in the response */
824+
if ((wire_type == 0) && is_dir)
825+
mode = wire_perms_to_posix(wire) | S_IFDIR;
826+
else
827+
mode = (wire_perms_to_posix(wire) | wire_filetype_to_posix(wire_type));
828+
return (umode_t)mode;
829+
}
830+
749831
/* Fill a cifs_fattr struct with info from POSIX info struct */
750832
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
751833
struct cifs_open_info_data *data,
@@ -782,20 +864,14 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
782864
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
783865
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
784866
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
785-
fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode);
867+
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode),
868+
fattr->cf_cifsattrs & ATTR_DIRECTORY);
786869

787870
if (cifs_open_data_reparse(data) &&
788871
cifs_reparse_point_to_fattr(cifs_sb, fattr, data))
789872
goto out_reparse;
790873

791-
fattr->cf_mode &= ~S_IFMT;
792-
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
793-
fattr->cf_mode |= S_IFDIR;
794-
fattr->cf_dtype = DT_DIR;
795-
} else { /* file */
796-
fattr->cf_mode |= S_IFREG;
797-
fattr->cf_dtype = DT_REG;
798-
}
874+
fattr->cf_dtype = S_DT(fattr->cf_mode);
799875

800876
out_reparse:
801877
if (S_ISLNK(fattr->cf_mode)) {

fs/smb/client/readdir.c

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
7171
struct inode *inode;
7272
struct super_block *sb = parent->d_sb;
7373
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
74+
bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
75+
bool reparse_need_reval = false;
7476
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
7577
int rc;
7678

@@ -85,7 +87,21 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
8587
* this spares us an invalidation.
8688
*/
8789
retry:
88-
if ((fattr->cf_cifsattrs & ATTR_REPARSE) ||
90+
if (posix) {
91+
switch (fattr->cf_mode & S_IFMT) {
92+
case S_IFLNK:
93+
case S_IFBLK:
94+
case S_IFCHR:
95+
reparse_need_reval = true;
96+
break;
97+
default:
98+
break;
99+
}
100+
} else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
101+
reparse_need_reval = true;
102+
}
103+
104+
if (reparse_need_reval ||
89105
(fattr->cf_flags & CIFS_FATTR_NEED_REVAL))
90106
return;
91107

@@ -241,31 +257,29 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
241257
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
242258
fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
243259

244-
/*
245-
* Since we set the inode type below we need to mask off
246-
* to avoid strange results if bits set above.
247-
* XXX: why not make server&client use the type bits?
248-
*/
249-
fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT;
260+
if (fattr->cf_cifsattrs & ATTR_REPARSE)
261+
fattr->cf_cifstag = le32_to_cpu(info->ReparseTag);
262+
263+
/* The Mode field in the response can now include the file type as well */
264+
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode),
265+
fattr->cf_cifsattrs & ATTR_DIRECTORY);
266+
fattr->cf_dtype = S_DT(le32_to_cpu(info->Mode));
267+
268+
switch (fattr->cf_mode & S_IFMT) {
269+
case S_IFLNK:
270+
case S_IFBLK:
271+
case S_IFCHR:
272+
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
273+
break;
274+
default:
275+
break;
276+
}
250277

251278
cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o\n",
252279
le32_to_cpu(info->DeviceId),
253280
le32_to_cpu(info->ReparseTag),
254281
le32_to_cpu(info->Mode));
255282

256-
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
257-
fattr->cf_mode |= S_IFDIR;
258-
fattr->cf_dtype = DT_DIR;
259-
} else {
260-
/*
261-
* mark anything that is not a dir as regular
262-
* file. special files should have the REPARSE
263-
* attribute and will be marked as needing revaluation
264-
*/
265-
fattr->cf_mode |= S_IFREG;
266-
fattr->cf_dtype = DT_REG;
267-
}
268-
269283
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
270284
sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
271285
}

fs/smb/client/reparse.c

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -803,44 +803,60 @@ static void wsl_to_fattr(struct cifs_open_info_data *data,
803803
fattr->cf_dtype = S_DT(fattr->cf_mode);
804804
}
805805

806-
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
807-
struct cifs_fattr *fattr,
808-
struct cifs_open_info_data *data)
806+
static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb,
807+
struct cifs_fattr *fattr,
808+
struct cifs_open_info_data *data)
809809
{
810810
struct reparse_posix_data *buf = data->reparse.posix;
811-
u32 tag = data->reparse.tag;
812811

813-
if (tag == IO_REPARSE_TAG_NFS && buf) {
814-
if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType))
812+
813+
if (buf == NULL)
814+
return true;
815+
816+
if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) {
817+
WARN_ON_ONCE(1);
818+
return false;
819+
}
820+
821+
switch (le64_to_cpu(buf->InodeType)) {
822+
case NFS_SPECFILE_CHR:
823+
if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) {
824+
WARN_ON_ONCE(1);
815825
return false;
816-
switch (le64_to_cpu(buf->InodeType)) {
817-
case NFS_SPECFILE_CHR:
818-
if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)
819-
return false;
820-
fattr->cf_mode |= S_IFCHR;
821-
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
822-
break;
823-
case NFS_SPECFILE_BLK:
824-
if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8)
825-
return false;
826-
fattr->cf_mode |= S_IFBLK;
827-
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
828-
break;
829-
case NFS_SPECFILE_FIFO:
830-
fattr->cf_mode |= S_IFIFO;
831-
break;
832-
case NFS_SPECFILE_SOCK:
833-
fattr->cf_mode |= S_IFSOCK;
834-
break;
835-
case NFS_SPECFILE_LNK:
836-
fattr->cf_mode |= S_IFLNK;
837-
break;
838-
default:
826+
}
827+
fattr->cf_mode |= S_IFCHR;
828+
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
829+
break;
830+
case NFS_SPECFILE_BLK:
831+
if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) {
839832
WARN_ON_ONCE(1);
840833
return false;
841834
}
842-
goto out;
835+
fattr->cf_mode |= S_IFBLK;
836+
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
837+
break;
838+
case NFS_SPECFILE_FIFO:
839+
fattr->cf_mode |= S_IFIFO;
840+
break;
841+
case NFS_SPECFILE_SOCK:
842+
fattr->cf_mode |= S_IFSOCK;
843+
break;
844+
case NFS_SPECFILE_LNK:
845+
fattr->cf_mode |= S_IFLNK;
846+
break;
847+
default:
848+
WARN_ON_ONCE(1);
849+
return false;
843850
}
851+
return true;
852+
}
853+
854+
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
855+
struct cifs_fattr *fattr,
856+
struct cifs_open_info_data *data)
857+
{
858+
u32 tag = data->reparse.tag;
859+
bool ok;
844860

845861
switch (tag) {
846862
case IO_REPARSE_TAG_INTERNAL:
@@ -860,15 +876,19 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
860876
case IO_REPARSE_TAG_LX_BLK:
861877
wsl_to_fattr(data, cifs_sb, tag, fattr);
862878
break;
879+
case IO_REPARSE_TAG_NFS:
880+
ok = posix_reparse_to_fattr(cifs_sb, fattr, data);
881+
if (!ok)
882+
return false;
883+
break;
863884
case 0: /* SMB1 symlink */
864885
case IO_REPARSE_TAG_SYMLINK:
865-
case IO_REPARSE_TAG_NFS:
866886
fattr->cf_mode |= S_IFLNK;
867887
break;
868888
default:
869889
return false;
870890
}
871-
out:
891+
872892
fattr->cf_dtype = S_DT(fattr->cf_mode);
873893
return true;
874894
}

fs/smb/client/smb2inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,8 @@ int smb2_query_path_info(const unsigned int xid,
943943
if (rc || !data->reparse_point)
944944
goto out;
945945

946-
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
946+
if (!tcon->posix_extensions)
947+
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
947948
/*
948949
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
949950
* response.

0 commit comments

Comments
 (0)