.. | .. |
---|
25 | 25 | #include <linux/freezer.h> |
---|
26 | 26 | #include <linux/sched/signal.h> |
---|
27 | 27 | #include <linux/wait_bit.h> |
---|
| 28 | +#include <linux/fiemap.h> |
---|
28 | 29 | |
---|
29 | 30 | #include <asm/div64.h> |
---|
30 | 31 | #include "cifsfs.h" |
---|
31 | 32 | #include "cifspdu.h" |
---|
32 | 33 | #include "cifsglob.h" |
---|
33 | 34 | #include "cifsproto.h" |
---|
| 35 | +#include "smb2proto.h" |
---|
34 | 36 | #include "cifs_debug.h" |
---|
35 | 37 | #include "cifs_fs_sb.h" |
---|
36 | 38 | #include "cifs_unicode.h" |
---|
.. | .. |
---|
61 | 63 | } |
---|
62 | 64 | |
---|
63 | 65 | /* check if server can support readpages */ |
---|
64 | | - if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < |
---|
| 66 | + if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read < |
---|
65 | 67 | PAGE_SIZE + MAX_CIFS_HDR_SIZE) |
---|
66 | 68 | inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
---|
67 | 69 | else |
---|
.. | .. |
---|
113 | 115 | } |
---|
114 | 116 | |
---|
115 | 117 | /* revalidate if mtime or size have changed */ |
---|
| 118 | + fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); |
---|
116 | 119 | if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) && |
---|
117 | 120 | cifs_i->server_eof == fattr->cf_eof) { |
---|
118 | 121 | cifs_dbg(FYI, "%s: inode %llu is unchanged\n", |
---|
.. | .. |
---|
162 | 165 | cifs_revalidate_cache(inode, fattr); |
---|
163 | 166 | |
---|
164 | 167 | spin_lock(&inode->i_lock); |
---|
165 | | - inode->i_atime = fattr->cf_atime; |
---|
| 168 | + fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); |
---|
| 169 | + fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode); |
---|
| 170 | + fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode); |
---|
| 171 | + /* we do not want atime to be less than mtime, it broke some apps */ |
---|
| 172 | + if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0) |
---|
| 173 | + inode->i_atime = fattr->cf_mtime; |
---|
| 174 | + else |
---|
| 175 | + inode->i_atime = fattr->cf_atime; |
---|
166 | 176 | inode->i_mtime = fattr->cf_mtime; |
---|
167 | 177 | inode->i_ctime = fattr->cf_ctime; |
---|
168 | 178 | inode->i_rdev = fattr->cf_rdev; |
---|
.. | .. |
---|
325 | 335 | fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; |
---|
326 | 336 | fattr->cf_uid = cifs_sb->mnt_uid; |
---|
327 | 337 | fattr->cf_gid = cifs_sb->mnt_gid; |
---|
328 | | - ktime_get_real_ts64(&fattr->cf_mtime); |
---|
329 | | - fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran); |
---|
| 338 | + ktime_get_coarse_real_ts64(&fattr->cf_mtime); |
---|
330 | 339 | fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; |
---|
331 | 340 | fattr->cf_nlink = 2; |
---|
332 | | - fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; |
---|
| 341 | + fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL; |
---|
333 | 342 | } |
---|
334 | 343 | |
---|
335 | 344 | static int |
---|
.. | .. |
---|
351 | 360 | } else if (rc == -EREMOTE) { |
---|
352 | 361 | cifs_create_dfs_fattr(&fattr, inode->i_sb); |
---|
353 | 362 | rc = 0; |
---|
354 | | - } |
---|
| 363 | + } else |
---|
| 364 | + goto cifs_gfiunix_out; |
---|
355 | 365 | |
---|
356 | 366 | cifs_fattr_to_inode(inode, &fattr); |
---|
| 367 | + |
---|
| 368 | +cifs_gfiunix_out: |
---|
357 | 369 | free_xid(xid); |
---|
358 | 370 | return rc; |
---|
359 | 371 | } |
---|
.. | .. |
---|
416 | 428 | } |
---|
417 | 429 | |
---|
418 | 430 | /* if filetype is different, return error */ |
---|
419 | | - if (unlikely(((*pinode)->i_mode & S_IFMT) != |
---|
420 | | - (fattr.cf_mode & S_IFMT))) { |
---|
| 431 | + if (unlikely(inode_wrong_type(*pinode, fattr.cf_mode))) { |
---|
421 | 432 | CIFS_I(*pinode)->time = 0; /* force reval */ |
---|
422 | 433 | rc = -ESTALE; |
---|
423 | 434 | goto cgiiu_exit; |
---|
.. | .. |
---|
440 | 451 | struct cifs_tcon *tcon; |
---|
441 | 452 | struct cifs_fid fid; |
---|
442 | 453 | struct cifs_open_parms oparms; |
---|
443 | | - struct cifs_io_parms io_parms; |
---|
| 454 | + struct cifs_io_parms io_parms = {0}; |
---|
444 | 455 | char buf[24]; |
---|
445 | 456 | unsigned int bytes_read; |
---|
446 | 457 | char *pbuf; |
---|
.. | .. |
---|
468 | 479 | oparms.tcon = tcon; |
---|
469 | 480 | oparms.cifs_sb = cifs_sb; |
---|
470 | 481 | oparms.desired_access = GENERIC_READ; |
---|
471 | | - oparms.create_options = CREATE_NOT_DIR; |
---|
472 | | - if (backup_cred(cifs_sb)) |
---|
473 | | - oparms.create_options |= CREATE_OPEN_BACKUP_INTENT; |
---|
| 482 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR); |
---|
474 | 483 | oparms.disposition = FILE_OPEN; |
---|
475 | 484 | oparms.path = path; |
---|
476 | 485 | oparms.fid = &fid; |
---|
.. | .. |
---|
589 | 598 | #endif |
---|
590 | 599 | } |
---|
591 | 600 | |
---|
| 601 | +/* Fill a cifs_fattr struct with info from POSIX info struct */ |
---|
| 602 | +static void |
---|
| 603 | +smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info, |
---|
| 604 | + struct super_block *sb, bool adjust_tz, bool symlink) |
---|
| 605 | +{ |
---|
| 606 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
| 607 | + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
---|
| 608 | + |
---|
| 609 | + memset(fattr, 0, sizeof(*fattr)); |
---|
| 610 | + |
---|
| 611 | + /* no fattr->flags to set */ |
---|
| 612 | + fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); |
---|
| 613 | + fattr->cf_uniqueid = le64_to_cpu(info->Inode); |
---|
| 614 | + |
---|
| 615 | + if (info->LastAccessTime) |
---|
| 616 | + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
---|
| 617 | + else |
---|
| 618 | + ktime_get_coarse_real_ts64(&fattr->cf_atime); |
---|
| 619 | + |
---|
| 620 | + fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
---|
| 621 | + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
---|
| 622 | + |
---|
| 623 | + if (adjust_tz) { |
---|
| 624 | + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; |
---|
| 625 | + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; |
---|
| 626 | + } |
---|
| 627 | + |
---|
| 628 | + fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
---|
| 629 | + fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
---|
| 630 | + fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
---|
| 631 | + |
---|
| 632 | + fattr->cf_nlink = le32_to_cpu(info->HardLinks); |
---|
| 633 | + fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); |
---|
| 634 | + /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ |
---|
| 635 | + /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ |
---|
| 636 | + |
---|
| 637 | + if (symlink) { |
---|
| 638 | + fattr->cf_mode |= S_IFLNK; |
---|
| 639 | + fattr->cf_dtype = DT_LNK; |
---|
| 640 | + } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
---|
| 641 | + fattr->cf_mode |= S_IFDIR; |
---|
| 642 | + fattr->cf_dtype = DT_DIR; |
---|
| 643 | + } else { /* file */ |
---|
| 644 | + fattr->cf_mode |= S_IFREG; |
---|
| 645 | + fattr->cf_dtype = DT_REG; |
---|
| 646 | + } |
---|
| 647 | + /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ |
---|
| 648 | + |
---|
| 649 | + fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */ |
---|
| 650 | + fattr->cf_gid = cifs_sb->mnt_gid; |
---|
| 651 | + |
---|
| 652 | + cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", |
---|
| 653 | + fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); |
---|
| 654 | +} |
---|
| 655 | + |
---|
| 656 | + |
---|
592 | 657 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
---|
593 | 658 | static void |
---|
594 | 659 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
---|
595 | 660 | struct super_block *sb, bool adjust_tz, |
---|
596 | | - bool symlink) |
---|
| 661 | + bool symlink, u32 reparse_tag) |
---|
597 | 662 | { |
---|
598 | 663 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
599 | 664 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
---|
.. | .. |
---|
605 | 670 | |
---|
606 | 671 | if (info->LastAccessTime) |
---|
607 | 672 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
---|
608 | | - else { |
---|
609 | | - ktime_get_real_ts64(&fattr->cf_atime); |
---|
610 | | - fattr->cf_atime = timespec64_trunc(fattr->cf_atime, sb->s_time_gran); |
---|
611 | | - } |
---|
| 673 | + else |
---|
| 674 | + ktime_get_coarse_real_ts64(&fattr->cf_atime); |
---|
612 | 675 | |
---|
613 | 676 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
---|
614 | 677 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
---|
.. | .. |
---|
623 | 686 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
---|
624 | 687 | |
---|
625 | 688 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); |
---|
626 | | - |
---|
627 | | - if (symlink) { |
---|
| 689 | + if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) { |
---|
| 690 | + fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode; |
---|
| 691 | + fattr->cf_dtype = DT_LNK; |
---|
| 692 | + } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) { |
---|
| 693 | + fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode; |
---|
| 694 | + fattr->cf_dtype = DT_FIFO; |
---|
| 695 | + } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) { |
---|
| 696 | + fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode; |
---|
| 697 | + fattr->cf_dtype = DT_SOCK; |
---|
| 698 | + } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) { |
---|
| 699 | + fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode; |
---|
| 700 | + fattr->cf_dtype = DT_CHR; |
---|
| 701 | + } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) { |
---|
| 702 | + fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode; |
---|
| 703 | + fattr->cf_dtype = DT_BLK; |
---|
| 704 | + } else if (symlink) { /* TODO add more reparse tag checks */ |
---|
628 | 705 | fattr->cf_mode = S_IFLNK; |
---|
629 | 706 | fattr->cf_dtype = DT_LNK; |
---|
630 | 707 | } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
---|
.. | .. |
---|
650 | 727 | */ |
---|
651 | 728 | if ((fattr->cf_nlink < 1) && !tcon->unix_ext && |
---|
652 | 729 | !info->DeletePending) { |
---|
653 | | - cifs_dbg(1, "bogus file nlink value %u\n", |
---|
654 | | - fattr->cf_nlink); |
---|
| 730 | + cifs_dbg(VFS, "bogus file nlink value %u\n", |
---|
| 731 | + fattr->cf_nlink); |
---|
655 | 732 | fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; |
---|
656 | 733 | } |
---|
657 | 734 | } |
---|
.. | .. |
---|
679 | 756 | rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); |
---|
680 | 757 | switch (rc) { |
---|
681 | 758 | case 0: |
---|
| 759 | + /* TODO: add support to query reparse tag */ |
---|
682 | 760 | cifs_all_info_to_fattr(&fattr, &find_data, inode->i_sb, false, |
---|
683 | | - false); |
---|
| 761 | + false, 0 /* no reparse tag */); |
---|
684 | 762 | break; |
---|
685 | 763 | case -EREMOTE: |
---|
686 | 764 | cifs_create_dfs_fattr(&fattr, inode->i_sb); |
---|
.. | .. |
---|
723 | 801 | return hash; |
---|
724 | 802 | } |
---|
725 | 803 | |
---|
| 804 | +/** |
---|
| 805 | + * cifs_backup_query_path_info - SMB1 fallback code to get ino |
---|
| 806 | + * |
---|
| 807 | + * Fallback code to get file metadata when we don't have access to |
---|
| 808 | + * @full_path (EACCES) and have backup creds. |
---|
| 809 | + * |
---|
| 810 | + * @data will be set to search info result buffer |
---|
| 811 | + * @resp_buf will be set to cifs resp buf and needs to be freed with |
---|
| 812 | + * cifs_buf_release() when done with @data. |
---|
| 813 | + */ |
---|
| 814 | +static int |
---|
| 815 | +cifs_backup_query_path_info(int xid, |
---|
| 816 | + struct cifs_tcon *tcon, |
---|
| 817 | + struct super_block *sb, |
---|
| 818 | + const char *full_path, |
---|
| 819 | + void **resp_buf, |
---|
| 820 | + FILE_ALL_INFO **data) |
---|
| 821 | +{ |
---|
| 822 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
| 823 | + struct cifs_search_info info = {0}; |
---|
| 824 | + u16 flags; |
---|
| 825 | + int rc; |
---|
| 826 | + |
---|
| 827 | + *resp_buf = NULL; |
---|
| 828 | + info.endOfSearch = false; |
---|
| 829 | + if (tcon->unix_ext) |
---|
| 830 | + info.info_level = SMB_FIND_FILE_UNIX; |
---|
| 831 | + else if ((tcon->ses->capabilities & |
---|
| 832 | + tcon->ses->server->vals->cap_nt_find) == 0) |
---|
| 833 | + info.info_level = SMB_FIND_FILE_INFO_STANDARD; |
---|
| 834 | + else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
---|
| 835 | + info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; |
---|
| 836 | + else /* no srvino useful for fallback to some netapp */ |
---|
| 837 | + info.info_level = SMB_FIND_FILE_DIRECTORY_INFO; |
---|
| 838 | + |
---|
| 839 | + flags = CIFS_SEARCH_CLOSE_ALWAYS | |
---|
| 840 | + CIFS_SEARCH_CLOSE_AT_END | |
---|
| 841 | + CIFS_SEARCH_BACKUP_SEARCH; |
---|
| 842 | + |
---|
| 843 | + rc = CIFSFindFirst(xid, tcon, full_path, |
---|
| 844 | + cifs_sb, NULL, flags, &info, false); |
---|
| 845 | + if (rc) |
---|
| 846 | + return rc; |
---|
| 847 | + |
---|
| 848 | + *resp_buf = (void *)info.ntwrk_buf_start; |
---|
| 849 | + *data = (FILE_ALL_INFO *)info.srch_entries_start; |
---|
| 850 | + return 0; |
---|
| 851 | +} |
---|
| 852 | + |
---|
| 853 | +static void |
---|
| 854 | +cifs_set_fattr_ino(int xid, |
---|
| 855 | + struct cifs_tcon *tcon, |
---|
| 856 | + struct super_block *sb, |
---|
| 857 | + struct inode **inode, |
---|
| 858 | + const char *full_path, |
---|
| 859 | + FILE_ALL_INFO *data, |
---|
| 860 | + struct cifs_fattr *fattr) |
---|
| 861 | +{ |
---|
| 862 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
| 863 | + struct TCP_Server_Info *server = tcon->ses->server; |
---|
| 864 | + int rc; |
---|
| 865 | + |
---|
| 866 | + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { |
---|
| 867 | + if (*inode) |
---|
| 868 | + fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
| 869 | + else |
---|
| 870 | + fattr->cf_uniqueid = iunique(sb, ROOT_I); |
---|
| 871 | + return; |
---|
| 872 | + } |
---|
| 873 | + |
---|
| 874 | + /* |
---|
| 875 | + * If we have an inode pass a NULL tcon to ensure we don't |
---|
| 876 | + * make a round trip to the server. This only works for SMB2+. |
---|
| 877 | + */ |
---|
| 878 | + rc = server->ops->get_srv_inum(xid, |
---|
| 879 | + *inode ? NULL : tcon, |
---|
| 880 | + cifs_sb, full_path, |
---|
| 881 | + &fattr->cf_uniqueid, |
---|
| 882 | + data); |
---|
| 883 | + if (rc) { |
---|
| 884 | + /* |
---|
| 885 | + * If that fails reuse existing ino or generate one |
---|
| 886 | + * and disable server ones |
---|
| 887 | + */ |
---|
| 888 | + if (*inode) |
---|
| 889 | + fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
| 890 | + else { |
---|
| 891 | + fattr->cf_uniqueid = iunique(sb, ROOT_I); |
---|
| 892 | + cifs_autodisable_serverino(cifs_sb); |
---|
| 893 | + } |
---|
| 894 | + return; |
---|
| 895 | + } |
---|
| 896 | + |
---|
| 897 | + /* If no errors, check for zero root inode (invalid) */ |
---|
| 898 | + if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) { |
---|
| 899 | + cifs_dbg(FYI, "Invalid (0) inodenum\n"); |
---|
| 900 | + if (*inode) { |
---|
| 901 | + /* reuse */ |
---|
| 902 | + fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
| 903 | + } else { |
---|
| 904 | + /* make an ino by hashing the UNC */ |
---|
| 905 | + fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO; |
---|
| 906 | + fattr->cf_uniqueid = simple_hashstr(tcon->treeName); |
---|
| 907 | + } |
---|
| 908 | + } |
---|
| 909 | +} |
---|
| 910 | + |
---|
| 911 | +static inline bool is_inode_cache_good(struct inode *ino) |
---|
| 912 | +{ |
---|
| 913 | + return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0; |
---|
| 914 | +} |
---|
| 915 | + |
---|
726 | 916 | int |
---|
727 | | -cifs_get_inode_info(struct inode **inode, const char *full_path, |
---|
728 | | - FILE_ALL_INFO *data, struct super_block *sb, int xid, |
---|
| 917 | +cifs_get_inode_info(struct inode **inode, |
---|
| 918 | + const char *full_path, |
---|
| 919 | + FILE_ALL_INFO *in_data, |
---|
| 920 | + struct super_block *sb, int xid, |
---|
729 | 921 | const struct cifs_fid *fid) |
---|
730 | 922 | { |
---|
731 | | - bool validinum = false; |
---|
732 | | - __u16 srchflgs; |
---|
733 | | - int rc = 0, tmprc = ENOSYS; |
---|
| 923 | + |
---|
734 | 924 | struct cifs_tcon *tcon; |
---|
735 | 925 | struct TCP_Server_Info *server; |
---|
736 | 926 | struct tcon_link *tlink; |
---|
737 | 927 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
738 | | - char *buf = NULL; |
---|
739 | 928 | bool adjust_tz = false; |
---|
740 | | - struct cifs_fattr fattr; |
---|
741 | | - struct cifs_search_info *srchinf = NULL; |
---|
742 | | - bool symlink = false; |
---|
| 929 | + struct cifs_fattr fattr = {0}; |
---|
| 930 | + bool is_reparse_point = false; |
---|
| 931 | + FILE_ALL_INFO *data = in_data; |
---|
| 932 | + FILE_ALL_INFO *tmp_data = NULL; |
---|
| 933 | + void *smb1_backup_rsp_buf = NULL; |
---|
| 934 | + int rc = 0; |
---|
| 935 | + int tmprc = 0; |
---|
| 936 | + __u32 reparse_tag = 0; |
---|
743 | 937 | |
---|
744 | 938 | tlink = cifs_sb_tlink(cifs_sb); |
---|
745 | 939 | if (IS_ERR(tlink)) |
---|
.. | .. |
---|
747 | 941 | tcon = tlink_tcon(tlink); |
---|
748 | 942 | server = tcon->ses->server; |
---|
749 | 943 | |
---|
750 | | - cifs_dbg(FYI, "Getting info on %s\n", full_path); |
---|
| 944 | + /* |
---|
| 945 | + * 1. Fetch file metadata if not provided (data) |
---|
| 946 | + */ |
---|
751 | 947 | |
---|
752 | | - if ((data == NULL) && (*inode != NULL)) { |
---|
753 | | - if (CIFS_CACHE_READ(CIFS_I(*inode)) && |
---|
754 | | - CIFS_I(*inode)->time != 0) { |
---|
| 948 | + if (!data) { |
---|
| 949 | + if (is_inode_cache_good(*inode)) { |
---|
755 | 950 | cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); |
---|
756 | | - goto cgii_exit; |
---|
| 951 | + goto out; |
---|
757 | 952 | } |
---|
758 | | - } |
---|
759 | | - |
---|
760 | | - /* if inode info is not passed, get it from server */ |
---|
761 | | - if (data == NULL) { |
---|
762 | | - if (!server->ops->query_path_info) { |
---|
763 | | - rc = -ENOSYS; |
---|
764 | | - goto cgii_exit; |
---|
765 | | - } |
---|
766 | | - buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
---|
767 | | - if (buf == NULL) { |
---|
| 953 | + tmp_data = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
---|
| 954 | + if (!tmp_data) { |
---|
768 | 955 | rc = -ENOMEM; |
---|
769 | | - goto cgii_exit; |
---|
| 956 | + goto out; |
---|
770 | 957 | } |
---|
771 | | - data = (FILE_ALL_INFO *)buf; |
---|
772 | | - rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, |
---|
773 | | - data, &adjust_tz, &symlink); |
---|
| 958 | + rc = server->ops->query_path_info(xid, tcon, cifs_sb, |
---|
| 959 | + full_path, tmp_data, |
---|
| 960 | + &adjust_tz, &is_reparse_point); |
---|
| 961 | + data = tmp_data; |
---|
774 | 962 | } |
---|
775 | | - |
---|
776 | | - if (!rc) { |
---|
777 | | - cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz, |
---|
778 | | - symlink); |
---|
779 | | - } else if (rc == -EREMOTE) { |
---|
780 | | - cifs_create_dfs_fattr(&fattr, sb); |
---|
781 | | - rc = 0; |
---|
782 | | - } else if ((rc == -EACCES) && backup_cred(cifs_sb) && |
---|
783 | | - (strcmp(server->vals->version_string, SMB1_VERSION_STRING) |
---|
784 | | - == 0)) { |
---|
785 | | - /* |
---|
786 | | - * For SMB2 and later the backup intent flag is already |
---|
787 | | - * sent if needed on open and there is no path based |
---|
788 | | - * FindFirst operation to use to retry with |
---|
789 | | - */ |
---|
790 | | - |
---|
791 | | - srchinf = kzalloc(sizeof(struct cifs_search_info), |
---|
792 | | - GFP_KERNEL); |
---|
793 | | - if (srchinf == NULL) { |
---|
794 | | - rc = -ENOMEM; |
---|
795 | | - goto cgii_exit; |
---|
796 | | - } |
---|
797 | | - |
---|
798 | | - srchinf->endOfSearch = false; |
---|
799 | | - if (tcon->unix_ext) |
---|
800 | | - srchinf->info_level = SMB_FIND_FILE_UNIX; |
---|
801 | | - else if ((tcon->ses->capabilities & |
---|
802 | | - tcon->ses->server->vals->cap_nt_find) == 0) |
---|
803 | | - srchinf->info_level = SMB_FIND_FILE_INFO_STANDARD; |
---|
804 | | - else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
---|
805 | | - srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; |
---|
806 | | - else /* no srvino useful for fallback to some netapp */ |
---|
807 | | - srchinf->info_level = SMB_FIND_FILE_DIRECTORY_INFO; |
---|
808 | | - |
---|
809 | | - srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | |
---|
810 | | - CIFS_SEARCH_CLOSE_AT_END | |
---|
811 | | - CIFS_SEARCH_BACKUP_SEARCH; |
---|
812 | | - |
---|
813 | | - rc = CIFSFindFirst(xid, tcon, full_path, |
---|
814 | | - cifs_sb, NULL, srchflgs, srchinf, false); |
---|
815 | | - if (!rc) { |
---|
816 | | - data = (FILE_ALL_INFO *)srchinf->srch_entries_start; |
---|
817 | | - |
---|
818 | | - cifs_dir_info_to_fattr(&fattr, |
---|
819 | | - (FILE_DIRECTORY_INFO *)data, cifs_sb); |
---|
820 | | - fattr.cf_uniqueid = le64_to_cpu( |
---|
821 | | - ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); |
---|
822 | | - validinum = true; |
---|
823 | | - |
---|
824 | | - cifs_buf_release(srchinf->ntwrk_buf_start); |
---|
825 | | - } |
---|
826 | | - kfree(srchinf); |
---|
827 | | - if (rc) |
---|
828 | | - goto cgii_exit; |
---|
829 | | - } else |
---|
830 | | - goto cgii_exit; |
---|
831 | 963 | |
---|
832 | 964 | /* |
---|
833 | | - * If an inode wasn't passed in, then get the inode number |
---|
834 | | - * |
---|
835 | | - * Is an i_ino of zero legal? Can we use that to check if the server |
---|
836 | | - * supports returning inode numbers? Are there other sanity checks we |
---|
837 | | - * can use to ensure that the server is really filling in that field? |
---|
| 965 | + * 2. Convert it to internal cifs metadata (fattr) |
---|
838 | 966 | */ |
---|
839 | | - if (*inode == NULL) { |
---|
840 | | - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
---|
841 | | - if (validinum == false) { |
---|
842 | | - if (server->ops->get_srv_inum) |
---|
843 | | - tmprc = server->ops->get_srv_inum(xid, |
---|
844 | | - tcon, cifs_sb, full_path, |
---|
845 | | - &fattr.cf_uniqueid, data); |
---|
846 | | - if (tmprc) { |
---|
847 | | - cifs_dbg(FYI, "GetSrvInodeNum rc %d\n", |
---|
848 | | - tmprc); |
---|
849 | | - fattr.cf_uniqueid = iunique(sb, ROOT_I); |
---|
850 | | - cifs_autodisable_serverino(cifs_sb); |
---|
851 | | - } else if ((fattr.cf_uniqueid == 0) && |
---|
852 | | - strlen(full_path) == 0) { |
---|
853 | | - /* some servers ret bad root ino ie 0 */ |
---|
854 | | - cifs_dbg(FYI, "Invalid (0) inodenum\n"); |
---|
855 | | - fattr.cf_flags |= |
---|
856 | | - CIFS_FATTR_FAKE_ROOT_INO; |
---|
857 | | - fattr.cf_uniqueid = |
---|
858 | | - simple_hashstr(tcon->treeName); |
---|
859 | | - } |
---|
860 | | - } |
---|
861 | | - } else |
---|
862 | | - fattr.cf_uniqueid = iunique(sb, ROOT_I); |
---|
863 | | - } else { |
---|
864 | | - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && |
---|
865 | | - validinum == false && server->ops->get_srv_inum) { |
---|
866 | | - /* |
---|
867 | | - * Pass a NULL tcon to ensure we don't make a round |
---|
868 | | - * trip to the server. This only works for SMB2+. |
---|
869 | | - */ |
---|
870 | | - tmprc = server->ops->get_srv_inum(xid, |
---|
871 | | - NULL, cifs_sb, full_path, |
---|
872 | | - &fattr.cf_uniqueid, data); |
---|
873 | | - if (tmprc) |
---|
874 | | - fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
875 | | - else if ((fattr.cf_uniqueid == 0) && |
---|
876 | | - strlen(full_path) == 0) { |
---|
877 | | - /* |
---|
878 | | - * Reuse existing root inode num since |
---|
879 | | - * inum zero for root causes ls of . and .. to |
---|
880 | | - * not be returned |
---|
881 | | - */ |
---|
882 | | - cifs_dbg(FYI, "Srv ret 0 inode num for root\n"); |
---|
883 | | - fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
884 | | - } |
---|
885 | | - } else |
---|
886 | | - fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; |
---|
| 967 | + |
---|
| 968 | + switch (rc) { |
---|
| 969 | + case 0: |
---|
| 970 | + /* |
---|
| 971 | + * If the file is a reparse point, it is more complicated |
---|
| 972 | + * since we have to check if its reparse tag matches a known |
---|
| 973 | + * special file type e.g. symlink or fifo or char etc. |
---|
| 974 | + */ |
---|
| 975 | + if ((le32_to_cpu(data->Attributes) & ATTR_REPARSE) && |
---|
| 976 | + server->ops->query_reparse_tag) { |
---|
| 977 | + rc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, |
---|
| 978 | + full_path, &reparse_tag); |
---|
| 979 | + cifs_dbg(FYI, "reparse tag 0x%x\n", reparse_tag); |
---|
| 980 | + } |
---|
| 981 | + cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz, |
---|
| 982 | + is_reparse_point, reparse_tag); |
---|
| 983 | + break; |
---|
| 984 | + case -EREMOTE: |
---|
| 985 | + /* DFS link, no metadata available on this server */ |
---|
| 986 | + cifs_create_dfs_fattr(&fattr, sb); |
---|
| 987 | + rc = 0; |
---|
| 988 | + break; |
---|
| 989 | + case -EACCES: |
---|
| 990 | + /* |
---|
| 991 | + * perm errors, try again with backup flags if possible |
---|
| 992 | + * |
---|
| 993 | + * For SMB2 and later the backup intent flag |
---|
| 994 | + * is already sent if needed on open and there |
---|
| 995 | + * is no path based FindFirst operation to use |
---|
| 996 | + * to retry with |
---|
| 997 | + */ |
---|
| 998 | + if (backup_cred(cifs_sb) && is_smb1_server(server)) { |
---|
| 999 | + /* for easier reading */ |
---|
| 1000 | + FILE_DIRECTORY_INFO *fdi; |
---|
| 1001 | + SEARCH_ID_FULL_DIR_INFO *si; |
---|
| 1002 | + |
---|
| 1003 | + rc = cifs_backup_query_path_info(xid, tcon, sb, |
---|
| 1004 | + full_path, |
---|
| 1005 | + &smb1_backup_rsp_buf, |
---|
| 1006 | + &data); |
---|
| 1007 | + if (rc) |
---|
| 1008 | + goto out; |
---|
| 1009 | + |
---|
| 1010 | + fdi = (FILE_DIRECTORY_INFO *)data; |
---|
| 1011 | + si = (SEARCH_ID_FULL_DIR_INFO *)data; |
---|
| 1012 | + |
---|
| 1013 | + cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb); |
---|
| 1014 | + fattr.cf_uniqueid = le64_to_cpu(si->UniqueId); |
---|
| 1015 | + /* uniqueid set, skip get inum step */ |
---|
| 1016 | + goto handle_mnt_opt; |
---|
| 1017 | + } else { |
---|
| 1018 | + /* nothing we can do, bail out */ |
---|
| 1019 | + goto out; |
---|
| 1020 | + } |
---|
| 1021 | + break; |
---|
| 1022 | + default: |
---|
| 1023 | + cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); |
---|
| 1024 | + goto out; |
---|
887 | 1025 | } |
---|
888 | 1026 | |
---|
| 1027 | + /* |
---|
| 1028 | + * 3. Get or update inode number (fattr.cf_uniqueid) |
---|
| 1029 | + */ |
---|
| 1030 | + |
---|
| 1031 | + cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr); |
---|
| 1032 | + |
---|
| 1033 | + /* |
---|
| 1034 | + * 4. Tweak fattr based on mount options |
---|
| 1035 | + */ |
---|
| 1036 | + |
---|
| 1037 | +handle_mnt_opt: |
---|
889 | 1038 | /* query for SFU type info if supported and needed */ |
---|
890 | 1039 | if (fattr.cf_cifsattrs & ATTR_SYSTEM && |
---|
891 | 1040 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
---|
.. | .. |
---|
894 | 1043 | cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); |
---|
895 | 1044 | } |
---|
896 | 1045 | |
---|
897 | | -#ifdef CONFIG_CIFS_ACL |
---|
898 | 1046 | /* fill in 0777 bits from ACL */ |
---|
899 | | - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
---|
900 | | - rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid); |
---|
| 1047 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { |
---|
| 1048 | + rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true, |
---|
| 1049 | + full_path, fid); |
---|
| 1050 | + if (rc == -EREMOTE) |
---|
| 1051 | + rc = 0; |
---|
| 1052 | + if (rc) { |
---|
| 1053 | + cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n", |
---|
| 1054 | + __func__, rc); |
---|
| 1055 | + goto out; |
---|
| 1056 | + } |
---|
| 1057 | + } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
---|
| 1058 | + rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false, |
---|
| 1059 | + full_path, fid); |
---|
| 1060 | + if (rc == -EREMOTE) |
---|
| 1061 | + rc = 0; |
---|
901 | 1062 | if (rc) { |
---|
902 | 1063 | cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n", |
---|
903 | 1064 | __func__, rc); |
---|
904 | | - goto cgii_exit; |
---|
| 1065 | + goto out; |
---|
905 | 1066 | } |
---|
906 | 1067 | } |
---|
907 | | -#endif /* CONFIG_CIFS_ACL */ |
---|
908 | 1068 | |
---|
909 | 1069 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
---|
910 | 1070 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
---|
.. | .. |
---|
918 | 1078 | cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); |
---|
919 | 1079 | } |
---|
920 | 1080 | |
---|
| 1081 | + /* |
---|
| 1082 | + * 5. Update inode with final fattr data |
---|
| 1083 | + */ |
---|
| 1084 | + |
---|
921 | 1085 | if (!*inode) { |
---|
922 | 1086 | *inode = cifs_iget(sb, &fattr); |
---|
923 | 1087 | if (!*inode) |
---|
.. | .. |
---|
930 | 1094 | CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { |
---|
931 | 1095 | CIFS_I(*inode)->time = 0; /* force reval */ |
---|
932 | 1096 | rc = -ESTALE; |
---|
933 | | - goto cgii_exit; |
---|
| 1097 | + goto out; |
---|
934 | 1098 | } |
---|
935 | 1099 | |
---|
936 | 1100 | /* if filetype is different, return error */ |
---|
.. | .. |
---|
938 | 1102 | (fattr.cf_mode & S_IFMT))) { |
---|
939 | 1103 | CIFS_I(*inode)->time = 0; /* force reval */ |
---|
940 | 1104 | rc = -ESTALE; |
---|
941 | | - goto cgii_exit; |
---|
| 1105 | + goto out; |
---|
942 | 1106 | } |
---|
943 | 1107 | |
---|
944 | 1108 | cifs_fattr_to_inode(*inode, &fattr); |
---|
945 | 1109 | } |
---|
946 | | - |
---|
947 | | -cgii_exit: |
---|
948 | | - if ((*inode) && ((*inode)->i_ino == 0)) |
---|
949 | | - cifs_dbg(FYI, "inode number of zero returned\n"); |
---|
950 | | - |
---|
951 | | - kfree(buf); |
---|
| 1110 | +out: |
---|
| 1111 | + cifs_buf_release(smb1_backup_rsp_buf); |
---|
952 | 1112 | cifs_put_tlink(tlink); |
---|
| 1113 | + kfree(tmp_data); |
---|
953 | 1114 | return rc; |
---|
954 | 1115 | } |
---|
| 1116 | + |
---|
| 1117 | +int |
---|
| 1118 | +smb311_posix_get_inode_info(struct inode **inode, |
---|
| 1119 | + const char *full_path, |
---|
| 1120 | + struct super_block *sb, unsigned int xid) |
---|
| 1121 | +{ |
---|
| 1122 | + struct cifs_tcon *tcon; |
---|
| 1123 | + struct tcon_link *tlink; |
---|
| 1124 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
---|
| 1125 | + bool adjust_tz = false; |
---|
| 1126 | + struct cifs_fattr fattr = {0}; |
---|
| 1127 | + bool symlink = false; |
---|
| 1128 | + struct smb311_posix_qinfo *data = NULL; |
---|
| 1129 | + int rc = 0; |
---|
| 1130 | + int tmprc = 0; |
---|
| 1131 | + |
---|
| 1132 | + tlink = cifs_sb_tlink(cifs_sb); |
---|
| 1133 | + if (IS_ERR(tlink)) |
---|
| 1134 | + return PTR_ERR(tlink); |
---|
| 1135 | + tcon = tlink_tcon(tlink); |
---|
| 1136 | + |
---|
| 1137 | + /* |
---|
| 1138 | + * 1. Fetch file metadata |
---|
| 1139 | + */ |
---|
| 1140 | + |
---|
| 1141 | + if (is_inode_cache_good(*inode)) { |
---|
| 1142 | + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); |
---|
| 1143 | + goto out; |
---|
| 1144 | + } |
---|
| 1145 | + data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL); |
---|
| 1146 | + if (!data) { |
---|
| 1147 | + rc = -ENOMEM; |
---|
| 1148 | + goto out; |
---|
| 1149 | + } |
---|
| 1150 | + |
---|
| 1151 | + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, |
---|
| 1152 | + full_path, data, |
---|
| 1153 | + &adjust_tz, &symlink); |
---|
| 1154 | + |
---|
| 1155 | + /* |
---|
| 1156 | + * 2. Convert it to internal cifs metadata (fattr) |
---|
| 1157 | + */ |
---|
| 1158 | + |
---|
| 1159 | + switch (rc) { |
---|
| 1160 | + case 0: |
---|
| 1161 | + smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink); |
---|
| 1162 | + break; |
---|
| 1163 | + case -EREMOTE: |
---|
| 1164 | + /* DFS link, no metadata available on this server */ |
---|
| 1165 | + cifs_create_dfs_fattr(&fattr, sb); |
---|
| 1166 | + rc = 0; |
---|
| 1167 | + break; |
---|
| 1168 | + case -EACCES: |
---|
| 1169 | + /* |
---|
| 1170 | + * For SMB2 and later the backup intent flag |
---|
| 1171 | + * is already sent if needed on open and there |
---|
| 1172 | + * is no path based FindFirst operation to use |
---|
| 1173 | + * to retry with so nothing we can do, bail out |
---|
| 1174 | + */ |
---|
| 1175 | + goto out; |
---|
| 1176 | + default: |
---|
| 1177 | + cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); |
---|
| 1178 | + goto out; |
---|
| 1179 | + } |
---|
| 1180 | + |
---|
| 1181 | + |
---|
| 1182 | + /* |
---|
| 1183 | + * 3. Tweak fattr based on mount options |
---|
| 1184 | + */ |
---|
| 1185 | + |
---|
| 1186 | + /* check for Minshall+French symlinks */ |
---|
| 1187 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { |
---|
| 1188 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, |
---|
| 1189 | + full_path); |
---|
| 1190 | + if (tmprc) |
---|
| 1191 | + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); |
---|
| 1192 | + } |
---|
| 1193 | + |
---|
| 1194 | + /* |
---|
| 1195 | + * 4. Update inode with final fattr data |
---|
| 1196 | + */ |
---|
| 1197 | + |
---|
| 1198 | + if (!*inode) { |
---|
| 1199 | + *inode = cifs_iget(sb, &fattr); |
---|
| 1200 | + if (!*inode) |
---|
| 1201 | + rc = -ENOMEM; |
---|
| 1202 | + } else { |
---|
| 1203 | + /* we already have inode, update it */ |
---|
| 1204 | + |
---|
| 1205 | + /* if uniqueid is different, return error */ |
---|
| 1206 | + if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && |
---|
| 1207 | + CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { |
---|
| 1208 | + CIFS_I(*inode)->time = 0; /* force reval */ |
---|
| 1209 | + rc = -ESTALE; |
---|
| 1210 | + goto out; |
---|
| 1211 | + } |
---|
| 1212 | + |
---|
| 1213 | + /* if filetype is different, return error */ |
---|
| 1214 | + if (unlikely(((*inode)->i_mode & S_IFMT) != |
---|
| 1215 | + (fattr.cf_mode & S_IFMT))) { |
---|
| 1216 | + CIFS_I(*inode)->time = 0; /* force reval */ |
---|
| 1217 | + rc = -ESTALE; |
---|
| 1218 | + goto out; |
---|
| 1219 | + } |
---|
| 1220 | + |
---|
| 1221 | + cifs_fattr_to_inode(*inode, &fattr); |
---|
| 1222 | + } |
---|
| 1223 | +out: |
---|
| 1224 | + cifs_put_tlink(tlink); |
---|
| 1225 | + kfree(data); |
---|
| 1226 | + return rc; |
---|
| 1227 | +} |
---|
| 1228 | + |
---|
955 | 1229 | |
---|
956 | 1230 | static const struct inode_operations cifs_ipc_inode_ops = { |
---|
957 | 1231 | .lookup = cifs_lookup, |
---|
.. | .. |
---|
971 | 1245 | return 0; |
---|
972 | 1246 | |
---|
973 | 1247 | /* don't match inode of different type */ |
---|
974 | | - if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
---|
| 1248 | + if (inode_wrong_type(inode, fattr->cf_mode)) |
---|
975 | 1249 | return 0; |
---|
976 | 1250 | |
---|
977 | 1251 | /* if it's not a directory or has no dentries, then flag it */ |
---|
.. | .. |
---|
1086 | 1360 | /* some servers mistakenly claim POSIX support */ |
---|
1087 | 1361 | if (rc != -EOPNOTSUPP) |
---|
1088 | 1362 | goto iget_no_retry; |
---|
1089 | | - cifs_dbg(VFS, "server does not support POSIX extensions"); |
---|
| 1363 | + cifs_dbg(VFS, "server does not support POSIX extensions\n"); |
---|
1090 | 1364 | tcon->unix_ext = false; |
---|
1091 | 1365 | } |
---|
1092 | 1366 | |
---|
1093 | 1367 | convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); |
---|
1094 | | - rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); |
---|
| 1368 | + if (tcon->posix_extensions) |
---|
| 1369 | + rc = smb311_posix_get_inode_info(&inode, path, sb, xid); |
---|
| 1370 | + else |
---|
| 1371 | + rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); |
---|
1095 | 1372 | |
---|
1096 | 1373 | iget_no_retry: |
---|
1097 | 1374 | if (!inode) { |
---|
.. | .. |
---|
1214 | 1491 | oparms.tcon = tcon; |
---|
1215 | 1492 | oparms.cifs_sb = cifs_sb; |
---|
1216 | 1493 | oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES; |
---|
1217 | | - oparms.create_options = CREATE_NOT_DIR; |
---|
| 1494 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR); |
---|
1218 | 1495 | oparms.disposition = FILE_OPEN; |
---|
1219 | 1496 | oparms.path = full_path; |
---|
1220 | 1497 | oparms.fid = &fid; |
---|
.. | .. |
---|
1320 | 1597 | /* |
---|
1321 | 1598 | * If d_inode(dentry) is null (usually meaning the cached dentry |
---|
1322 | 1599 | * is a negative dentry) then we would attempt a standard SMB delete, but |
---|
1323 | | - * if that fails we can not attempt the fall back mechanisms on EACCESS |
---|
1324 | | - * but will return the EACCESS to the caller. Note that the VFS does not call |
---|
| 1600 | + * if that fails we can not attempt the fall back mechanisms on EACCES |
---|
| 1601 | + * but will return the EACCES to the caller. Note that the VFS does not call |
---|
1325 | 1602 | * unlink on negative dentries currently. |
---|
1326 | 1603 | */ |
---|
1327 | 1604 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
---|
.. | .. |
---|
1348 | 1625 | server = tcon->ses->server; |
---|
1349 | 1626 | |
---|
1350 | 1627 | xid = get_xid(); |
---|
| 1628 | + |
---|
| 1629 | + if (tcon->nodelete) { |
---|
| 1630 | + rc = -EACCES; |
---|
| 1631 | + goto unlink_out; |
---|
| 1632 | + } |
---|
1351 | 1633 | |
---|
1352 | 1634 | /* Unlink can be called from rename so we can not take the |
---|
1353 | 1635 | * sb->s_vfs_rename_mutex here */ |
---|
.. | .. |
---|
1442 | 1724 | int rc = 0; |
---|
1443 | 1725 | struct inode *inode = NULL; |
---|
1444 | 1726 | |
---|
1445 | | - if (tcon->unix_ext) |
---|
| 1727 | + if (tcon->posix_extensions) |
---|
| 1728 | + rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid); |
---|
| 1729 | + else if (tcon->unix_ext) |
---|
1446 | 1730 | rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, |
---|
1447 | 1731 | xid); |
---|
1448 | 1732 | else |
---|
.. | .. |
---|
1619 | 1903 | } |
---|
1620 | 1904 | |
---|
1621 | 1905 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ |
---|
1622 | | - rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb); |
---|
| 1906 | + rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb); |
---|
1623 | 1907 | if (rc) { |
---|
1624 | 1908 | cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc); |
---|
1625 | 1909 | d_drop(direntry); |
---|
1626 | 1910 | goto mkdir_out; |
---|
1627 | 1911 | } |
---|
1628 | 1912 | |
---|
| 1913 | + /* TODO: skip this for smb2/smb3 */ |
---|
1629 | 1914 | rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, |
---|
1630 | 1915 | xid); |
---|
1631 | 1916 | mkdir_out: |
---|
.. | .. |
---|
1672 | 1957 | |
---|
1673 | 1958 | if (!server->ops->rmdir) { |
---|
1674 | 1959 | rc = -ENOSYS; |
---|
| 1960 | + cifs_put_tlink(tlink); |
---|
| 1961 | + goto rmdir_exit; |
---|
| 1962 | + } |
---|
| 1963 | + |
---|
| 1964 | + if (tcon->nodelete) { |
---|
| 1965 | + rc = -EACCES; |
---|
1675 | 1966 | cifs_put_tlink(tlink); |
---|
1676 | 1967 | goto rmdir_exit; |
---|
1677 | 1968 | } |
---|
.. | .. |
---|
1751 | 2042 | oparms.cifs_sb = cifs_sb; |
---|
1752 | 2043 | /* open the file to be renamed -- we need DELETE perms */ |
---|
1753 | 2044 | oparms.desired_access = DELETE; |
---|
1754 | | - oparms.create_options = CREATE_NOT_DIR; |
---|
| 2045 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR); |
---|
1755 | 2046 | oparms.disposition = FILE_OPEN; |
---|
1756 | 2047 | oparms.path = from_path; |
---|
1757 | 2048 | oparms.fid = &fid; |
---|
.. | .. |
---|
1765 | 2056 | CIFSSMBClose(xid, tcon, fid.netfid); |
---|
1766 | 2057 | } |
---|
1767 | 2058 | do_rename_exit: |
---|
| 2059 | + if (rc == 0) |
---|
| 2060 | + d_move(from_dentry, to_dentry); |
---|
1768 | 2061 | cifs_put_tlink(tlink); |
---|
1769 | 2062 | return rc; |
---|
1770 | 2063 | } |
---|
.. | .. |
---|
1927 | 2220 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { |
---|
1928 | 2221 | rc = invalidate_inode_pages2(inode->i_mapping); |
---|
1929 | 2222 | if (rc) |
---|
1930 | | - cifs_dbg(VFS, "%s: could not invalidate inode %p\n", |
---|
| 2223 | + cifs_dbg(VFS, "%s: Could not invalidate inode %p\n", |
---|
1931 | 2224 | __func__, inode); |
---|
1932 | 2225 | } |
---|
1933 | 2226 | |
---|
.. | .. |
---|
1953 | 2246 | { |
---|
1954 | 2247 | int rc; |
---|
1955 | 2248 | unsigned long *flags = &CIFS_I(inode)->flags; |
---|
| 2249 | + |
---|
| 2250 | + /* swapfiles are not supposed to be shared */ |
---|
| 2251 | + if (IS_SWAPFILE(inode)) |
---|
| 2252 | + return 0; |
---|
1956 | 2253 | |
---|
1957 | 2254 | rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable, |
---|
1958 | 2255 | TASK_KILLABLE); |
---|
.. | .. |
---|
2026 | 2323 | dentry, cifs_get_time(dentry), jiffies); |
---|
2027 | 2324 | |
---|
2028 | 2325 | again: |
---|
2029 | | - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
---|
| 2326 | + if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) |
---|
| 2327 | + rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); |
---|
| 2328 | + else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
---|
2030 | 2329 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
---|
2031 | 2330 | else |
---|
2032 | 2331 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
---|
.. | .. |
---|
2078 | 2377 | * We need to be sure that all dirty pages are written and the server |
---|
2079 | 2378 | * has actual ctime, mtime and file length. |
---|
2080 | 2379 | */ |
---|
2081 | | - if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && |
---|
2082 | | - inode->i_mapping->nrpages != 0) { |
---|
| 2380 | + if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) && |
---|
| 2381 | + !CIFS_CACHE_READ(CIFS_I(inode)) && |
---|
| 2382 | + inode->i_mapping && inode->i_mapping->nrpages != 0) { |
---|
2083 | 2383 | rc = filemap_fdatawait(inode->i_mapping); |
---|
2084 | 2384 | if (rc) { |
---|
2085 | 2385 | mapping_set_error(inode->i_mapping, rc); |
---|
.. | .. |
---|
2087 | 2387 | } |
---|
2088 | 2388 | } |
---|
2089 | 2389 | |
---|
2090 | | - rc = cifs_revalidate_dentry_attr(dentry); |
---|
2091 | | - if (rc) |
---|
2092 | | - return rc; |
---|
| 2390 | + if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC) |
---|
| 2391 | + CIFS_I(inode)->time = 0; /* force revalidate */ |
---|
| 2392 | + |
---|
| 2393 | + /* |
---|
| 2394 | + * If the caller doesn't require syncing, only sync if |
---|
| 2395 | + * necessary (e.g. due to earlier truncate or setattr |
---|
| 2396 | + * invalidating the cached metadata) |
---|
| 2397 | + */ |
---|
| 2398 | + if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) || |
---|
| 2399 | + (CIFS_I(inode)->time == 0)) { |
---|
| 2400 | + rc = cifs_revalidate_dentry_attr(dentry); |
---|
| 2401 | + if (rc) |
---|
| 2402 | + return rc; |
---|
| 2403 | + } |
---|
2093 | 2404 | |
---|
2094 | 2405 | generic_fillattr(inode, stat); |
---|
2095 | | - stat->blksize = CIFS_MAX_MSGSIZE; |
---|
| 2406 | + stat->blksize = cifs_sb->bsize; |
---|
2096 | 2407 | stat->ino = CIFS_I(inode)->uniqueid; |
---|
2097 | 2408 | |
---|
2098 | 2409 | /* old CIFS Unix Extensions doesn't return create time */ |
---|
.. | .. |
---|
2121 | 2432 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) |
---|
2122 | 2433 | stat->gid = current_fsgid(); |
---|
2123 | 2434 | } |
---|
2124 | | - return rc; |
---|
| 2435 | + return 0; |
---|
2125 | 2436 | } |
---|
2126 | 2437 | |
---|
2127 | | -static int cifs_truncate_page(struct address_space *mapping, loff_t from) |
---|
| 2438 | +int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, |
---|
| 2439 | + u64 len) |
---|
| 2440 | +{ |
---|
| 2441 | + struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
---|
| 2442 | + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->vfs_inode.i_sb); |
---|
| 2443 | + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
---|
| 2444 | + struct TCP_Server_Info *server = tcon->ses->server; |
---|
| 2445 | + struct cifsFileInfo *cfile; |
---|
| 2446 | + int rc; |
---|
| 2447 | + |
---|
| 2448 | + /* |
---|
| 2449 | + * We need to be sure that all dirty pages are written as they |
---|
| 2450 | + * might fill holes on the server. |
---|
| 2451 | + */ |
---|
| 2452 | + if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && |
---|
| 2453 | + inode->i_mapping->nrpages != 0) { |
---|
| 2454 | + rc = filemap_fdatawait(inode->i_mapping); |
---|
| 2455 | + if (rc) { |
---|
| 2456 | + mapping_set_error(inode->i_mapping, rc); |
---|
| 2457 | + return rc; |
---|
| 2458 | + } |
---|
| 2459 | + } |
---|
| 2460 | + |
---|
| 2461 | + cfile = find_readable_file(cifs_i, false); |
---|
| 2462 | + if (cfile == NULL) |
---|
| 2463 | + return -EINVAL; |
---|
| 2464 | + |
---|
| 2465 | + if (server->ops->fiemap) { |
---|
| 2466 | + rc = server->ops->fiemap(tcon, cfile, fei, start, len); |
---|
| 2467 | + cifsFileInfo_put(cfile); |
---|
| 2468 | + return rc; |
---|
| 2469 | + } |
---|
| 2470 | + |
---|
| 2471 | + cifsFileInfo_put(cfile); |
---|
| 2472 | + return -ENOTSUPP; |
---|
| 2473 | +} |
---|
| 2474 | + |
---|
| 2475 | +int cifs_truncate_page(struct address_space *mapping, loff_t from) |
---|
2128 | 2476 | { |
---|
2129 | 2477 | pgoff_t index = from >> PAGE_SHIFT; |
---|
2130 | 2478 | unsigned offset = from & (PAGE_SIZE - 1); |
---|
.. | .. |
---|
2141 | 2489 | return rc; |
---|
2142 | 2490 | } |
---|
2143 | 2491 | |
---|
2144 | | -static void cifs_setsize(struct inode *inode, loff_t offset) |
---|
| 2492 | +void cifs_setsize(struct inode *inode, loff_t offset) |
---|
2145 | 2493 | { |
---|
2146 | 2494 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
---|
2147 | 2495 | |
---|
.. | .. |
---|
2175 | 2523 | * writebehind data than the SMB timeout for the SetPathInfo |
---|
2176 | 2524 | * request would allow |
---|
2177 | 2525 | */ |
---|
2178 | | - open_file = find_writable_file(cifsInode, true); |
---|
| 2526 | + open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); |
---|
2179 | 2527 | if (open_file) { |
---|
2180 | 2528 | tcon = tlink_tcon(open_file->tlink); |
---|
2181 | 2529 | server = tcon->ses->server; |
---|
.. | .. |
---|
2219 | 2567 | if (rc == 0) { |
---|
2220 | 2568 | cifsInode->server_eof = attrs->ia_size; |
---|
2221 | 2569 | cifs_setsize(inode, attrs->ia_size); |
---|
| 2570 | + /* |
---|
| 2571 | + * i_blocks is not related to (i_size / i_blksize), but instead |
---|
| 2572 | + * 512 byte (2**9) size is required for calculating num blocks. |
---|
| 2573 | + * Until we can query the server for actual allocation size, |
---|
| 2574 | + * this is best estimate we have for blocks allocated for a file |
---|
| 2575 | + * Number of blocks must be rounded up so size 1 is not 0 blocks |
---|
| 2576 | + */ |
---|
| 2577 | + inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9; |
---|
2222 | 2578 | |
---|
2223 | 2579 | /* |
---|
2224 | 2580 | * The man page of truncate says if the size changed, |
---|
.. | .. |
---|
2334 | 2690 | args->ctime = NO_CHANGE_64; |
---|
2335 | 2691 | |
---|
2336 | 2692 | args->device = 0; |
---|
2337 | | - open_file = find_writable_file(cifsInode, true); |
---|
| 2693 | + open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); |
---|
2338 | 2694 | if (open_file) { |
---|
2339 | 2695 | u16 nfid = open_file->fid.netfid; |
---|
2340 | 2696 | u32 npid = open_file->pid; |
---|
.. | .. |
---|
2388 | 2744 | struct inode *inode = d_inode(direntry); |
---|
2389 | 2745 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
---|
2390 | 2746 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
---|
| 2747 | + struct cifsFileInfo *wfile; |
---|
| 2748 | + struct cifs_tcon *tcon; |
---|
2391 | 2749 | char *full_path = NULL; |
---|
2392 | 2750 | int rc = -EACCES; |
---|
2393 | 2751 | __u32 dosattr = 0; |
---|
.. | .. |
---|
2395 | 2753 | |
---|
2396 | 2754 | xid = get_xid(); |
---|
2397 | 2755 | |
---|
2398 | | - cifs_dbg(FYI, "setattr on file %pd attrs->iavalid 0x%x\n", |
---|
| 2756 | + cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n", |
---|
2399 | 2757 | direntry, attrs->ia_valid); |
---|
2400 | 2758 | |
---|
2401 | 2759 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
---|
.. | .. |
---|
2416 | 2774 | |
---|
2417 | 2775 | /* |
---|
2418 | 2776 | * Attempt to flush data before changing attributes. We need to do |
---|
2419 | | - * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the |
---|
2420 | | - * ownership or mode then we may also need to do this. Here, we take |
---|
2421 | | - * the safe way out and just do the flush on all setattr requests. If |
---|
2422 | | - * the flush returns error, store it to report later and continue. |
---|
| 2777 | + * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data |
---|
| 2778 | + * returns error, store it to report later and continue. |
---|
2423 | 2779 | * |
---|
2424 | 2780 | * BB: This should be smarter. Why bother flushing pages that |
---|
2425 | 2781 | * will be truncated anyway? Also, should we error out here if |
---|
2426 | | - * the flush returns error? |
---|
| 2782 | + * the flush returns error? Do we need to check for ATTR_MTIME_SET flag? |
---|
2427 | 2783 | */ |
---|
2428 | | - rc = filemap_write_and_wait(inode->i_mapping); |
---|
2429 | | - if (is_interrupt_error(rc)) { |
---|
2430 | | - rc = -ERESTARTSYS; |
---|
2431 | | - goto cifs_setattr_exit; |
---|
| 2784 | + if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) { |
---|
| 2785 | + rc = filemap_write_and_wait(inode->i_mapping); |
---|
| 2786 | + if (is_interrupt_error(rc)) { |
---|
| 2787 | + rc = -ERESTARTSYS; |
---|
| 2788 | + goto cifs_setattr_exit; |
---|
| 2789 | + } |
---|
| 2790 | + mapping_set_error(inode->i_mapping, rc); |
---|
2432 | 2791 | } |
---|
2433 | 2792 | |
---|
2434 | | - mapping_set_error(inode->i_mapping, rc); |
---|
2435 | 2793 | rc = 0; |
---|
| 2794 | + |
---|
| 2795 | + if ((attrs->ia_valid & ATTR_MTIME) && |
---|
| 2796 | + !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { |
---|
| 2797 | + rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile); |
---|
| 2798 | + if (!rc) { |
---|
| 2799 | + tcon = tlink_tcon(wfile->tlink); |
---|
| 2800 | + rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid); |
---|
| 2801 | + cifsFileInfo_put(wfile); |
---|
| 2802 | + if (rc) |
---|
| 2803 | + goto cifs_setattr_exit; |
---|
| 2804 | + } else if (rc != -EBADF) |
---|
| 2805 | + goto cifs_setattr_exit; |
---|
| 2806 | + else |
---|
| 2807 | + rc = 0; |
---|
| 2808 | + } |
---|
2436 | 2809 | |
---|
2437 | 2810 | if (attrs->ia_valid & ATTR_SIZE) { |
---|
2438 | 2811 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
---|
.. | .. |
---|
2446 | 2819 | if (attrs->ia_valid & ATTR_GID) |
---|
2447 | 2820 | gid = attrs->ia_gid; |
---|
2448 | 2821 | |
---|
2449 | | -#ifdef CONFIG_CIFS_ACL |
---|
2450 | | - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
---|
| 2822 | + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || |
---|
| 2823 | + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { |
---|
2451 | 2824 | if (uid_valid(uid) || gid_valid(gid)) { |
---|
2452 | 2825 | rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64, |
---|
2453 | 2826 | uid, gid); |
---|
.. | .. |
---|
2458 | 2831 | } |
---|
2459 | 2832 | } |
---|
2460 | 2833 | } else |
---|
2461 | | -#endif /* CONFIG_CIFS_ACL */ |
---|
2462 | 2834 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) |
---|
2463 | 2835 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); |
---|
2464 | 2836 | |
---|
.. | .. |
---|
2469 | 2841 | if (attrs->ia_valid & ATTR_MODE) { |
---|
2470 | 2842 | mode = attrs->ia_mode; |
---|
2471 | 2843 | rc = 0; |
---|
2472 | | -#ifdef CONFIG_CIFS_ACL |
---|
2473 | | - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
---|
| 2844 | + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || |
---|
| 2845 | + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { |
---|
2474 | 2846 | rc = id_mode_to_cifs_acl(inode, full_path, mode, |
---|
2475 | 2847 | INVALID_UID, INVALID_GID); |
---|
2476 | 2848 | if (rc) { |
---|
.. | .. |
---|
2479 | 2851 | goto cifs_setattr_exit; |
---|
2480 | 2852 | } |
---|
2481 | 2853 | } else |
---|
2482 | | -#endif /* CONFIG_CIFS_ACL */ |
---|
2483 | 2854 | if (((mode & S_IWUGO) == 0) && |
---|
2484 | 2855 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
---|
2485 | 2856 | |
---|