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