Skip to content

Commit 6a832bc

Browse files
slowfranklinSteve French
authored andcommitted
fs/smb/client: Implement new SMB3 POSIX type
Fixes special files against current Samba. On the Samba server: insgesamt 20 131958 brw-r--r-- 1 root root 0, 0 15. Nov 12:04 blockdev 131965 crw-r--r-- 1 root root 1, 1 15. Nov 12:04 chardev 131966 prw-r--r-- 1 samba samba 0 15. Nov 12:05 fifo 131953 -rw-rwxrw-+ 2 samba samba 4 18. Nov 11:37 file 131953 -rw-rwxrw-+ 2 samba samba 4 18. Nov 11:37 hardlink 131957 lrwxrwxrwx 1 samba samba 4 15. Nov 12:03 symlink -> file 131954 -rwxrwxr-x+ 1 samba samba 0 18. Nov 15:28 symlinkoversmb Before: ls: cannot access '/mnt/smb3unix/posix/blockdev': No data available ls: cannot access '/mnt/smb3unix/posix/chardev': No data available ls: cannot access '/mnt/smb3unix/posix/symlinkoversmb': No data available ls: cannot access '/mnt/smb3unix/posix/fifo': No data available ls: cannot access '/mnt/smb3unix/posix/symlink': No data available total 16 ? -????????? ? ? ? ? ? blockdev ? -????????? ? ? ? ? ? chardev ? -????????? ? ? ? ? ? fifo 131953 -rw-rwxrw- 2 root samba 4 Nov 18 11:37 file 131953 -rw-rwxrw- 2 root samba 4 Nov 18 11:37 hardlink ? -????????? ? ? ? ? ? symlink ? -????????? ? ? ? ? ? symlinkoversmb After: insgesamt 21 131958 brw-r--r-- 1 root root 0, 0 15. Nov 12:04 blockdev 131965 crw-r--r-- 1 root root 1, 1 15. Nov 12:04 chardev 131966 prw-r--r-- 1 root samba 0 15. Nov 12:05 fifo 131953 -rw-rwxrw- 2 root samba 4 18. Nov 11:37 file 131953 -rw-rwxrw- 2 root samba 4 18. Nov 11:37 hardlink 131957 lrwxrwxrwx 1 root samba 4 15. Nov 12:03 symlink -> file 131954 lrwxrwxr-x 1 root samba 23 18. Nov 15:28 symlinkoversmb -> mnt/smb3unix/posix/file Cc: [email protected] Acked-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Ralph Boehme <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent ca4b2c4 commit 6a832bc

File tree

4 files changed

+149
-60
lines changed

4 files changed

+149
-60
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);
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/inode.c

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,84 @@ 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)
818+
{
819+
u32 wire_type;
820+
u32 mode;
821+
822+
wire_type = (wire & POSIX_FILETYPE_MASK) >> POSIX_FILETYPE_SHIFT;
823+
mode = (wire_perms_to_posix(wire) | wire_filetype_to_posix(wire_type));
824+
return (umode_t)mode;
825+
}
826+
749827
/* Fill a cifs_fattr struct with info from POSIX info struct */
750828
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
751829
struct cifs_open_info_data *data,
@@ -782,20 +860,13 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
782860
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
783861
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
784862
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
785-
fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode);
863+
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode));
786864

787865
if (cifs_open_data_reparse(data) &&
788866
cifs_reparse_point_to_fattr(cifs_sb, fattr, data))
789867
goto out_reparse;
790868

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-
}
869+
fattr->cf_dtype = S_DT(fattr->cf_mode);
799870

800871
out_reparse:
801872
if (S_ISLNK(fattr->cf_mode)) {

fs/smb/client/readdir.c

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -241,31 +241,28 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
241241
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
242242
fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
243243

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;
244+
if (fattr->cf_cifsattrs & ATTR_REPARSE)
245+
fattr->cf_cifstag = le32_to_cpu(info->ReparseTag);
246+
247+
/* The Mode field in the response can now include the file type as well */
248+
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode));
249+
fattr->cf_dtype = S_DT(le32_to_cpu(info->Mode));
250+
251+
switch (fattr->cf_mode & S_IFMT) {
252+
case S_IFLNK:
253+
case S_IFBLK:
254+
case S_IFCHR:
255+
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
256+
break;
257+
default:
258+
break;
259+
}
250260

251261
cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o\n",
252262
le32_to_cpu(info->DeviceId),
253263
le32_to_cpu(info->ReparseTag),
254264
le32_to_cpu(info->Mode));
255265

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-
269266
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
270267
sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
271268
}

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
}

0 commit comments

Comments
 (0)