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