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.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

+178 -68
+1
fs/smb/client/cifsproto.h
··· 669 669 int cifs_sfu_make_node(unsigned int xid, struct inode *inode, 670 670 struct dentry *dentry, struct cifs_tcon *tcon, 671 671 const char *full_path, umode_t mode, dev_t dev); 672 + umode_t wire_mode_to_posix(u32 wire, bool is_dir); 672 673 673 674 #ifdef CONFIG_CIFS_DFS_UPCALL 674 675 static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
+1 -3
fs/smb/client/connect.c
··· 2532 2532 2533 2533 list_del_init(&tcon->tcon_list); 2534 2534 tcon->status = TID_EXITING; 2535 - #ifdef CONFIG_CIFS_DFS_UPCALL 2536 - list_replace_init(&tcon->dfs_ses_list, &ses_list); 2537 - #endif 2538 2535 spin_unlock(&tcon->tc_lock); 2539 2536 spin_unlock(&cifs_tcp_ses_lock); 2540 2537 ··· 2539 2542 cancel_delayed_work_sync(&tcon->query_interfaces); 2540 2543 #ifdef CONFIG_CIFS_DFS_UPCALL 2541 2544 cancel_delayed_work_sync(&tcon->dfs_cache_work); 2545 + list_replace_init(&tcon->dfs_ses_list, &ses_list); 2542 2546 #endif 2543 2547 2544 2548 if (tcon->use_witness) {
+85 -9
fs/smb/client/inode.c
··· 746 746 #endif 747 747 } 748 748 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 + 749 831 /* Fill a cifs_fattr struct with info from POSIX info struct */ 750 832 static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 751 833 struct cifs_open_info_data *data, ··· 864 782 fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 865 783 fattr->cf_createtime = le64_to_cpu(info->CreationTime); 866 784 fattr->cf_nlink = le32_to_cpu(info->HardLinks); 867 - fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); 785 + fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode), 786 + fattr->cf_cifsattrs & ATTR_DIRECTORY); 868 787 869 788 if (cifs_open_data_reparse(data) && 870 789 cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) 871 790 goto out_reparse; 872 791 873 - fattr->cf_mode &= ~S_IFMT; 874 - if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 875 - fattr->cf_mode |= S_IFDIR; 876 - fattr->cf_dtype = DT_DIR; 877 - } else { /* file */ 878 - fattr->cf_mode |= S_IFREG; 879 - fattr->cf_dtype = DT_REG; 880 - } 792 + fattr->cf_dtype = S_DT(fattr->cf_mode); 881 793 882 794 out_reparse: 883 795 if (S_ISLNK(fattr->cf_mode)) {
+34 -20
fs/smb/client/readdir.c
··· 71 71 struct inode *inode; 72 72 struct super_block *sb = parent->d_sb; 73 73 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; 74 76 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 75 77 int rc; 76 78 ··· 87 85 * this spares us an invalidation. 88 86 */ 89 87 retry: 90 - if ((fattr->cf_cifsattrs & ATTR_REPARSE) || 88 + if (posix) { 89 + switch (fattr->cf_mode & S_IFMT) { 90 + case S_IFLNK: 91 + case S_IFBLK: 92 + case S_IFCHR: 93 + reparse_need_reval = true; 94 + break; 95 + default: 96 + break; 97 + } 98 + } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { 99 + reparse_need_reval = true; 100 + } 101 + 102 + if (reparse_need_reval || 91 103 (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)) 92 104 return; 93 105 ··· 257 241 fattr->cf_nlink = le32_to_cpu(info->HardLinks); 258 242 fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); 259 243 260 - /* 261 - * Since we set the inode type below we need to mask off 262 - * to avoid strange results if bits set above. 263 - * XXX: why not make server&client use the type bits? 264 - */ 265 - 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_cifsattrs & ATTR_DIRECTORY); 250 + fattr->cf_dtype = S_DT(le32_to_cpu(info->Mode)); 251 + 252 + switch (fattr->cf_mode & S_IFMT) { 253 + case S_IFLNK: 254 + case S_IFBLK: 255 + case S_IFCHR: 256 + fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; 257 + break; 258 + default: 259 + break; 260 + } 266 261 267 262 cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o\n", 268 263 le32_to_cpu(info->DeviceId), 269 264 le32_to_cpu(info->ReparseTag), 270 265 le32_to_cpu(info->Mode)); 271 - 272 - if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 273 - fattr->cf_mode |= S_IFDIR; 274 - fattr->cf_dtype = DT_DIR; 275 - } else { 276 - /* 277 - * mark anything that is not a dir as regular 278 - * file. special files should have the REPARSE 279 - * attribute and will be marked as needing revaluation 280 - */ 281 - fattr->cf_mode |= S_IFREG; 282 - fattr->cf_dtype = DT_REG; 283 - } 284 266 285 267 sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER); 286 268 sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
+55 -35
fs/smb/client/reparse.c
··· 803 803 fattr->cf_dtype = S_DT(fattr->cf_mode); 804 804 } 805 805 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) 809 + { 810 + struct reparse_posix_data *buf = data->reparse.posix; 811 + 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); 825 + return false; 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) { 832 + WARN_ON_ONCE(1); 833 + return false; 834 + } 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; 850 + } 851 + return true; 852 + } 853 + 806 854 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 807 855 struct cifs_fattr *fattr, 808 856 struct cifs_open_info_data *data) 809 857 { 810 - struct reparse_posix_data *buf = data->reparse.posix; 811 858 u32 tag = data->reparse.tag; 812 - 813 - if (tag == IO_REPARSE_TAG_NFS && buf) { 814 - if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) 815 - 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: 839 - WARN_ON_ONCE(1); 840 - return false; 841 - } 842 - goto out; 843 - } 859 + bool ok; 844 860 845 861 switch (tag) { 846 862 case IO_REPARSE_TAG_INTERNAL: ··· 876 860 case IO_REPARSE_TAG_LX_BLK: 877 861 wsl_to_fattr(data, cifs_sb, tag, fattr); 878 862 break; 863 + case IO_REPARSE_TAG_NFS: 864 + ok = posix_reparse_to_fattr(cifs_sb, fattr, data); 865 + if (!ok) 866 + return false; 867 + break; 879 868 case 0: /* SMB1 symlink */ 880 869 case IO_REPARSE_TAG_SYMLINK: 881 - case IO_REPARSE_TAG_NFS: 882 870 fattr->cf_mode |= S_IFLNK; 883 871 break; 884 872 default: 885 873 return false; 886 874 } 887 - out: 875 + 888 876 fattr->cf_dtype = S_DT(fattr->cf_mode); 889 877 return true; 890 878 }
+2 -1
fs/smb/client/smb2inode.c
··· 943 943 if (rc || !data->reparse_point) 944 944 goto out; 945 945 946 - cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 946 + if (!tcon->posix_extensions) 947 + cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 947 948 /* 948 949 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create 949 950 * response.