138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1 238c8a9a5SSteve French /* 338c8a9a5SSteve French * 438c8a9a5SSteve French * Copyright (C) International Business Machines Corp., 2002,2010 538c8a9a5SSteve French * Author(s): Steve French (sfrench@us.ibm.com) 638c8a9a5SSteve French * 738c8a9a5SSteve French */ 838c8a9a5SSteve French #include <linux/fs.h> 938c8a9a5SSteve French #include <linux/stat.h> 1038c8a9a5SSteve French #include <linux/slab.h> 1138c8a9a5SSteve French #include <linux/pagemap.h> 1238c8a9a5SSteve French #include <linux/freezer.h> 1338c8a9a5SSteve French #include <linux/sched/signal.h> 1438c8a9a5SSteve French #include <linux/wait_bit.h> 1538c8a9a5SSteve French #include <linux/fiemap.h> 1638c8a9a5SSteve French #include <asm/div64.h> 1738c8a9a5SSteve French #include "cifsfs.h" 1838c8a9a5SSteve French #include "cifspdu.h" 1938c8a9a5SSteve French #include "cifsglob.h" 2038c8a9a5SSteve French #include "cifsproto.h" 2138c8a9a5SSteve French #include "smb2proto.h" 2238c8a9a5SSteve French #include "cifs_debug.h" 2338c8a9a5SSteve French #include "cifs_fs_sb.h" 2438c8a9a5SSteve French #include "cifs_unicode.h" 2538c8a9a5SSteve French #include "fscache.h" 2638c8a9a5SSteve French #include "fs_context.h" 2738c8a9a5SSteve French #include "cifs_ioctl.h" 2838c8a9a5SSteve French #include "cached_dir.h" 29db0f1c07SPaulo Alcantara #include "reparse.h" 3038c8a9a5SSteve French 3138c8a9a5SSteve French static void cifs_set_ops(struct inode *inode) 3238c8a9a5SSteve French { 3338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 3438c8a9a5SSteve French 3538c8a9a5SSteve French switch (inode->i_mode & S_IFMT) { 3638c8a9a5SSteve French case S_IFREG: 3738c8a9a5SSteve French inode->i_op = &cifs_file_inode_ops; 3838c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { 3938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 4038c8a9a5SSteve French inode->i_fop = &cifs_file_direct_nobrl_ops; 4138c8a9a5SSteve French else 4238c8a9a5SSteve French inode->i_fop = &cifs_file_direct_ops; 4338c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { 4438c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 4538c8a9a5SSteve French inode->i_fop = &cifs_file_strict_nobrl_ops; 4638c8a9a5SSteve French else 4738c8a9a5SSteve French inode->i_fop = &cifs_file_strict_ops; 4838c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 4938c8a9a5SSteve French inode->i_fop = &cifs_file_nobrl_ops; 5038c8a9a5SSteve French else { /* not direct, send byte range locks */ 5138c8a9a5SSteve French inode->i_fop = &cifs_file_ops; 5238c8a9a5SSteve French } 5338c8a9a5SSteve French 5438c8a9a5SSteve French /* check if server can support readahead */ 5538c8a9a5SSteve French if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read < 5638c8a9a5SSteve French PAGE_SIZE + MAX_CIFS_HDR_SIZE) 5738c8a9a5SSteve French inode->i_data.a_ops = &cifs_addr_ops_smallbuf; 5838c8a9a5SSteve French else 5938c8a9a5SSteve French inode->i_data.a_ops = &cifs_addr_ops; 6038c8a9a5SSteve French break; 6138c8a9a5SSteve French case S_IFDIR: 6238c8a9a5SSteve French if (IS_AUTOMOUNT(inode)) { 630a049935SPaulo Alcantara inode->i_op = &cifs_namespace_inode_operations; 6438c8a9a5SSteve French } else { 6538c8a9a5SSteve French inode->i_op = &cifs_dir_inode_ops; 6638c8a9a5SSteve French inode->i_fop = &cifs_dir_ops; 6738c8a9a5SSteve French } 6838c8a9a5SSteve French break; 6938c8a9a5SSteve French case S_IFLNK: 7038c8a9a5SSteve French inode->i_op = &cifs_symlink_inode_ops; 7138c8a9a5SSteve French break; 7238c8a9a5SSteve French default: 7338c8a9a5SSteve French init_special_inode(inode, inode->i_mode, inode->i_rdev); 7438c8a9a5SSteve French break; 7538c8a9a5SSteve French } 7638c8a9a5SSteve French } 7738c8a9a5SSteve French 7838c8a9a5SSteve French /* check inode attributes against fattr. If they don't match, tag the 7938c8a9a5SSteve French * inode for cache invalidation 8038c8a9a5SSteve French */ 8138c8a9a5SSteve French static void 8238c8a9a5SSteve French cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) 8338c8a9a5SSteve French { 8438c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 8538c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 8623171df5SJeff Layton struct timespec64 mtime; 8738c8a9a5SSteve French 8838c8a9a5SSteve French cifs_dbg(FYI, "%s: revalidating inode %llu\n", 8938c8a9a5SSteve French __func__, cifs_i->uniqueid); 9038c8a9a5SSteve French 9138c8a9a5SSteve French if (inode->i_state & I_NEW) { 9238c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is new\n", 9338c8a9a5SSteve French __func__, cifs_i->uniqueid); 9438c8a9a5SSteve French return; 9538c8a9a5SSteve French } 9638c8a9a5SSteve French 9738c8a9a5SSteve French /* don't bother with revalidation if we have an oplock */ 9838c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) { 9938c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is oplocked\n", 10038c8a9a5SSteve French __func__, cifs_i->uniqueid); 10138c8a9a5SSteve French return; 10238c8a9a5SSteve French } 10338c8a9a5SSteve French 10438c8a9a5SSteve French /* revalidate if mtime or size have changed */ 10538c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 10623171df5SJeff Layton mtime = inode_get_mtime(inode); 10723171df5SJeff Layton if (timespec64_equal(&mtime, &fattr->cf_mtime) && 10838c8a9a5SSteve French cifs_i->server_eof == fattr->cf_eof) { 10938c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is unchanged\n", 11038c8a9a5SSteve French __func__, cifs_i->uniqueid); 11138c8a9a5SSteve French return; 11238c8a9a5SSteve French } 11338c8a9a5SSteve French 11438c8a9a5SSteve French cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n", 11538c8a9a5SSteve French __func__, cifs_i->uniqueid); 11638c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags); 11738c8a9a5SSteve French /* Invalidate fscache cookie */ 11838c8a9a5SSteve French cifs_fscache_fill_coherency(&cifs_i->netfs.inode, &cd); 11938c8a9a5SSteve French fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0); 12038c8a9a5SSteve French } 12138c8a9a5SSteve French 12238c8a9a5SSteve French /* 12338c8a9a5SSteve French * copy nlink to the inode, unless it wasn't provided. Provide 12438c8a9a5SSteve French * sane values if we don't have an existing one and none was provided 12538c8a9a5SSteve French */ 12638c8a9a5SSteve French static void 12738c8a9a5SSteve French cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) 12838c8a9a5SSteve French { 12938c8a9a5SSteve French /* 13038c8a9a5SSteve French * if we're in a situation where we can't trust what we 13138c8a9a5SSteve French * got from the server (readdir, some non-unix cases) 13238c8a9a5SSteve French * fake reasonable values 13338c8a9a5SSteve French */ 13438c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) { 13538c8a9a5SSteve French /* only provide fake values on a new inode */ 13638c8a9a5SSteve French if (inode->i_state & I_NEW) { 13738c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_DIRECTORY) 13838c8a9a5SSteve French set_nlink(inode, 2); 13938c8a9a5SSteve French else 14038c8a9a5SSteve French set_nlink(inode, 1); 14138c8a9a5SSteve French } 14238c8a9a5SSteve French return; 14338c8a9a5SSteve French } 14438c8a9a5SSteve French 14538c8a9a5SSteve French /* we trust the server, so update it */ 14638c8a9a5SSteve French set_nlink(inode, fattr->cf_nlink); 14738c8a9a5SSteve French } 14838c8a9a5SSteve French 14938c8a9a5SSteve French /* populate an inode with info from a cifs_fattr struct */ 15038c8a9a5SSteve French int 1519179aa27SBharath SM cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, 1529179aa27SBharath SM bool from_readdir) 15338c8a9a5SSteve French { 15438c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 15538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 15638c8a9a5SSteve French 15738c8a9a5SSteve French if (!(inode->i_state & I_NEW) && 15838c8a9a5SSteve French unlikely(inode_wrong_type(inode, fattr->cf_mode))) { 15938c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force reval */ 16038c8a9a5SSteve French return -ESTALE; 16138c8a9a5SSteve French } 16238c8a9a5SSteve French 16338c8a9a5SSteve French cifs_revalidate_cache(inode, fattr); 16438c8a9a5SSteve French 16538c8a9a5SSteve French spin_lock(&inode->i_lock); 16638c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 16738c8a9a5SSteve French fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode); 16838c8a9a5SSteve French fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode); 16938c8a9a5SSteve French /* we do not want atime to be less than mtime, it broke some apps */ 17038c8a9a5SSteve French if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0) 17123171df5SJeff Layton inode_set_atime_to_ts(inode, fattr->cf_mtime); 17238c8a9a5SSteve French else 17323171df5SJeff Layton inode_set_atime_to_ts(inode, fattr->cf_atime); 17423171df5SJeff Layton inode_set_mtime_to_ts(inode, fattr->cf_mtime); 17594487653SJeff Layton inode_set_ctime_to_ts(inode, fattr->cf_ctime); 17638c8a9a5SSteve French inode->i_rdev = fattr->cf_rdev; 17738c8a9a5SSteve French cifs_nlink_fattr_to_inode(inode, fattr); 17838c8a9a5SSteve French inode->i_uid = fattr->cf_uid; 17938c8a9a5SSteve French inode->i_gid = fattr->cf_gid; 18038c8a9a5SSteve French 18138c8a9a5SSteve French /* if dynperm is set, don't clobber existing mode */ 18238c8a9a5SSteve French if (inode->i_state & I_NEW || 18338c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) 18438c8a9a5SSteve French inode->i_mode = fattr->cf_mode; 18538c8a9a5SSteve French 18638c8a9a5SSteve French cifs_i->cifsAttrs = fattr->cf_cifsattrs; 187b9e741acSPaulo Alcantara cifs_i->reparse_tag = fattr->cf_cifstag; 18838c8a9a5SSteve French 18938c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) 19038c8a9a5SSteve French cifs_i->time = 0; 19138c8a9a5SSteve French else 19238c8a9a5SSteve French cifs_i->time = jiffies; 19338c8a9a5SSteve French 19438c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING) 19538c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19638c8a9a5SSteve French else 19738c8a9a5SSteve French clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19838c8a9a5SSteve French 19938c8a9a5SSteve French cifs_i->server_eof = fattr->cf_eof; 20038c8a9a5SSteve French /* 20138c8a9a5SSteve French * Can't safely change the file size here if the client is writing to 20238c8a9a5SSteve French * it due to potential races. 20338c8a9a5SSteve French */ 2049179aa27SBharath SM if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) { 20538c8a9a5SSteve French i_size_write(inode, fattr->cf_eof); 20638c8a9a5SSteve French 20738c8a9a5SSteve French /* 20838c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), 20938c8a9a5SSteve French * but instead 512 byte (2**9) size is required for 21038c8a9a5SSteve French * calculating num blocks. 21138c8a9a5SSteve French */ 21238c8a9a5SSteve French inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; 21338c8a9a5SSteve French } 21438c8a9a5SSteve French 215b9e741acSPaulo Alcantara if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) { 21638c8a9a5SSteve French kfree(cifs_i->symlink_target); 21738c8a9a5SSteve French cifs_i->symlink_target = fattr->cf_symlink_target; 21838c8a9a5SSteve French fattr->cf_symlink_target = NULL; 21938c8a9a5SSteve French } 22038c8a9a5SSteve French spin_unlock(&inode->i_lock); 22138c8a9a5SSteve French 222a18280e7SPaulo Alcantara if (fattr->cf_flags & CIFS_FATTR_JUNCTION) 22338c8a9a5SSteve French inode->i_flags |= S_AUTOMOUNT; 22438c8a9a5SSteve French if (inode->i_state & I_NEW) 22538c8a9a5SSteve French cifs_set_ops(inode); 22638c8a9a5SSteve French return 0; 22738c8a9a5SSteve French } 22838c8a9a5SSteve French 22938c8a9a5SSteve French void 23038c8a9a5SSteve French cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr) 23138c8a9a5SSteve French { 23238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 23338c8a9a5SSteve French 23438c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 23538c8a9a5SSteve French return; 23638c8a9a5SSteve French 23738c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 23838c8a9a5SSteve French } 23938c8a9a5SSteve French 24038c8a9a5SSteve French /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ 24138c8a9a5SSteve French void 24238c8a9a5SSteve French cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, 24338c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 24438c8a9a5SSteve French { 24538c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 24638c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); 24738c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); 24838c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 24938c8a9a5SSteve French 25038c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 25138c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); 25238c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); 25338c8a9a5SSteve French /* old POSIX extensions don't get create time */ 25438c8a9a5SSteve French 25538c8a9a5SSteve French fattr->cf_mode = le64_to_cpu(info->Permissions); 25638c8a9a5SSteve French 25738c8a9a5SSteve French /* 25838c8a9a5SSteve French * Since we set the inode type below we need to mask off 25938c8a9a5SSteve French * to avoid strange results if bits set above. 26038c8a9a5SSteve French */ 26138c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 26238c8a9a5SSteve French switch (le32_to_cpu(info->Type)) { 26338c8a9a5SSteve French case UNIX_FILE: 26438c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 26538c8a9a5SSteve French fattr->cf_dtype = DT_REG; 26638c8a9a5SSteve French break; 26738c8a9a5SSteve French case UNIX_SYMLINK: 26838c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 26938c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 27038c8a9a5SSteve French break; 27138c8a9a5SSteve French case UNIX_DIR: 27238c8a9a5SSteve French fattr->cf_mode |= S_IFDIR; 27338c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 27438c8a9a5SSteve French break; 27538c8a9a5SSteve French case UNIX_CHARDEV: 27638c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 27738c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 27838c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 27938c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 28038c8a9a5SSteve French break; 28138c8a9a5SSteve French case UNIX_BLOCKDEV: 28238c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 28338c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 28438c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 28538c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 28638c8a9a5SSteve French break; 28738c8a9a5SSteve French case UNIX_FIFO: 28838c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 28938c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 29038c8a9a5SSteve French break; 29138c8a9a5SSteve French case UNIX_SOCKET: 29238c8a9a5SSteve French fattr->cf_mode |= S_IFSOCK; 29338c8a9a5SSteve French fattr->cf_dtype = DT_SOCK; 29438c8a9a5SSteve French break; 29538c8a9a5SSteve French default: 29638c8a9a5SSteve French /* safest to call it a file if we do not know */ 29738c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 29838c8a9a5SSteve French fattr->cf_dtype = DT_REG; 29938c8a9a5SSteve French cifs_dbg(FYI, "unknown type %d\n", le32_to_cpu(info->Type)); 30038c8a9a5SSteve French break; 30138c8a9a5SSteve French } 30238c8a9a5SSteve French 30338c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 30438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { 30538c8a9a5SSteve French u64 id = le64_to_cpu(info->Uid); 30638c8a9a5SSteve French if (id < ((uid_t)-1)) { 30738c8a9a5SSteve French kuid_t uid = make_kuid(&init_user_ns, id); 30838c8a9a5SSteve French if (uid_valid(uid)) 30938c8a9a5SSteve French fattr->cf_uid = uid; 31038c8a9a5SSteve French } 31138c8a9a5SSteve French } 31238c8a9a5SSteve French 31338c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 31438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { 31538c8a9a5SSteve French u64 id = le64_to_cpu(info->Gid); 31638c8a9a5SSteve French if (id < ((gid_t)-1)) { 31738c8a9a5SSteve French kgid_t gid = make_kgid(&init_user_ns, id); 31838c8a9a5SSteve French if (gid_valid(gid)) 31938c8a9a5SSteve French fattr->cf_gid = gid; 32038c8a9a5SSteve French } 32138c8a9a5SSteve French } 32238c8a9a5SSteve French 32338c8a9a5SSteve French fattr->cf_nlink = le64_to_cpu(info->Nlinks); 32438c8a9a5SSteve French } 32538c8a9a5SSteve French 32638c8a9a5SSteve French /* 32738c8a9a5SSteve French * Fill a cifs_fattr struct with fake inode info. 32838c8a9a5SSteve French * 32938c8a9a5SSteve French * Needed to setup cifs_fattr data for the directory which is the 33038c8a9a5SSteve French * junction to the new submount (ie to setup the fake directory 331a18280e7SPaulo Alcantara * which represents a DFS referral or reparse mount point). 33238c8a9a5SSteve French */ 333a18280e7SPaulo Alcantara static void cifs_create_junction_fattr(struct cifs_fattr *fattr, 334a18280e7SPaulo Alcantara struct super_block *sb) 33538c8a9a5SSteve French { 33638c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 33738c8a9a5SSteve French 338a18280e7SPaulo Alcantara cifs_dbg(FYI, "%s: creating fake fattr\n", __func__); 33938c8a9a5SSteve French 34038c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 34138c8a9a5SSteve French fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; 34238c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 34338c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 34438c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_mtime); 34538c8a9a5SSteve French fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; 34638c8a9a5SSteve French fattr->cf_nlink = 2; 347a18280e7SPaulo Alcantara fattr->cf_flags = CIFS_FATTR_JUNCTION; 348a18280e7SPaulo Alcantara } 349a18280e7SPaulo Alcantara 350a18280e7SPaulo Alcantara /* Update inode with final fattr data */ 351a18280e7SPaulo Alcantara static int update_inode_info(struct super_block *sb, 352a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 353a18280e7SPaulo Alcantara struct inode **inode) 354a18280e7SPaulo Alcantara { 355a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 356a18280e7SPaulo Alcantara int rc = 0; 357a18280e7SPaulo Alcantara 358a18280e7SPaulo Alcantara if (!*inode) { 359a18280e7SPaulo Alcantara *inode = cifs_iget(sb, fattr); 360a18280e7SPaulo Alcantara if (!*inode) 361a18280e7SPaulo Alcantara rc = -ENOMEM; 362a18280e7SPaulo Alcantara return rc; 363a18280e7SPaulo Alcantara } 364a18280e7SPaulo Alcantara /* We already have inode, update it. 365a18280e7SPaulo Alcantara * 366a18280e7SPaulo Alcantara * If file type or uniqueid is different, return error. 367a18280e7SPaulo Alcantara */ 368a18280e7SPaulo Alcantara if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 369a18280e7SPaulo Alcantara CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) { 370a18280e7SPaulo Alcantara CIFS_I(*inode)->time = 0; /* force reval */ 371a18280e7SPaulo Alcantara return -ESTALE; 372a18280e7SPaulo Alcantara } 3739179aa27SBharath SM return cifs_fattr_to_inode(*inode, fattr, false); 37438c8a9a5SSteve French } 37538c8a9a5SSteve French 37638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 37738c8a9a5SSteve French static int 37838c8a9a5SSteve French cifs_get_file_info_unix(struct file *filp) 37938c8a9a5SSteve French { 38038c8a9a5SSteve French int rc; 38138c8a9a5SSteve French unsigned int xid; 38238c8a9a5SSteve French FILE_UNIX_BASIC_INFO find_data; 38338c8a9a5SSteve French struct cifs_fattr fattr = {}; 38438c8a9a5SSteve French struct inode *inode = file_inode(filp); 38538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 38638c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 38738c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 38838c8a9a5SSteve French 38938c8a9a5SSteve French xid = get_xid(); 39038c8a9a5SSteve French 39138c8a9a5SSteve French if (cfile->symlink_target) { 39238c8a9a5SSteve French fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 39338c8a9a5SSteve French if (!fattr.cf_symlink_target) { 39438c8a9a5SSteve French rc = -ENOMEM; 39538c8a9a5SSteve French goto cifs_gfiunix_out; 39638c8a9a5SSteve French } 39738c8a9a5SSteve French } 39838c8a9a5SSteve French 39938c8a9a5SSteve French rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data); 40038c8a9a5SSteve French if (!rc) { 40138c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); 40238c8a9a5SSteve French } else if (rc == -EREMOTE) { 403a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 40438c8a9a5SSteve French rc = 0; 40538c8a9a5SSteve French } else 40638c8a9a5SSteve French goto cifs_gfiunix_out; 40738c8a9a5SSteve French 4089179aa27SBharath SM rc = cifs_fattr_to_inode(inode, &fattr, false); 40938c8a9a5SSteve French 41038c8a9a5SSteve French cifs_gfiunix_out: 41138c8a9a5SSteve French free_xid(xid); 41238c8a9a5SSteve French return rc; 41338c8a9a5SSteve French } 41438c8a9a5SSteve French 415a18280e7SPaulo Alcantara static int cifs_get_unix_fattr(const unsigned char *full_path, 416a18280e7SPaulo Alcantara struct super_block *sb, 417a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 418a18280e7SPaulo Alcantara struct inode **pinode, 419a18280e7SPaulo Alcantara const unsigned int xid) 42038c8a9a5SSteve French { 42138c8a9a5SSteve French struct TCP_Server_Info *server; 42238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 423a18280e7SPaulo Alcantara FILE_UNIX_BASIC_INFO find_data; 424a18280e7SPaulo Alcantara struct cifs_tcon *tcon; 425a18280e7SPaulo Alcantara struct tcon_link *tlink; 426a18280e7SPaulo Alcantara int rc, tmprc; 42738c8a9a5SSteve French 42838c8a9a5SSteve French cifs_dbg(FYI, "Getting info on %s\n", full_path); 42938c8a9a5SSteve French 43038c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 43138c8a9a5SSteve French if (IS_ERR(tlink)) 43238c8a9a5SSteve French return PTR_ERR(tlink); 43338c8a9a5SSteve French tcon = tlink_tcon(tlink); 43438c8a9a5SSteve French server = tcon->ses->server; 43538c8a9a5SSteve French 43638c8a9a5SSteve French /* could have done a find first instead but this returns more info */ 43738c8a9a5SSteve French rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, 43838c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 43938c8a9a5SSteve French cifs_dbg(FYI, "%s: query path info: rc = %d\n", __func__, rc); 44038c8a9a5SSteve French cifs_put_tlink(tlink); 44138c8a9a5SSteve French 44238c8a9a5SSteve French if (!rc) { 443a18280e7SPaulo Alcantara cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb); 44438c8a9a5SSteve French } else if (rc == -EREMOTE) { 445a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 44638c8a9a5SSteve French rc = 0; 44738c8a9a5SSteve French } else { 44838c8a9a5SSteve French return rc; 44938c8a9a5SSteve French } 45038c8a9a5SSteve French 451a18280e7SPaulo Alcantara if (!*pinode) 452a18280e7SPaulo Alcantara cifs_fill_uniqueid(sb, fattr); 453a18280e7SPaulo Alcantara 45438c8a9a5SSteve French /* check for Minshall+French symlinks */ 45538c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 456a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 45738c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 45838c8a9a5SSteve French } 45938c8a9a5SSteve French 460a18280e7SPaulo Alcantara if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { 46138c8a9a5SSteve French if (!server->ops->query_symlink) 46238c8a9a5SSteve French return -EOPNOTSUPP; 463a18280e7SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 464a18280e7SPaulo Alcantara cifs_sb, full_path, 4654d07e5dfSPaulo Alcantara &fattr->cf_symlink_target); 46638c8a9a5SSteve French cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 46738c8a9a5SSteve French } 468a18280e7SPaulo Alcantara return rc; 46938c8a9a5SSteve French } 47038c8a9a5SSteve French 471a18280e7SPaulo Alcantara int cifs_get_inode_info_unix(struct inode **pinode, 472a18280e7SPaulo Alcantara const unsigned char *full_path, 473a18280e7SPaulo Alcantara struct super_block *sb, unsigned int xid) 474a18280e7SPaulo Alcantara { 475a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 476a18280e7SPaulo Alcantara int rc; 47738c8a9a5SSteve French 478a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid); 479a18280e7SPaulo Alcantara if (rc) 480a18280e7SPaulo Alcantara goto out; 48138c8a9a5SSteve French 482a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, pinode); 483a18280e7SPaulo Alcantara out: 48438c8a9a5SSteve French kfree(fattr.cf_symlink_target); 48538c8a9a5SSteve French return rc; 48638c8a9a5SSteve French } 48738c8a9a5SSteve French #else 488a18280e7SPaulo Alcantara static inline int cifs_get_unix_fattr(const unsigned char *full_path, 489a18280e7SPaulo Alcantara struct super_block *sb, 490a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 491a18280e7SPaulo Alcantara struct inode **pinode, 492a18280e7SPaulo Alcantara const unsigned int xid) 493a18280e7SPaulo Alcantara { 494a18280e7SPaulo Alcantara return -EOPNOTSUPP; 495a18280e7SPaulo Alcantara } 496a18280e7SPaulo Alcantara 49738c8a9a5SSteve French int cifs_get_inode_info_unix(struct inode **pinode, 49838c8a9a5SSteve French const unsigned char *full_path, 49938c8a9a5SSteve French struct super_block *sb, unsigned int xid) 50038c8a9a5SSteve French { 50138c8a9a5SSteve French return -EOPNOTSUPP; 50238c8a9a5SSteve French } 50338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 50438c8a9a5SSteve French 50538c8a9a5SSteve French static int 50638c8a9a5SSteve French cifs_sfu_type(struct cifs_fattr *fattr, const char *path, 50738c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 50838c8a9a5SSteve French { 50938c8a9a5SSteve French int rc; 51038c8a9a5SSteve French __u32 oplock; 51138c8a9a5SSteve French struct tcon_link *tlink; 51238c8a9a5SSteve French struct cifs_tcon *tcon; 51338c8a9a5SSteve French struct cifs_fid fid; 51438c8a9a5SSteve French struct cifs_open_parms oparms; 51538c8a9a5SSteve French struct cifs_io_parms io_parms = {0}; 51638c8a9a5SSteve French char buf[24]; 51738c8a9a5SSteve French unsigned int bytes_read; 51838c8a9a5SSteve French char *pbuf; 51938c8a9a5SSteve French int buf_type = CIFS_NO_BUFFER; 52038c8a9a5SSteve French 52138c8a9a5SSteve French pbuf = buf; 52238c8a9a5SSteve French 52338c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 52438c8a9a5SSteve French 52538c8a9a5SSteve French if (fattr->cf_eof == 0) { 52638c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 52738c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 52838c8a9a5SSteve French return 0; 52938c8a9a5SSteve French } else if (fattr->cf_eof < 8) { 53038c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 53138c8a9a5SSteve French fattr->cf_dtype = DT_REG; 53238c8a9a5SSteve French return -EINVAL; /* EOPNOTSUPP? */ 53338c8a9a5SSteve French } 53438c8a9a5SSteve French 53538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 53638c8a9a5SSteve French if (IS_ERR(tlink)) 53738c8a9a5SSteve French return PTR_ERR(tlink); 53838c8a9a5SSteve French tcon = tlink_tcon(tlink); 53938c8a9a5SSteve French 54038c8a9a5SSteve French oparms = (struct cifs_open_parms) { 54138c8a9a5SSteve French .tcon = tcon, 54238c8a9a5SSteve French .cifs_sb = cifs_sb, 54338c8a9a5SSteve French .desired_access = GENERIC_READ, 54438c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 54538c8a9a5SSteve French .disposition = FILE_OPEN, 54638c8a9a5SSteve French .path = path, 54738c8a9a5SSteve French .fid = &fid, 54838c8a9a5SSteve French }; 54938c8a9a5SSteve French 55038c8a9a5SSteve French if (tcon->ses->server->oplocks) 55138c8a9a5SSteve French oplock = REQ_OPLOCK; 55238c8a9a5SSteve French else 55338c8a9a5SSteve French oplock = 0; 55438c8a9a5SSteve French rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); 55538c8a9a5SSteve French if (rc) { 55638c8a9a5SSteve French cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc); 55738c8a9a5SSteve French cifs_put_tlink(tlink); 55838c8a9a5SSteve French return rc; 55938c8a9a5SSteve French } 56038c8a9a5SSteve French 56138c8a9a5SSteve French /* Read header */ 56238c8a9a5SSteve French io_parms.netfid = fid.netfid; 56338c8a9a5SSteve French io_parms.pid = current->tgid; 56438c8a9a5SSteve French io_parms.tcon = tcon; 56538c8a9a5SSteve French io_parms.offset = 0; 56638c8a9a5SSteve French io_parms.length = 24; 56738c8a9a5SSteve French 56838c8a9a5SSteve French rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms, 56938c8a9a5SSteve French &bytes_read, &pbuf, &buf_type); 57038c8a9a5SSteve French if ((rc == 0) && (bytes_read >= 8)) { 57138c8a9a5SSteve French if (memcmp("IntxBLK", pbuf, 8) == 0) { 57238c8a9a5SSteve French cifs_dbg(FYI, "Block device\n"); 57338c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 57438c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 57538c8a9a5SSteve French if (bytes_read == 24) { 57638c8a9a5SSteve French /* we have enough to decode dev num */ 57738c8a9a5SSteve French __u64 mjr; /* major */ 57838c8a9a5SSteve French __u64 mnr; /* minor */ 57938c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 58038c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 58138c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 58238c8a9a5SSteve French } 58338c8a9a5SSteve French } else if (memcmp("IntxCHR", pbuf, 8) == 0) { 58438c8a9a5SSteve French cifs_dbg(FYI, "Char device\n"); 58538c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 58638c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 58738c8a9a5SSteve French if (bytes_read == 24) { 58838c8a9a5SSteve French /* we have enough to decode dev num */ 58938c8a9a5SSteve French __u64 mjr; /* major */ 59038c8a9a5SSteve French __u64 mnr; /* minor */ 59138c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 59238c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 59338c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 59438c8a9a5SSteve French } 59538c8a9a5SSteve French } else if (memcmp("IntxLNK", pbuf, 7) == 0) { 59638c8a9a5SSteve French cifs_dbg(FYI, "Symlink\n"); 59738c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 59838c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 599d6120327SSteve French } else if (memcmp("LnxFIFO", pbuf, 8) == 0) { 600d6120327SSteve French cifs_dbg(FYI, "FIFO\n"); 601d6120327SSteve French fattr->cf_mode |= S_IFIFO; 602d6120327SSteve French fattr->cf_dtype = DT_FIFO; 60338c8a9a5SSteve French } else { 60438c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* file? */ 60538c8a9a5SSteve French fattr->cf_dtype = DT_REG; 60638c8a9a5SSteve French rc = -EOPNOTSUPP; 60738c8a9a5SSteve French } 60838c8a9a5SSteve French } else { 60938c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* then it is a file */ 61038c8a9a5SSteve French fattr->cf_dtype = DT_REG; 61138c8a9a5SSteve French rc = -EOPNOTSUPP; /* or some unknown SFU type */ 61238c8a9a5SSteve French } 61338c8a9a5SSteve French 61438c8a9a5SSteve French tcon->ses->server->ops->close(xid, tcon, &fid); 61538c8a9a5SSteve French cifs_put_tlink(tlink); 61638c8a9a5SSteve French return rc; 61738c8a9a5SSteve French } 61838c8a9a5SSteve French 61938c8a9a5SSteve French #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ 62038c8a9a5SSteve French 62138c8a9a5SSteve French /* 62238c8a9a5SSteve French * Fetch mode bits as provided by SFU. 62338c8a9a5SSteve French * 62438c8a9a5SSteve French * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? 62538c8a9a5SSteve French */ 62638c8a9a5SSteve French static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, 62738c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 62838c8a9a5SSteve French { 62938c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR 63038c8a9a5SSteve French ssize_t rc; 63138c8a9a5SSteve French char ea_value[4]; 63238c8a9a5SSteve French __u32 mode; 63338c8a9a5SSteve French struct tcon_link *tlink; 63438c8a9a5SSteve French struct cifs_tcon *tcon; 63538c8a9a5SSteve French 63638c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 63738c8a9a5SSteve French if (IS_ERR(tlink)) 63838c8a9a5SSteve French return PTR_ERR(tlink); 63938c8a9a5SSteve French tcon = tlink_tcon(tlink); 64038c8a9a5SSteve French 64138c8a9a5SSteve French if (tcon->ses->server->ops->query_all_EAs == NULL) { 64238c8a9a5SSteve French cifs_put_tlink(tlink); 64338c8a9a5SSteve French return -EOPNOTSUPP; 64438c8a9a5SSteve French } 64538c8a9a5SSteve French 64638c8a9a5SSteve French rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, 64738c8a9a5SSteve French "SETFILEBITS", ea_value, 4 /* size of buf */, 64838c8a9a5SSteve French cifs_sb); 64938c8a9a5SSteve French cifs_put_tlink(tlink); 65038c8a9a5SSteve French if (rc < 0) 65138c8a9a5SSteve French return (int)rc; 65238c8a9a5SSteve French else if (rc > 3) { 65338c8a9a5SSteve French mode = le32_to_cpu(*((__le32 *)ea_value)); 65438c8a9a5SSteve French fattr->cf_mode &= ~SFBITS_MASK; 65538c8a9a5SSteve French cifs_dbg(FYI, "special bits 0%o org mode 0%o\n", 65638c8a9a5SSteve French mode, fattr->cf_mode); 65738c8a9a5SSteve French fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; 65838c8a9a5SSteve French cifs_dbg(FYI, "special mode bits 0%o\n", mode); 65938c8a9a5SSteve French } 66038c8a9a5SSteve French 66138c8a9a5SSteve French return 0; 66238c8a9a5SSteve French #else 66338c8a9a5SSteve French return -EOPNOTSUPP; 66438c8a9a5SSteve French #endif 66538c8a9a5SSteve French } 66638c8a9a5SSteve French 66738c8a9a5SSteve French /* Fill a cifs_fattr struct with info from POSIX info struct */ 6688b4e285dSPaulo Alcantara static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 6698b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 6708b4e285dSPaulo Alcantara struct super_block *sb) 67138c8a9a5SSteve French { 67238c8a9a5SSteve French struct smb311_posix_qinfo *info = &data->posix_fi; 67338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 67438c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 67538c8a9a5SSteve French 67638c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 67738c8a9a5SSteve French 67838c8a9a5SSteve French /* no fattr->flags to set */ 67938c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); 68038c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->Inode); 68138c8a9a5SSteve French 68238c8a9a5SSteve French if (info->LastAccessTime) 68338c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 68438c8a9a5SSteve French else 68538c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 68638c8a9a5SSteve French 68738c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 68838c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 68938c8a9a5SSteve French 6908b4e285dSPaulo Alcantara if (data->adjust_tz) { 69138c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 69238c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 69338c8a9a5SSteve French } 69438c8a9a5SSteve French 695304ff3c1SPaulo Alcantara /* 696304ff3c1SPaulo Alcantara * The srv fs device id is overridden on network mount so setting 697304ff3c1SPaulo Alcantara * @fattr->cf_rdev isn't needed here. 698304ff3c1SPaulo Alcantara */ 69938c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 70038c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 70138c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 70238c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->HardLinks); 70338c8a9a5SSteve French fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); 70438c8a9a5SSteve French 705304ff3c1SPaulo Alcantara if (cifs_open_data_reparse(data) && 706304ff3c1SPaulo Alcantara cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) 707304ff3c1SPaulo Alcantara goto out_reparse; 708304ff3c1SPaulo Alcantara 709304ff3c1SPaulo Alcantara fattr->cf_mode &= ~S_IFMT; 710304ff3c1SPaulo Alcantara if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 71138c8a9a5SSteve French fattr->cf_mode |= S_IFDIR; 71238c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 71338c8a9a5SSteve French } else { /* file */ 71438c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 71538c8a9a5SSteve French fattr->cf_dtype = DT_REG; 71638c8a9a5SSteve French } 71738c8a9a5SSteve French 718304ff3c1SPaulo Alcantara out_reparse: 719304ff3c1SPaulo Alcantara if (S_ISLNK(fattr->cf_mode)) { 720304ff3c1SPaulo Alcantara if (likely(data->symlink_target)) 721304ff3c1SPaulo Alcantara fattr->cf_eof = strnlen(data->symlink_target, PATH_MAX); 722304ff3c1SPaulo Alcantara fattr->cf_symlink_target = data->symlink_target; 723304ff3c1SPaulo Alcantara data->symlink_target = NULL; 724304ff3c1SPaulo Alcantara } 725a90f37e3SSteve French sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER); 726a90f37e3SSteve French sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP); 72738c8a9a5SSteve French 72838c8a9a5SSteve French cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", 72938c8a9a5SSteve French fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 73038c8a9a5SSteve French } 73138c8a9a5SSteve French 7328b4e285dSPaulo Alcantara static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, 7338b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 7348b4e285dSPaulo Alcantara struct super_block *sb) 73538c8a9a5SSteve French { 73638c8a9a5SSteve French struct smb2_file_all_info *info = &data->fi; 73738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 73838c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 73938c8a9a5SSteve French 74038c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 74138c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); 74238c8a9a5SSteve French if (info->DeletePending) 74338c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; 74438c8a9a5SSteve French 74538c8a9a5SSteve French if (info->LastAccessTime) 74638c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 74738c8a9a5SSteve French else 74838c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 74938c8a9a5SSteve French 75038c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 75138c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 75238c8a9a5SSteve French 7538b4e285dSPaulo Alcantara if (data->adjust_tz) { 75438c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 75538c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 75638c8a9a5SSteve French } 75738c8a9a5SSteve French 75838c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 75938c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 76038c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 76138c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 76297db4160SPaulo Alcantara fattr->cf_uid = cifs_sb->ctx->linux_uid; 76397db4160SPaulo Alcantara fattr->cf_gid = cifs_sb->ctx->linux_gid; 7645f71ebc4SPaulo Alcantara 765304ff3c1SPaulo Alcantara fattr->cf_mode = cifs_sb->ctx->file_mode; 7665f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data) && 767df32e887SPaulo Alcantara cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) 7685f71ebc4SPaulo Alcantara goto out_reparse; 7695f71ebc4SPaulo Alcantara 7705f71ebc4SPaulo Alcantara if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 77138c8a9a5SSteve French fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; 77238c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 77338c8a9a5SSteve French /* 77438c8a9a5SSteve French * Server can return wrong NumberOfLinks value for directories 77538c8a9a5SSteve French * when Unix extensions are disabled - fake it. 77638c8a9a5SSteve French */ 77738c8a9a5SSteve French if (!tcon->unix_ext) 77838c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 77938c8a9a5SSteve French } else { 78038c8a9a5SSteve French fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; 78138c8a9a5SSteve French fattr->cf_dtype = DT_REG; 78238c8a9a5SSteve French 78338c8a9a5SSteve French /* clear write bits if ATTR_READONLY is set */ 78438c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_READONLY) 78538c8a9a5SSteve French fattr->cf_mode &= ~(S_IWUGO); 78638c8a9a5SSteve French 78738c8a9a5SSteve French /* 78838c8a9a5SSteve French * Don't accept zero nlink from non-unix servers unless 78938c8a9a5SSteve French * delete is pending. Instead mark it as unknown. 79038c8a9a5SSteve French */ 79138c8a9a5SSteve French if ((fattr->cf_nlink < 1) && !tcon->unix_ext && 79238c8a9a5SSteve French !info->DeletePending) { 79338c8a9a5SSteve French cifs_dbg(VFS, "bogus file nlink value %u\n", 79438c8a9a5SSteve French fattr->cf_nlink); 79538c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 79638c8a9a5SSteve French } 79738c8a9a5SSteve French } 79838c8a9a5SSteve French 7995f71ebc4SPaulo Alcantara out_reparse: 80038c8a9a5SSteve French if (S_ISLNK(fattr->cf_mode)) { 8011de3dbd9SPaulo Alcantara if (likely(data->symlink_target)) 8021de3dbd9SPaulo Alcantara fattr->cf_eof = strnlen(data->symlink_target, PATH_MAX); 80338c8a9a5SSteve French fattr->cf_symlink_target = data->symlink_target; 80438c8a9a5SSteve French data->symlink_target = NULL; 80538c8a9a5SSteve French } 80638c8a9a5SSteve French } 80738c8a9a5SSteve French 80838c8a9a5SSteve French static int 80938c8a9a5SSteve French cifs_get_file_info(struct file *filp) 81038c8a9a5SSteve French { 81138c8a9a5SSteve French int rc; 81238c8a9a5SSteve French unsigned int xid; 81338c8a9a5SSteve French struct cifs_open_info_data data = {}; 81438c8a9a5SSteve French struct cifs_fattr fattr; 81538c8a9a5SSteve French struct inode *inode = file_inode(filp); 81638c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 81738c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 81838c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 819b6e27f7fSSteve French struct dentry *dentry = filp->f_path.dentry; 820b6e27f7fSSteve French void *page = alloc_dentry_path(); 821b6e27f7fSSteve French const unsigned char *path; 82238c8a9a5SSteve French 8231598a015SMeetakshi Setiya if (!server->ops->query_file_info) { 8241598a015SMeetakshi Setiya free_dentry_path(page); 82538c8a9a5SSteve French return -ENOSYS; 8261598a015SMeetakshi Setiya } 82738c8a9a5SSteve French 82838c8a9a5SSteve French xid = get_xid(); 82938c8a9a5SSteve French rc = server->ops->query_file_info(xid, tcon, cfile, &data); 83038c8a9a5SSteve French switch (rc) { 83138c8a9a5SSteve French case 0: 83238c8a9a5SSteve French /* TODO: add support to query reparse tag */ 8338b4e285dSPaulo Alcantara data.adjust_tz = false; 83438c8a9a5SSteve French if (data.symlink_target) { 8358b4e285dSPaulo Alcantara data.symlink = true; 836df32e887SPaulo Alcantara data.reparse.tag = IO_REPARSE_TAG_SYMLINK; 83738c8a9a5SSteve French } 838b6e27f7fSSteve French path = build_path_from_dentry(dentry, page); 839b6e27f7fSSteve French if (IS_ERR(path)) { 8401598a015SMeetakshi Setiya rc = PTR_ERR(path); 8411598a015SMeetakshi Setiya goto cgfi_exit; 842b6e27f7fSSteve French } 8438b4e285dSPaulo Alcantara cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); 844b6e27f7fSSteve French if (fattr.cf_flags & CIFS_FATTR_DELETE_PENDING) 845b6e27f7fSSteve French cifs_mark_open_handles_for_deleted_file(inode, path); 84638c8a9a5SSteve French break; 84738c8a9a5SSteve French case -EREMOTE: 848a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 84938c8a9a5SSteve French rc = 0; 85038c8a9a5SSteve French break; 85138c8a9a5SSteve French case -EOPNOTSUPP: 85238c8a9a5SSteve French case -EINVAL: 85338c8a9a5SSteve French /* 85438c8a9a5SSteve French * FIXME: legacy server -- fall back to path-based call? 85538c8a9a5SSteve French * for now, just skip revalidating and mark inode for 85638c8a9a5SSteve French * immediate reval. 85738c8a9a5SSteve French */ 85838c8a9a5SSteve French rc = 0; 85938c8a9a5SSteve French CIFS_I(inode)->time = 0; 86038c8a9a5SSteve French goto cgfi_exit; 86138c8a9a5SSteve French default: 86238c8a9a5SSteve French goto cgfi_exit; 86338c8a9a5SSteve French } 86438c8a9a5SSteve French 86538c8a9a5SSteve French /* 86638c8a9a5SSteve French * don't bother with SFU junk here -- just mark inode as needing 86738c8a9a5SSteve French * revalidation. 86838c8a9a5SSteve French */ 86938c8a9a5SSteve French fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; 87038c8a9a5SSteve French fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; 87138c8a9a5SSteve French /* if filetype is different, return error */ 8729179aa27SBharath SM rc = cifs_fattr_to_inode(inode, &fattr, false); 87338c8a9a5SSteve French cgfi_exit: 87438c8a9a5SSteve French cifs_free_open_info(&data); 875b6e27f7fSSteve French free_dentry_path(page); 87638c8a9a5SSteve French free_xid(xid); 87738c8a9a5SSteve French return rc; 87838c8a9a5SSteve French } 87938c8a9a5SSteve French 88038c8a9a5SSteve French /* Simple function to return a 64 bit hash of string. Rarely called */ 88138c8a9a5SSteve French static __u64 simple_hashstr(const char *str) 88238c8a9a5SSteve French { 88338c8a9a5SSteve French const __u64 hash_mult = 1125899906842597ULL; /* a big enough prime */ 88438c8a9a5SSteve French __u64 hash = 0; 88538c8a9a5SSteve French 88638c8a9a5SSteve French while (*str) 88738c8a9a5SSteve French hash = (hash + (__u64) *str++) * hash_mult; 88838c8a9a5SSteve French 88938c8a9a5SSteve French return hash; 89038c8a9a5SSteve French } 89138c8a9a5SSteve French 89238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 89338c8a9a5SSteve French /** 89438c8a9a5SSteve French * cifs_backup_query_path_info - SMB1 fallback code to get ino 89538c8a9a5SSteve French * 89638c8a9a5SSteve French * Fallback code to get file metadata when we don't have access to 89738c8a9a5SSteve French * full_path (EACCES) and have backup creds. 89838c8a9a5SSteve French * 89938c8a9a5SSteve French * @xid: transaction id used to identify original request in logs 90038c8a9a5SSteve French * @tcon: information about the server share we have mounted 90138c8a9a5SSteve French * @sb: the superblock stores info such as disk space available 90238c8a9a5SSteve French * @full_path: name of the file we are getting the metadata for 90338c8a9a5SSteve French * @resp_buf: will be set to cifs resp buf and needs to be freed with 90438c8a9a5SSteve French * cifs_buf_release() when done with @data 90538c8a9a5SSteve French * @data: will be set to search info result buffer 90638c8a9a5SSteve French */ 90738c8a9a5SSteve French static int 90838c8a9a5SSteve French cifs_backup_query_path_info(int xid, 90938c8a9a5SSteve French struct cifs_tcon *tcon, 91038c8a9a5SSteve French struct super_block *sb, 91138c8a9a5SSteve French const char *full_path, 91238c8a9a5SSteve French void **resp_buf, 91338c8a9a5SSteve French FILE_ALL_INFO **data) 91438c8a9a5SSteve French { 91538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 91638c8a9a5SSteve French struct cifs_search_info info = {0}; 91738c8a9a5SSteve French u16 flags; 91838c8a9a5SSteve French int rc; 91938c8a9a5SSteve French 92038c8a9a5SSteve French *resp_buf = NULL; 92138c8a9a5SSteve French info.endOfSearch = false; 92238c8a9a5SSteve French if (tcon->unix_ext) 92338c8a9a5SSteve French info.info_level = SMB_FIND_FILE_UNIX; 92438c8a9a5SSteve French else if ((tcon->ses->capabilities & 92538c8a9a5SSteve French tcon->ses->server->vals->cap_nt_find) == 0) 92638c8a9a5SSteve French info.info_level = SMB_FIND_FILE_INFO_STANDARD; 92738c8a9a5SSteve French else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 92838c8a9a5SSteve French info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 92938c8a9a5SSteve French else /* no srvino useful for fallback to some netapp */ 93038c8a9a5SSteve French info.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 93138c8a9a5SSteve French 93238c8a9a5SSteve French flags = CIFS_SEARCH_CLOSE_ALWAYS | 93338c8a9a5SSteve French CIFS_SEARCH_CLOSE_AT_END | 93438c8a9a5SSteve French CIFS_SEARCH_BACKUP_SEARCH; 93538c8a9a5SSteve French 93638c8a9a5SSteve French rc = CIFSFindFirst(xid, tcon, full_path, 93738c8a9a5SSteve French cifs_sb, NULL, flags, &info, false); 93838c8a9a5SSteve French if (rc) 93938c8a9a5SSteve French return rc; 94038c8a9a5SSteve French 94138c8a9a5SSteve French *resp_buf = (void *)info.ntwrk_buf_start; 94238c8a9a5SSteve French *data = (FILE_ALL_INFO *)info.srch_entries_start; 94338c8a9a5SSteve French return 0; 94438c8a9a5SSteve French } 94538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 94638c8a9a5SSteve French 94738c8a9a5SSteve French static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_block *sb, 94838c8a9a5SSteve French struct inode **inode, const char *full_path, 94938c8a9a5SSteve French struct cifs_open_info_data *data, struct cifs_fattr *fattr) 95038c8a9a5SSteve French { 95138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 95238c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 95338c8a9a5SSteve French int rc; 95438c8a9a5SSteve French 95538c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 95638c8a9a5SSteve French if (*inode) 95738c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 95838c8a9a5SSteve French else 95938c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 96038c8a9a5SSteve French return; 96138c8a9a5SSteve French } 96238c8a9a5SSteve French 96338c8a9a5SSteve French /* 96438c8a9a5SSteve French * If we have an inode pass a NULL tcon to ensure we don't 96538c8a9a5SSteve French * make a round trip to the server. This only works for SMB2+. 96638c8a9a5SSteve French */ 96738c8a9a5SSteve French rc = server->ops->get_srv_inum(xid, *inode ? NULL : tcon, cifs_sb, full_path, 96838c8a9a5SSteve French &fattr->cf_uniqueid, data); 96938c8a9a5SSteve French if (rc) { 97038c8a9a5SSteve French /* 97138c8a9a5SSteve French * If that fails reuse existing ino or generate one 97238c8a9a5SSteve French * and disable server ones 97338c8a9a5SSteve French */ 97438c8a9a5SSteve French if (*inode) 97538c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 97638c8a9a5SSteve French else { 97738c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 97838c8a9a5SSteve French cifs_autodisable_serverino(cifs_sb); 97938c8a9a5SSteve French } 98038c8a9a5SSteve French return; 98138c8a9a5SSteve French } 98238c8a9a5SSteve French 98338c8a9a5SSteve French /* If no errors, check for zero root inode (invalid) */ 98438c8a9a5SSteve French if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) { 98538c8a9a5SSteve French cifs_dbg(FYI, "Invalid (0) inodenum\n"); 98638c8a9a5SSteve French if (*inode) { 98738c8a9a5SSteve French /* reuse */ 98838c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 98938c8a9a5SSteve French } else { 99038c8a9a5SSteve French /* make an ino by hashing the UNC */ 99138c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO; 99238c8a9a5SSteve French fattr->cf_uniqueid = simple_hashstr(tcon->tree_name); 99338c8a9a5SSteve French } 99438c8a9a5SSteve French } 99538c8a9a5SSteve French } 99638c8a9a5SSteve French 99738c8a9a5SSteve French static inline bool is_inode_cache_good(struct inode *ino) 99838c8a9a5SSteve French { 99938c8a9a5SSteve French return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0; 100038c8a9a5SSteve French } 100138c8a9a5SSteve French 1002a18280e7SPaulo Alcantara static int reparse_info_to_fattr(struct cifs_open_info_data *data, 10035f71ebc4SPaulo Alcantara struct super_block *sb, 10045f71ebc4SPaulo Alcantara const unsigned int xid, 10055f71ebc4SPaulo Alcantara struct cifs_tcon *tcon, 10065f71ebc4SPaulo Alcantara const char *full_path, 1007a90f37e3SSteve French struct cifs_fattr *fattr) 100838c8a9a5SSteve French { 10095f71ebc4SPaulo Alcantara struct TCP_Server_Info *server = tcon->ses->server; 10105f71ebc4SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 10119a49e221SPaulo Alcantara struct kvec rsp_iov, *iov = NULL; 10129a49e221SPaulo Alcantara int rsp_buftype = CIFS_NO_BUFFER; 1013df32e887SPaulo Alcantara u32 tag = data->reparse.tag; 10145f71ebc4SPaulo Alcantara int rc = 0; 10155f71ebc4SPaulo Alcantara 10169a49e221SPaulo Alcantara if (!tag && server->ops->query_reparse_point) { 10179a49e221SPaulo Alcantara rc = server->ops->query_reparse_point(xid, tcon, cifs_sb, 10189a49e221SPaulo Alcantara full_path, &tag, 10199a49e221SPaulo Alcantara &rsp_iov, &rsp_buftype); 10209a49e221SPaulo Alcantara if (!rc) 10219a49e221SPaulo Alcantara iov = &rsp_iov; 1022a158bb66SSteve French } else if (data->reparse.io.buftype != CIFS_NO_BUFFER && 1023a158bb66SSteve French data->reparse.io.iov.iov_base) { 1024a158bb66SSteve French iov = &data->reparse.io.iov; 10255f71ebc4SPaulo Alcantara } 10264d07e5dfSPaulo Alcantara 10274d07e5dfSPaulo Alcantara rc = -EOPNOTSUPP; 1028df32e887SPaulo Alcantara switch ((data->reparse.tag = tag)) { 10295f71ebc4SPaulo Alcantara case 0: /* SMB1 symlink */ 10304d07e5dfSPaulo Alcantara if (server->ops->query_symlink) { 10315f71ebc4SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 10325f71ebc4SPaulo Alcantara cifs_sb, full_path, 10334d07e5dfSPaulo Alcantara &data->symlink_target); 10345f71ebc4SPaulo Alcantara } 10355f71ebc4SPaulo Alcantara break; 1036a18280e7SPaulo Alcantara case IO_REPARSE_TAG_MOUNT_POINT: 1037a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 10384d07e5dfSPaulo Alcantara rc = 0; 1039a18280e7SPaulo Alcantara goto out; 10404d07e5dfSPaulo Alcantara default: 104102bcf865SSteve French /* Check for cached reparse point data */ 104202bcf865SSteve French if (data->symlink_target || data->reparse.buf) { 10434d07e5dfSPaulo Alcantara rc = 0; 1044a158bb66SSteve French } else if (iov && server->ops->parse_reparse_point) { 10454d07e5dfSPaulo Alcantara rc = server->ops->parse_reparse_point(cifs_sb, 10464d07e5dfSPaulo Alcantara iov, data); 10474d07e5dfSPaulo Alcantara } 10484d07e5dfSPaulo Alcantara break; 10495f71ebc4SPaulo Alcantara } 1050a18280e7SPaulo Alcantara 105102bcf865SSteve French if (tcon->posix_extensions) 1052a90f37e3SSteve French smb311_posix_info_to_fattr(fattr, data, sb); 10531598a015SMeetakshi Setiya else 1054a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 1055a18280e7SPaulo Alcantara out: 1056b9e741acSPaulo Alcantara fattr->cf_cifstag = data->reparse.tag; 10579a49e221SPaulo Alcantara free_rsp_buf(rsp_buftype, rsp_iov.iov_base); 10585f71ebc4SPaulo Alcantara return rc; 10595f71ebc4SPaulo Alcantara } 10605f71ebc4SPaulo Alcantara 1061a18280e7SPaulo Alcantara static int cifs_get_fattr(struct cifs_open_info_data *data, 1062a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1063a18280e7SPaulo Alcantara const struct cifs_fid *fid, 1064a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 1065a18280e7SPaulo Alcantara struct inode **inode, 1066a18280e7SPaulo Alcantara const char *full_path) 106738c8a9a5SSteve French { 1068a18280e7SPaulo Alcantara struct cifs_open_info_data tmp_data = {}; 106938c8a9a5SSteve French struct cifs_tcon *tcon; 107038c8a9a5SSteve French struct TCP_Server_Info *server; 107138c8a9a5SSteve French struct tcon_link *tlink; 107238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 107338c8a9a5SSteve French void *smb1_backup_rsp_buf = NULL; 107438c8a9a5SSteve French int rc = 0; 107538c8a9a5SSteve French int tmprc = 0; 107638c8a9a5SSteve French 107738c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 107838c8a9a5SSteve French if (IS_ERR(tlink)) 107938c8a9a5SSteve French return PTR_ERR(tlink); 108038c8a9a5SSteve French tcon = tlink_tcon(tlink); 108138c8a9a5SSteve French server = tcon->ses->server; 108238c8a9a5SSteve French 108338c8a9a5SSteve French /* 108438c8a9a5SSteve French * 1. Fetch file metadata if not provided (data) 108538c8a9a5SSteve French */ 108638c8a9a5SSteve French 108738c8a9a5SSteve French if (!data) { 10888b4e285dSPaulo Alcantara rc = server->ops->query_path_info(xid, tcon, cifs_sb, 10898b4e285dSPaulo Alcantara full_path, &tmp_data); 109038c8a9a5SSteve French data = &tmp_data; 109138c8a9a5SSteve French } 109238c8a9a5SSteve French 109338c8a9a5SSteve French /* 109438c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 109538c8a9a5SSteve French */ 109638c8a9a5SSteve French 109738c8a9a5SSteve French switch (rc) { 109838c8a9a5SSteve French case 0: 109938c8a9a5SSteve French /* 110038c8a9a5SSteve French * If the file is a reparse point, it is more complicated 110138c8a9a5SSteve French * since we have to check if its reparse tag matches a known 110238c8a9a5SSteve French * special file type e.g. symlink or fifo or char etc. 110338c8a9a5SSteve French */ 11045f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data)) { 1105a18280e7SPaulo Alcantara rc = reparse_info_to_fattr(data, sb, xid, tcon, 1106a90f37e3SSteve French full_path, fattr); 1107a18280e7SPaulo Alcantara } else { 1108a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 110938c8a9a5SSteve French } 11101598a015SMeetakshi Setiya if (!rc && fattr->cf_flags & CIFS_FATTR_DELETE_PENDING) 11111598a015SMeetakshi Setiya cifs_mark_open_handles_for_deleted_file(*inode, full_path); 111238c8a9a5SSteve French break; 111338c8a9a5SSteve French case -EREMOTE: 111438c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1115a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 111638c8a9a5SSteve French rc = 0; 111738c8a9a5SSteve French break; 111838c8a9a5SSteve French case -EACCES: 111938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 112038c8a9a5SSteve French /* 112138c8a9a5SSteve French * perm errors, try again with backup flags if possible 112238c8a9a5SSteve French * 112338c8a9a5SSteve French * For SMB2 and later the backup intent flag 112438c8a9a5SSteve French * is already sent if needed on open and there 112538c8a9a5SSteve French * is no path based FindFirst operation to use 112638c8a9a5SSteve French * to retry with 112738c8a9a5SSteve French */ 112838c8a9a5SSteve French if (backup_cred(cifs_sb) && is_smb1_server(server)) { 112938c8a9a5SSteve French /* for easier reading */ 113038c8a9a5SSteve French FILE_ALL_INFO *fi; 113138c8a9a5SSteve French FILE_DIRECTORY_INFO *fdi; 113238c8a9a5SSteve French SEARCH_ID_FULL_DIR_INFO *si; 113338c8a9a5SSteve French 113438c8a9a5SSteve French rc = cifs_backup_query_path_info(xid, tcon, sb, 113538c8a9a5SSteve French full_path, 113638c8a9a5SSteve French &smb1_backup_rsp_buf, 113738c8a9a5SSteve French &fi); 113838c8a9a5SSteve French if (rc) 113938c8a9a5SSteve French goto out; 114038c8a9a5SSteve French 114138c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, fi); 114238c8a9a5SSteve French fdi = (FILE_DIRECTORY_INFO *)fi; 114338c8a9a5SSteve French si = (SEARCH_ID_FULL_DIR_INFO *)fi; 114438c8a9a5SSteve French 1145a18280e7SPaulo Alcantara cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); 1146a18280e7SPaulo Alcantara fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); 114738c8a9a5SSteve French /* uniqueid set, skip get inum step */ 114838c8a9a5SSteve French goto handle_mnt_opt; 114938c8a9a5SSteve French } else { 115038c8a9a5SSteve French /* nothing we can do, bail out */ 115138c8a9a5SSteve French goto out; 115238c8a9a5SSteve French } 115338c8a9a5SSteve French #else 115438c8a9a5SSteve French goto out; 115538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 115638c8a9a5SSteve French break; 115738c8a9a5SSteve French default: 115838c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 115938c8a9a5SSteve French goto out; 116038c8a9a5SSteve French } 116138c8a9a5SSteve French 116238c8a9a5SSteve French /* 1163a18280e7SPaulo Alcantara * 3. Get or update inode number (fattr->cf_uniqueid) 116438c8a9a5SSteve French */ 116538c8a9a5SSteve French 1166a18280e7SPaulo Alcantara cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr); 116738c8a9a5SSteve French 116838c8a9a5SSteve French /* 116938c8a9a5SSteve French * 4. Tweak fattr based on mount options 117038c8a9a5SSteve French */ 117138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 117238c8a9a5SSteve French handle_mnt_opt: 117338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 117438c8a9a5SSteve French /* query for SFU type info if supported and needed */ 1175a18280e7SPaulo Alcantara if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && 1176a18280e7SPaulo Alcantara (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { 1177a18280e7SPaulo Alcantara tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid); 117838c8a9a5SSteve French if (tmprc) 117938c8a9a5SSteve French cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); 118038c8a9a5SSteve French } 118138c8a9a5SSteve French 118238c8a9a5SSteve French /* fill in 0777 bits from ACL */ 118338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { 1184a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1185a18280e7SPaulo Alcantara true, full_path, fid); 118638c8a9a5SSteve French if (rc == -EREMOTE) 118738c8a9a5SSteve French rc = 0; 118838c8a9a5SSteve French if (rc) { 118938c8a9a5SSteve French cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n", 119038c8a9a5SSteve French __func__, rc); 119138c8a9a5SSteve French goto out; 119238c8a9a5SSteve French } 119338c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 1194a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1195a18280e7SPaulo Alcantara false, full_path, fid); 119638c8a9a5SSteve French if (rc == -EREMOTE) 119738c8a9a5SSteve French rc = 0; 119838c8a9a5SSteve French if (rc) { 119938c8a9a5SSteve French cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n", 120038c8a9a5SSteve French __func__, rc); 120138c8a9a5SSteve French goto out; 120238c8a9a5SSteve French } 120338c8a9a5SSteve French } 120438c8a9a5SSteve French 120538c8a9a5SSteve French /* fill in remaining high mode bits e.g. SUID, VTX */ 120638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) 1207a18280e7SPaulo Alcantara cifs_sfu_mode(fattr, full_path, cifs_sb, xid); 120838c8a9a5SSteve French 120938c8a9a5SSteve French /* check for Minshall+French symlinks */ 121038c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1211a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 121238c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 121338c8a9a5SSteve French } 121438c8a9a5SSteve French 121538c8a9a5SSteve French out: 121638c8a9a5SSteve French cifs_buf_release(smb1_backup_rsp_buf); 121738c8a9a5SSteve French cifs_put_tlink(tlink); 121838c8a9a5SSteve French cifs_free_open_info(&tmp_data); 1219a18280e7SPaulo Alcantara return rc; 1220a18280e7SPaulo Alcantara } 1221a18280e7SPaulo Alcantara 1222a18280e7SPaulo Alcantara int cifs_get_inode_info(struct inode **inode, 1223a18280e7SPaulo Alcantara const char *full_path, 1224a18280e7SPaulo Alcantara struct cifs_open_info_data *data, 1225a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1226a18280e7SPaulo Alcantara const struct cifs_fid *fid) 1227a18280e7SPaulo Alcantara { 1228a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1229a18280e7SPaulo Alcantara int rc; 1230a18280e7SPaulo Alcantara 1231a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1232a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1233a18280e7SPaulo Alcantara return 0; 1234a18280e7SPaulo Alcantara } 1235a18280e7SPaulo Alcantara 1236a18280e7SPaulo Alcantara rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path); 1237a18280e7SPaulo Alcantara if (rc) 1238a18280e7SPaulo Alcantara goto out; 1239a18280e7SPaulo Alcantara 1240a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 1241a18280e7SPaulo Alcantara out: 124238c8a9a5SSteve French kfree(fattr.cf_symlink_target); 124338c8a9a5SSteve French return rc; 124438c8a9a5SSteve French } 124538c8a9a5SSteve French 124602bcf865SSteve French static int smb311_posix_get_fattr(struct cifs_open_info_data *data, 124702bcf865SSteve French struct cifs_fattr *fattr, 124838c8a9a5SSteve French const char *full_path, 1249a18280e7SPaulo Alcantara struct super_block *sb, 1250a18280e7SPaulo Alcantara const unsigned int xid) 125138c8a9a5SSteve French { 125202bcf865SSteve French struct cifs_open_info_data tmp_data = {}; 1253cfb8f73dSPaulo Alcantara struct TCP_Server_Info *server; 1254a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 125538c8a9a5SSteve French struct cifs_tcon *tcon; 125638c8a9a5SSteve French struct tcon_link *tlink; 1257a18280e7SPaulo Alcantara int tmprc; 125802bcf865SSteve French int rc = 0; 125938c8a9a5SSteve French 126038c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 126138c8a9a5SSteve French if (IS_ERR(tlink)) 126238c8a9a5SSteve French return PTR_ERR(tlink); 126338c8a9a5SSteve French tcon = tlink_tcon(tlink); 1264cfb8f73dSPaulo Alcantara server = tcon->ses->server; 126538c8a9a5SSteve French 126638c8a9a5SSteve French /* 126702bcf865SSteve French * 1. Fetch file metadata if not provided (data) 126838c8a9a5SSteve French */ 126902bcf865SSteve French if (!data) { 1270cfb8f73dSPaulo Alcantara rc = server->ops->query_path_info(xid, tcon, cifs_sb, 1271a90f37e3SSteve French full_path, &tmp_data); 127202bcf865SSteve French data = &tmp_data; 127302bcf865SSteve French } 127438c8a9a5SSteve French 127538c8a9a5SSteve French /* 127638c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 127738c8a9a5SSteve French */ 127838c8a9a5SSteve French 127938c8a9a5SSteve French switch (rc) { 128038c8a9a5SSteve French case 0: 128102bcf865SSteve French if (cifs_open_data_reparse(data)) { 128202bcf865SSteve French rc = reparse_info_to_fattr(data, sb, xid, tcon, 1283a90f37e3SSteve French full_path, fattr); 128402bcf865SSteve French } else { 1285a90f37e3SSteve French smb311_posix_info_to_fattr(fattr, data, sb); 128602bcf865SSteve French } 128738c8a9a5SSteve French break; 128838c8a9a5SSteve French case -EREMOTE: 128938c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1290a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 129138c8a9a5SSteve French rc = 0; 129238c8a9a5SSteve French break; 129338c8a9a5SSteve French case -EACCES: 129438c8a9a5SSteve French /* 129538c8a9a5SSteve French * For SMB2 and later the backup intent flag 129638c8a9a5SSteve French * is already sent if needed on open and there 129738c8a9a5SSteve French * is no path based FindFirst operation to use 129838c8a9a5SSteve French * to retry with so nothing we can do, bail out 129938c8a9a5SSteve French */ 130038c8a9a5SSteve French goto out; 130138c8a9a5SSteve French default: 130238c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 130338c8a9a5SSteve French goto out; 130438c8a9a5SSteve French } 130538c8a9a5SSteve French 130638c8a9a5SSteve French /* 130738c8a9a5SSteve French * 3. Tweak fattr based on mount options 130838c8a9a5SSteve French */ 130938c8a9a5SSteve French /* check for Minshall+French symlinks */ 131038c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1311a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 131238c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 131338c8a9a5SSteve French } 131438c8a9a5SSteve French 131538c8a9a5SSteve French out: 131638c8a9a5SSteve French cifs_put_tlink(tlink); 131702bcf865SSteve French cifs_free_open_info(data); 131838c8a9a5SSteve French return rc; 131938c8a9a5SSteve French } 132038c8a9a5SSteve French 132102bcf865SSteve French int smb311_posix_get_inode_info(struct inode **inode, 132202bcf865SSteve French const char *full_path, 132302bcf865SSteve French struct cifs_open_info_data *data, 132402bcf865SSteve French struct super_block *sb, 132502bcf865SSteve French const unsigned int xid) 1326a18280e7SPaulo Alcantara { 1327a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1328a18280e7SPaulo Alcantara int rc; 1329a18280e7SPaulo Alcantara 1330a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1331a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1332a18280e7SPaulo Alcantara return 0; 1333a18280e7SPaulo Alcantara } 1334a18280e7SPaulo Alcantara 133502bcf865SSteve French rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid); 1336a18280e7SPaulo Alcantara if (rc) 1337a18280e7SPaulo Alcantara goto out; 1338a18280e7SPaulo Alcantara 1339a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 13401598a015SMeetakshi Setiya if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING) 13411598a015SMeetakshi Setiya cifs_mark_open_handles_for_deleted_file(*inode, full_path); 1342a18280e7SPaulo Alcantara out: 1343a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 1344a18280e7SPaulo Alcantara return rc; 1345a18280e7SPaulo Alcantara } 134638c8a9a5SSteve French 134738c8a9a5SSteve French static const struct inode_operations cifs_ipc_inode_ops = { 134838c8a9a5SSteve French .lookup = cifs_lookup, 134938c8a9a5SSteve French }; 135038c8a9a5SSteve French 135138c8a9a5SSteve French static int 135238c8a9a5SSteve French cifs_find_inode(struct inode *inode, void *opaque) 135338c8a9a5SSteve French { 135438c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 135538c8a9a5SSteve French 1356614bc8c7SDavid Howells /* [!] The compared values must be the same in struct cifs_fscache_inode_key. */ 1357614bc8c7SDavid Howells 135838c8a9a5SSteve French /* don't match inode with different uniqueid */ 135938c8a9a5SSteve French if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) 136038c8a9a5SSteve French return 0; 136138c8a9a5SSteve French 136238c8a9a5SSteve French /* use createtime like an i_generation field */ 136338c8a9a5SSteve French if (CIFS_I(inode)->createtime != fattr->cf_createtime) 136438c8a9a5SSteve French return 0; 136538c8a9a5SSteve French 136638c8a9a5SSteve French /* don't match inode of different type */ 136738c8a9a5SSteve French if (inode_wrong_type(inode, fattr->cf_mode)) 136838c8a9a5SSteve French return 0; 136938c8a9a5SSteve French 137038c8a9a5SSteve French /* if it's not a directory or has no dentries, then flag it */ 137138c8a9a5SSteve French if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) 137238c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; 137338c8a9a5SSteve French 137438c8a9a5SSteve French return 1; 137538c8a9a5SSteve French } 137638c8a9a5SSteve French 137738c8a9a5SSteve French static int 137838c8a9a5SSteve French cifs_init_inode(struct inode *inode, void *opaque) 137938c8a9a5SSteve French { 138038c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 138138c8a9a5SSteve French 138238c8a9a5SSteve French CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; 138338c8a9a5SSteve French CIFS_I(inode)->createtime = fattr->cf_createtime; 138438c8a9a5SSteve French return 0; 138538c8a9a5SSteve French } 138638c8a9a5SSteve French 138738c8a9a5SSteve French /* 138838c8a9a5SSteve French * walk dentry list for an inode and report whether it has aliases that 138938c8a9a5SSteve French * are hashed. We use this to determine if a directory inode can actually 139038c8a9a5SSteve French * be used. 139138c8a9a5SSteve French */ 139238c8a9a5SSteve French static bool 139338c8a9a5SSteve French inode_has_hashed_dentries(struct inode *inode) 139438c8a9a5SSteve French { 139538c8a9a5SSteve French struct dentry *dentry; 139638c8a9a5SSteve French 139738c8a9a5SSteve French spin_lock(&inode->i_lock); 139838c8a9a5SSteve French hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { 139938c8a9a5SSteve French if (!d_unhashed(dentry) || IS_ROOT(dentry)) { 140038c8a9a5SSteve French spin_unlock(&inode->i_lock); 140138c8a9a5SSteve French return true; 140238c8a9a5SSteve French } 140338c8a9a5SSteve French } 140438c8a9a5SSteve French spin_unlock(&inode->i_lock); 140538c8a9a5SSteve French return false; 140638c8a9a5SSteve French } 140738c8a9a5SSteve French 140838c8a9a5SSteve French /* Given fattrs, get a corresponding inode */ 140938c8a9a5SSteve French struct inode * 141038c8a9a5SSteve French cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) 141138c8a9a5SSteve French { 141238c8a9a5SSteve French unsigned long hash; 141338c8a9a5SSteve French struct inode *inode; 141438c8a9a5SSteve French 141538c8a9a5SSteve French retry_iget5_locked: 141638c8a9a5SSteve French cifs_dbg(FYI, "looking for uniqueid=%llu\n", fattr->cf_uniqueid); 141738c8a9a5SSteve French 141838c8a9a5SSteve French /* hash down to 32-bits on 32-bit arch */ 141938c8a9a5SSteve French hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); 142038c8a9a5SSteve French 142138c8a9a5SSteve French inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); 142238c8a9a5SSteve French if (inode) { 142338c8a9a5SSteve French /* was there a potentially problematic inode collision? */ 142438c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { 142538c8a9a5SSteve French fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; 142638c8a9a5SSteve French 142738c8a9a5SSteve French if (inode_has_hashed_dentries(inode)) { 142838c8a9a5SSteve French cifs_autodisable_serverino(CIFS_SB(sb)); 142938c8a9a5SSteve French iput(inode); 143038c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 143138c8a9a5SSteve French goto retry_iget5_locked; 143238c8a9a5SSteve French } 143338c8a9a5SSteve French } 143438c8a9a5SSteve French 143538c8a9a5SSteve French /* can't fail - see cifs_find_inode() */ 14369179aa27SBharath SM cifs_fattr_to_inode(inode, fattr, false); 143738c8a9a5SSteve French if (sb->s_flags & SB_NOATIME) 143838c8a9a5SSteve French inode->i_flags |= S_NOATIME | S_NOCMTIME; 143938c8a9a5SSteve French if (inode->i_state & I_NEW) { 144038c8a9a5SSteve French inode->i_ino = hash; 144138c8a9a5SSteve French cifs_fscache_get_inode_cookie(inode); 144238c8a9a5SSteve French unlock_new_inode(inode); 144338c8a9a5SSteve French } 144438c8a9a5SSteve French } 144538c8a9a5SSteve French 144638c8a9a5SSteve French return inode; 144738c8a9a5SSteve French } 144838c8a9a5SSteve French 144938c8a9a5SSteve French /* gets root inode */ 145038c8a9a5SSteve French struct inode *cifs_root_iget(struct super_block *sb) 145138c8a9a5SSteve French { 145238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1453a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 145438c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1455a18280e7SPaulo Alcantara struct inode *inode = NULL; 1456a18280e7SPaulo Alcantara unsigned int xid; 145738c8a9a5SSteve French char *path = NULL; 145838c8a9a5SSteve French int len; 1459a18280e7SPaulo Alcantara int rc; 146038c8a9a5SSteve French 146138c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 146238c8a9a5SSteve French && cifs_sb->prepath) { 146338c8a9a5SSteve French len = strlen(cifs_sb->prepath); 146438c8a9a5SSteve French path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL); 146538c8a9a5SSteve French if (path == NULL) 146638c8a9a5SSteve French return ERR_PTR(-ENOMEM); 146738c8a9a5SSteve French path[0] = '/'; 146838c8a9a5SSteve French memcpy(path+1, cifs_sb->prepath, len); 146938c8a9a5SSteve French } else { 147038c8a9a5SSteve French path = kstrdup("", GFP_KERNEL); 147138c8a9a5SSteve French if (path == NULL) 147238c8a9a5SSteve French return ERR_PTR(-ENOMEM); 147338c8a9a5SSteve French } 147438c8a9a5SSteve French 147538c8a9a5SSteve French xid = get_xid(); 147638c8a9a5SSteve French if (tcon->unix_ext) { 1477a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid); 147838c8a9a5SSteve French /* some servers mistakenly claim POSIX support */ 147938c8a9a5SSteve French if (rc != -EOPNOTSUPP) 1480a18280e7SPaulo Alcantara goto iget_root; 148138c8a9a5SSteve French cifs_dbg(VFS, "server does not support POSIX extensions\n"); 148238c8a9a5SSteve French tcon->unix_ext = false; 148338c8a9a5SSteve French } 148438c8a9a5SSteve French 148538c8a9a5SSteve French convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); 148638c8a9a5SSteve French if (tcon->posix_extensions) 148702bcf865SSteve French rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid); 148838c8a9a5SSteve French else 1489a18280e7SPaulo Alcantara rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); 149038c8a9a5SSteve French 1491a18280e7SPaulo Alcantara iget_root: 1492a18280e7SPaulo Alcantara if (!rc) { 1493a18280e7SPaulo Alcantara if (fattr.cf_flags & CIFS_FATTR_JUNCTION) { 1494a18280e7SPaulo Alcantara fattr.cf_flags &= ~CIFS_FATTR_JUNCTION; 1495a18280e7SPaulo Alcantara cifs_autodisable_serverino(cifs_sb); 1496a18280e7SPaulo Alcantara } 1497a18280e7SPaulo Alcantara inode = cifs_iget(sb, &fattr); 1498a18280e7SPaulo Alcantara } 1499a18280e7SPaulo Alcantara 150038c8a9a5SSteve French if (!inode) { 150138c8a9a5SSteve French inode = ERR_PTR(rc); 150238c8a9a5SSteve French goto out; 150338c8a9a5SSteve French } 150438c8a9a5SSteve French 15051598a015SMeetakshi Setiya if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING) 15061598a015SMeetakshi Setiya cifs_mark_open_handles_for_deleted_file(inode, path); 15071598a015SMeetakshi Setiya 150838c8a9a5SSteve French if (rc && tcon->pipe) { 150938c8a9a5SSteve French cifs_dbg(FYI, "ipc connection - fake read inode\n"); 151038c8a9a5SSteve French spin_lock(&inode->i_lock); 151138c8a9a5SSteve French inode->i_mode |= S_IFDIR; 151238c8a9a5SSteve French set_nlink(inode, 2); 151338c8a9a5SSteve French inode->i_op = &cifs_ipc_inode_ops; 151438c8a9a5SSteve French inode->i_fop = &simple_dir_operations; 151538c8a9a5SSteve French inode->i_uid = cifs_sb->ctx->linux_uid; 151638c8a9a5SSteve French inode->i_gid = cifs_sb->ctx->linux_gid; 151738c8a9a5SSteve French spin_unlock(&inode->i_lock); 151838c8a9a5SSteve French } else if (rc) { 151938c8a9a5SSteve French iget_failed(inode); 152038c8a9a5SSteve French inode = ERR_PTR(rc); 152138c8a9a5SSteve French } 152238c8a9a5SSteve French 152338c8a9a5SSteve French out: 152438c8a9a5SSteve French kfree(path); 152538c8a9a5SSteve French free_xid(xid); 1526a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 152738c8a9a5SSteve French return inode; 152838c8a9a5SSteve French } 152938c8a9a5SSteve French 153038c8a9a5SSteve French int 153138c8a9a5SSteve French cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, 153238c8a9a5SSteve French const char *full_path, __u32 dosattr) 153338c8a9a5SSteve French { 153438c8a9a5SSteve French bool set_time = false; 153538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 153638c8a9a5SSteve French struct TCP_Server_Info *server; 153738c8a9a5SSteve French FILE_BASIC_INFO info_buf; 153838c8a9a5SSteve French 153938c8a9a5SSteve French if (attrs == NULL) 154038c8a9a5SSteve French return -EINVAL; 154138c8a9a5SSteve French 154238c8a9a5SSteve French server = cifs_sb_master_tcon(cifs_sb)->ses->server; 154338c8a9a5SSteve French if (!server->ops->set_file_info) 154438c8a9a5SSteve French return -ENOSYS; 154538c8a9a5SSteve French 154638c8a9a5SSteve French info_buf.Pad = 0; 154738c8a9a5SSteve French 154838c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) { 154938c8a9a5SSteve French set_time = true; 155038c8a9a5SSteve French info_buf.LastAccessTime = 155138c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); 155238c8a9a5SSteve French } else 155338c8a9a5SSteve French info_buf.LastAccessTime = 0; 155438c8a9a5SSteve French 155538c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) { 155638c8a9a5SSteve French set_time = true; 155738c8a9a5SSteve French info_buf.LastWriteTime = 155838c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); 155938c8a9a5SSteve French } else 156038c8a9a5SSteve French info_buf.LastWriteTime = 0; 156138c8a9a5SSteve French 156238c8a9a5SSteve French /* 156338c8a9a5SSteve French * Samba throws this field away, but windows may actually use it. 156438c8a9a5SSteve French * Do not set ctime unless other time stamps are changed explicitly 156538c8a9a5SSteve French * (i.e. by utimes()) since we would then have a mix of client and 156638c8a9a5SSteve French * server times. 156738c8a9a5SSteve French */ 156838c8a9a5SSteve French if (set_time && (attrs->ia_valid & ATTR_CTIME)) { 156938c8a9a5SSteve French cifs_dbg(FYI, "CIFS - CTIME changed\n"); 157038c8a9a5SSteve French info_buf.ChangeTime = 157138c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); 157238c8a9a5SSteve French } else 157338c8a9a5SSteve French info_buf.ChangeTime = 0; 157438c8a9a5SSteve French 157538c8a9a5SSteve French info_buf.CreationTime = 0; /* don't change */ 157638c8a9a5SSteve French info_buf.Attributes = cpu_to_le32(dosattr); 157738c8a9a5SSteve French 157838c8a9a5SSteve French return server->ops->set_file_info(inode, full_path, &info_buf, xid); 157938c8a9a5SSteve French } 158038c8a9a5SSteve French 158138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 158238c8a9a5SSteve French /* 158338c8a9a5SSteve French * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit 158438c8a9a5SSteve French * and rename it to a random name that hopefully won't conflict with 158538c8a9a5SSteve French * anything else. 158638c8a9a5SSteve French */ 158738c8a9a5SSteve French int 158838c8a9a5SSteve French cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, 158938c8a9a5SSteve French const unsigned int xid) 159038c8a9a5SSteve French { 159138c8a9a5SSteve French int oplock = 0; 159238c8a9a5SSteve French int rc; 159338c8a9a5SSteve French struct cifs_fid fid; 159438c8a9a5SSteve French struct cifs_open_parms oparms; 159538c8a9a5SSteve French struct inode *inode = d_inode(dentry); 159638c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 159738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 159838c8a9a5SSteve French struct tcon_link *tlink; 159938c8a9a5SSteve French struct cifs_tcon *tcon; 160038c8a9a5SSteve French __u32 dosattr, origattr; 160138c8a9a5SSteve French FILE_BASIC_INFO *info_buf = NULL; 160238c8a9a5SSteve French 160338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 160438c8a9a5SSteve French if (IS_ERR(tlink)) 160538c8a9a5SSteve French return PTR_ERR(tlink); 160638c8a9a5SSteve French tcon = tlink_tcon(tlink); 160738c8a9a5SSteve French 160838c8a9a5SSteve French /* 160938c8a9a5SSteve French * We cannot rename the file if the server doesn't support 161038c8a9a5SSteve French * CAP_INFOLEVEL_PASSTHRU 161138c8a9a5SSteve French */ 161238c8a9a5SSteve French if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) { 161338c8a9a5SSteve French rc = -EBUSY; 161438c8a9a5SSteve French goto out; 161538c8a9a5SSteve French } 161638c8a9a5SSteve French 161738c8a9a5SSteve French oparms = (struct cifs_open_parms) { 161838c8a9a5SSteve French .tcon = tcon, 161938c8a9a5SSteve French .cifs_sb = cifs_sb, 162038c8a9a5SSteve French .desired_access = DELETE | FILE_WRITE_ATTRIBUTES, 162138c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 162238c8a9a5SSteve French .disposition = FILE_OPEN, 162338c8a9a5SSteve French .path = full_path, 162438c8a9a5SSteve French .fid = &fid, 162538c8a9a5SSteve French }; 162638c8a9a5SSteve French 162738c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 162838c8a9a5SSteve French if (rc != 0) 162938c8a9a5SSteve French goto out; 163038c8a9a5SSteve French 163138c8a9a5SSteve French origattr = cifsInode->cifsAttrs; 163238c8a9a5SSteve French if (origattr == 0) 163338c8a9a5SSteve French origattr |= ATTR_NORMAL; 163438c8a9a5SSteve French 163538c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 163638c8a9a5SSteve French if (dosattr == 0) 163738c8a9a5SSteve French dosattr |= ATTR_NORMAL; 163838c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 163938c8a9a5SSteve French 164038c8a9a5SSteve French /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */ 164138c8a9a5SSteve French if (dosattr != origattr) { 164238c8a9a5SSteve French info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); 164338c8a9a5SSteve French if (info_buf == NULL) { 164438c8a9a5SSteve French rc = -ENOMEM; 164538c8a9a5SSteve French goto out_close; 164638c8a9a5SSteve French } 164738c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(dosattr); 164838c8a9a5SSteve French rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 164938c8a9a5SSteve French current->tgid); 165038c8a9a5SSteve French /* although we would like to mark the file hidden 165138c8a9a5SSteve French if that fails we will still try to rename it */ 165238c8a9a5SSteve French if (!rc) 165338c8a9a5SSteve French cifsInode->cifsAttrs = dosattr; 165438c8a9a5SSteve French else 165538c8a9a5SSteve French dosattr = origattr; /* since not able to change them */ 165638c8a9a5SSteve French } 165738c8a9a5SSteve French 165838c8a9a5SSteve French /* rename the file */ 165938c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, 166038c8a9a5SSteve French cifs_sb->local_nls, 166138c8a9a5SSteve French cifs_remap(cifs_sb)); 166238c8a9a5SSteve French if (rc != 0) { 166338c8a9a5SSteve French rc = -EBUSY; 166438c8a9a5SSteve French goto undo_setattr; 166538c8a9a5SSteve French } 166638c8a9a5SSteve French 166738c8a9a5SSteve French /* try to set DELETE_ON_CLOSE */ 166838c8a9a5SSteve French if (!test_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags)) { 166938c8a9a5SSteve French rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid, 167038c8a9a5SSteve French current->tgid); 167138c8a9a5SSteve French /* 167238c8a9a5SSteve French * some samba versions return -ENOENT when we try to set the 167338c8a9a5SSteve French * file disposition here. Likely a samba bug, but work around 167438c8a9a5SSteve French * it for now. This means that some cifsXXX files may hang 167538c8a9a5SSteve French * around after they shouldn't. 167638c8a9a5SSteve French * 167738c8a9a5SSteve French * BB: remove this hack after more servers have the fix 167838c8a9a5SSteve French */ 167938c8a9a5SSteve French if (rc == -ENOENT) 168038c8a9a5SSteve French rc = 0; 168138c8a9a5SSteve French else if (rc != 0) { 168238c8a9a5SSteve French rc = -EBUSY; 168338c8a9a5SSteve French goto undo_rename; 168438c8a9a5SSteve French } 168538c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags); 168638c8a9a5SSteve French } 168738c8a9a5SSteve French 168838c8a9a5SSteve French out_close: 168938c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 169038c8a9a5SSteve French out: 169138c8a9a5SSteve French kfree(info_buf); 169238c8a9a5SSteve French cifs_put_tlink(tlink); 169338c8a9a5SSteve French return rc; 169438c8a9a5SSteve French 169538c8a9a5SSteve French /* 169638c8a9a5SSteve French * reset everything back to the original state. Don't bother 169738c8a9a5SSteve French * dealing with errors here since we can't do anything about 169838c8a9a5SSteve French * them anyway. 169938c8a9a5SSteve French */ 170038c8a9a5SSteve French undo_rename: 170138c8a9a5SSteve French CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, 170238c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 170338c8a9a5SSteve French undo_setattr: 170438c8a9a5SSteve French if (dosattr != origattr) { 170538c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(origattr); 170638c8a9a5SSteve French if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 170738c8a9a5SSteve French current->tgid)) 170838c8a9a5SSteve French cifsInode->cifsAttrs = origattr; 170938c8a9a5SSteve French } 171038c8a9a5SSteve French 171138c8a9a5SSteve French goto out_close; 171238c8a9a5SSteve French } 171338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 171438c8a9a5SSteve French 171538c8a9a5SSteve French /* copied from fs/nfs/dir.c with small changes */ 171638c8a9a5SSteve French static void 171738c8a9a5SSteve French cifs_drop_nlink(struct inode *inode) 171838c8a9a5SSteve French { 171938c8a9a5SSteve French spin_lock(&inode->i_lock); 172038c8a9a5SSteve French if (inode->i_nlink > 0) 172138c8a9a5SSteve French drop_nlink(inode); 172238c8a9a5SSteve French spin_unlock(&inode->i_lock); 172338c8a9a5SSteve French } 172438c8a9a5SSteve French 172538c8a9a5SSteve French /* 172638c8a9a5SSteve French * If d_inode(dentry) is null (usually meaning the cached dentry 172738c8a9a5SSteve French * is a negative dentry) then we would attempt a standard SMB delete, but 172838c8a9a5SSteve French * if that fails we can not attempt the fall back mechanisms on EACCES 172938c8a9a5SSteve French * but will return the EACCES to the caller. Note that the VFS does not call 173038c8a9a5SSteve French * unlink on negative dentries currently. 173138c8a9a5SSteve French */ 173238c8a9a5SSteve French int cifs_unlink(struct inode *dir, struct dentry *dentry) 173338c8a9a5SSteve French { 173438c8a9a5SSteve French int rc = 0; 173538c8a9a5SSteve French unsigned int xid; 173638c8a9a5SSteve French const char *full_path; 173738c8a9a5SSteve French void *page; 173838c8a9a5SSteve French struct inode *inode = d_inode(dentry); 173938c8a9a5SSteve French struct cifsInodeInfo *cifs_inode; 174038c8a9a5SSteve French struct super_block *sb = dir->i_sb; 174138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 174238c8a9a5SSteve French struct tcon_link *tlink; 174338c8a9a5SSteve French struct cifs_tcon *tcon; 174438c8a9a5SSteve French struct TCP_Server_Info *server; 174538c8a9a5SSteve French struct iattr *attrs = NULL; 174638c8a9a5SSteve French __u32 dosattr = 0, origattr = 0; 174738c8a9a5SSteve French 174838c8a9a5SSteve French cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); 174938c8a9a5SSteve French 175038c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 175138c8a9a5SSteve French return -EIO; 175238c8a9a5SSteve French 175338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 175438c8a9a5SSteve French if (IS_ERR(tlink)) 175538c8a9a5SSteve French return PTR_ERR(tlink); 175638c8a9a5SSteve French tcon = tlink_tcon(tlink); 175738c8a9a5SSteve French server = tcon->ses->server; 175838c8a9a5SSteve French 175938c8a9a5SSteve French xid = get_xid(); 176038c8a9a5SSteve French page = alloc_dentry_path(); 176138c8a9a5SSteve French 176238c8a9a5SSteve French if (tcon->nodelete) { 176338c8a9a5SSteve French rc = -EACCES; 176438c8a9a5SSteve French goto unlink_out; 176538c8a9a5SSteve French } 176638c8a9a5SSteve French 176738c8a9a5SSteve French /* Unlink can be called from rename so we can not take the 176838c8a9a5SSteve French * sb->s_vfs_rename_mutex here */ 176938c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 177038c8a9a5SSteve French if (IS_ERR(full_path)) { 177138c8a9a5SSteve French rc = PTR_ERR(full_path); 177238c8a9a5SSteve French goto unlink_out; 177338c8a9a5SSteve French } 177438c8a9a5SSteve French 177538c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, full_path); 177638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 177738c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 177838c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 177938c8a9a5SSteve French rc = CIFSPOSIXDelFile(xid, tcon, full_path, 178038c8a9a5SSteve French SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 178138c8a9a5SSteve French cifs_remap(cifs_sb)); 178238c8a9a5SSteve French cifs_dbg(FYI, "posix del rc %d\n", rc); 178338c8a9a5SSteve French if ((rc == 0) || (rc == -ENOENT)) 178438c8a9a5SSteve French goto psx_del_no_retry; 178538c8a9a5SSteve French } 178638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 178738c8a9a5SSteve French 178838c8a9a5SSteve French retry_std_delete: 178938c8a9a5SSteve French if (!server->ops->unlink) { 179038c8a9a5SSteve French rc = -ENOSYS; 179138c8a9a5SSteve French goto psx_del_no_retry; 179238c8a9a5SSteve French } 179338c8a9a5SSteve French 1794f93d145fSMeetakshi Setiya rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry); 179538c8a9a5SSteve French 179638c8a9a5SSteve French psx_del_no_retry: 179738c8a9a5SSteve French if (!rc) { 1798b6e27f7fSSteve French if (inode) { 1799b6e27f7fSSteve French cifs_mark_open_handles_for_deleted_file(inode, full_path); 180038c8a9a5SSteve French cifs_drop_nlink(inode); 1801b6e27f7fSSteve French } 180238c8a9a5SSteve French } else if (rc == -ENOENT) { 180338c8a9a5SSteve French d_drop(dentry); 180438c8a9a5SSteve French } else if (rc == -EBUSY) { 180538c8a9a5SSteve French if (server->ops->rename_pending_delete) { 180638c8a9a5SSteve French rc = server->ops->rename_pending_delete(full_path, 180738c8a9a5SSteve French dentry, xid); 1808b6e27f7fSSteve French if (rc == 0) { 1809b6e27f7fSSteve French cifs_mark_open_handles_for_deleted_file(inode, full_path); 181038c8a9a5SSteve French cifs_drop_nlink(inode); 181138c8a9a5SSteve French } 1812b6e27f7fSSteve French } 181338c8a9a5SSteve French } else if ((rc == -EACCES) && (dosattr == 0) && inode) { 181438c8a9a5SSteve French attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 181538c8a9a5SSteve French if (attrs == NULL) { 181638c8a9a5SSteve French rc = -ENOMEM; 181738c8a9a5SSteve French goto out_reval; 181838c8a9a5SSteve French } 181938c8a9a5SSteve French 182038c8a9a5SSteve French /* try to reset dos attributes */ 182138c8a9a5SSteve French cifs_inode = CIFS_I(inode); 182238c8a9a5SSteve French origattr = cifs_inode->cifsAttrs; 182338c8a9a5SSteve French if (origattr == 0) 182438c8a9a5SSteve French origattr |= ATTR_NORMAL; 182538c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 182638c8a9a5SSteve French if (dosattr == 0) 182738c8a9a5SSteve French dosattr |= ATTR_NORMAL; 182838c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 182938c8a9a5SSteve French 183038c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 183138c8a9a5SSteve French if (rc != 0) 183238c8a9a5SSteve French goto out_reval; 183338c8a9a5SSteve French 183438c8a9a5SSteve French goto retry_std_delete; 183538c8a9a5SSteve French } 183638c8a9a5SSteve French 183738c8a9a5SSteve French /* undo the setattr if we errored out and it's needed */ 183838c8a9a5SSteve French if (rc != 0 && dosattr != 0) 183938c8a9a5SSteve French cifs_set_file_info(inode, attrs, xid, full_path, origattr); 184038c8a9a5SSteve French 184138c8a9a5SSteve French out_reval: 184238c8a9a5SSteve French if (inode) { 184338c8a9a5SSteve French cifs_inode = CIFS_I(inode); 184438c8a9a5SSteve French cifs_inode->time = 0; /* will force revalidate to get info 184538c8a9a5SSteve French when needed */ 184694487653SJeff Layton inode_set_ctime_current(inode); 184738c8a9a5SSteve French } 184823171df5SJeff Layton inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); 184938c8a9a5SSteve French cifs_inode = CIFS_I(dir); 185038c8a9a5SSteve French CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ 185138c8a9a5SSteve French unlink_out: 185238c8a9a5SSteve French free_dentry_path(page); 185338c8a9a5SSteve French kfree(attrs); 185438c8a9a5SSteve French free_xid(xid); 185538c8a9a5SSteve French cifs_put_tlink(tlink); 185638c8a9a5SSteve French return rc; 185738c8a9a5SSteve French } 185838c8a9a5SSteve French 185938c8a9a5SSteve French static int 186038c8a9a5SSteve French cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, 186138c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 186238c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 186338c8a9a5SSteve French { 186438c8a9a5SSteve French int rc = 0; 186538c8a9a5SSteve French struct inode *inode = NULL; 186638c8a9a5SSteve French 186702bcf865SSteve French if (tcon->posix_extensions) { 186802bcf865SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, 186902bcf865SSteve French NULL, parent->i_sb, xid); 187038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 187102bcf865SSteve French } else if (tcon->unix_ext) { 187238c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, 187338c8a9a5SSteve French xid); 187438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 187502bcf865SSteve French } else { 187638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb, 187738c8a9a5SSteve French xid, NULL); 187802bcf865SSteve French } 187938c8a9a5SSteve French 188038c8a9a5SSteve French if (rc) 188138c8a9a5SSteve French return rc; 188238c8a9a5SSteve French 188338c8a9a5SSteve French if (!S_ISDIR(inode->i_mode)) { 188438c8a9a5SSteve French /* 188538c8a9a5SSteve French * mkdir succeeded, but another client has managed to remove the 188638c8a9a5SSteve French * sucker and replace it with non-directory. Return success, 188738c8a9a5SSteve French * but don't leave the child in dcache. 188838c8a9a5SSteve French */ 188938c8a9a5SSteve French iput(inode); 189038c8a9a5SSteve French d_drop(dentry); 189138c8a9a5SSteve French return 0; 189238c8a9a5SSteve French } 189338c8a9a5SSteve French /* 189438c8a9a5SSteve French * setting nlink not necessary except in cases where we failed to get it 189538c8a9a5SSteve French * from the server or was set bogus. Also, since this is a brand new 189638c8a9a5SSteve French * inode, no need to grab the i_lock before setting the i_nlink. 189738c8a9a5SSteve French */ 189838c8a9a5SSteve French if (inode->i_nlink < 2) 189938c8a9a5SSteve French set_nlink(inode, 2); 190038c8a9a5SSteve French mode &= ~current_umask(); 190138c8a9a5SSteve French /* must turn on setgid bit if parent dir has it */ 190238c8a9a5SSteve French if (parent->i_mode & S_ISGID) 190338c8a9a5SSteve French mode |= S_ISGID; 190438c8a9a5SSteve French 190538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 190638c8a9a5SSteve French if (tcon->unix_ext) { 190738c8a9a5SSteve French struct cifs_unix_set_info_args args = { 190838c8a9a5SSteve French .mode = mode, 190938c8a9a5SSteve French .ctime = NO_CHANGE_64, 191038c8a9a5SSteve French .atime = NO_CHANGE_64, 191138c8a9a5SSteve French .mtime = NO_CHANGE_64, 191238c8a9a5SSteve French .device = 0, 191338c8a9a5SSteve French }; 191438c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 191538c8a9a5SSteve French args.uid = current_fsuid(); 191638c8a9a5SSteve French if (parent->i_mode & S_ISGID) 191738c8a9a5SSteve French args.gid = parent->i_gid; 191838c8a9a5SSteve French else 191938c8a9a5SSteve French args.gid = current_fsgid(); 192038c8a9a5SSteve French } else { 192138c8a9a5SSteve French args.uid = INVALID_UID; /* no change */ 192238c8a9a5SSteve French args.gid = INVALID_GID; /* no change */ 192338c8a9a5SSteve French } 192438c8a9a5SSteve French CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, 192538c8a9a5SSteve French cifs_sb->local_nls, 192638c8a9a5SSteve French cifs_remap(cifs_sb)); 192738c8a9a5SSteve French } else { 192838c8a9a5SSteve French #else 192938c8a9a5SSteve French { 193038c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 193138c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 193238c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 193338c8a9a5SSteve French (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) 193438c8a9a5SSteve French server->ops->mkdir_setinfo(inode, full_path, cifs_sb, 193538c8a9a5SSteve French tcon, xid); 193638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 193738c8a9a5SSteve French inode->i_mode = (mode | S_IFDIR); 193838c8a9a5SSteve French 193938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 194038c8a9a5SSteve French inode->i_uid = current_fsuid(); 194138c8a9a5SSteve French if (inode->i_mode & S_ISGID) 194238c8a9a5SSteve French inode->i_gid = parent->i_gid; 194338c8a9a5SSteve French else 194438c8a9a5SSteve French inode->i_gid = current_fsgid(); 194538c8a9a5SSteve French } 194638c8a9a5SSteve French } 194738c8a9a5SSteve French d_instantiate(dentry, inode); 194838c8a9a5SSteve French return 0; 194938c8a9a5SSteve French } 195038c8a9a5SSteve French 195138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 195238c8a9a5SSteve French static int 195338c8a9a5SSteve French cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, 195438c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 195538c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 195638c8a9a5SSteve French { 195738c8a9a5SSteve French int rc = 0; 195838c8a9a5SSteve French u32 oplock = 0; 195938c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info = NULL; 196038c8a9a5SSteve French struct inode *newinode = NULL; 196138c8a9a5SSteve French struct cifs_fattr fattr; 196238c8a9a5SSteve French 196338c8a9a5SSteve French info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 196438c8a9a5SSteve French if (info == NULL) { 196538c8a9a5SSteve French rc = -ENOMEM; 196638c8a9a5SSteve French goto posix_mkdir_out; 196738c8a9a5SSteve French } 196838c8a9a5SSteve French 196938c8a9a5SSteve French mode &= ~current_umask(); 197038c8a9a5SSteve French rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, 197138c8a9a5SSteve French NULL /* netfid */, info, &oplock, full_path, 197238c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 197338c8a9a5SSteve French if (rc == -EOPNOTSUPP) 197438c8a9a5SSteve French goto posix_mkdir_out; 197538c8a9a5SSteve French else if (rc) { 197638c8a9a5SSteve French cifs_dbg(FYI, "posix mkdir returned 0x%x\n", rc); 197738c8a9a5SSteve French d_drop(dentry); 197838c8a9a5SSteve French goto posix_mkdir_out; 197938c8a9a5SSteve French } 198038c8a9a5SSteve French 198138c8a9a5SSteve French if (info->Type == cpu_to_le32(-1)) 198238c8a9a5SSteve French /* no return info, go query for it */ 198338c8a9a5SSteve French goto posix_mkdir_get_info; 198438c8a9a5SSteve French /* 198538c8a9a5SSteve French * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if 198638c8a9a5SSteve French * need to set uid/gid. 198738c8a9a5SSteve French */ 198838c8a9a5SSteve French 198938c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); 199038c8a9a5SSteve French cifs_fill_uniqueid(inode->i_sb, &fattr); 199138c8a9a5SSteve French newinode = cifs_iget(inode->i_sb, &fattr); 199238c8a9a5SSteve French if (!newinode) 199338c8a9a5SSteve French goto posix_mkdir_get_info; 199438c8a9a5SSteve French 199538c8a9a5SSteve French d_instantiate(dentry, newinode); 199638c8a9a5SSteve French 199738c8a9a5SSteve French #ifdef CONFIG_CIFS_DEBUG2 199838c8a9a5SSteve French cifs_dbg(FYI, "instantiated dentry %p %pd to inode %p\n", 199938c8a9a5SSteve French dentry, dentry, newinode); 200038c8a9a5SSteve French 200138c8a9a5SSteve French if (newinode->i_nlink != 2) 200238c8a9a5SSteve French cifs_dbg(FYI, "unexpected number of links %d\n", 200338c8a9a5SSteve French newinode->i_nlink); 200438c8a9a5SSteve French #endif 200538c8a9a5SSteve French 200638c8a9a5SSteve French posix_mkdir_out: 200738c8a9a5SSteve French kfree(info); 200838c8a9a5SSteve French return rc; 200938c8a9a5SSteve French posix_mkdir_get_info: 201038c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, 201138c8a9a5SSteve French xid); 201238c8a9a5SSteve French goto posix_mkdir_out; 201338c8a9a5SSteve French } 201438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 201538c8a9a5SSteve French 201638c8a9a5SSteve French int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, 201738c8a9a5SSteve French struct dentry *direntry, umode_t mode) 201838c8a9a5SSteve French { 201938c8a9a5SSteve French int rc = 0; 202038c8a9a5SSteve French unsigned int xid; 202138c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 202238c8a9a5SSteve French struct tcon_link *tlink; 202338c8a9a5SSteve French struct cifs_tcon *tcon; 202438c8a9a5SSteve French struct TCP_Server_Info *server; 202538c8a9a5SSteve French const char *full_path; 202638c8a9a5SSteve French void *page; 202738c8a9a5SSteve French 202838c8a9a5SSteve French cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n", 202938c8a9a5SSteve French mode, inode); 203038c8a9a5SSteve French 203138c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 203238c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 203338c8a9a5SSteve French return -EIO; 203438c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 203538c8a9a5SSteve French if (IS_ERR(tlink)) 203638c8a9a5SSteve French return PTR_ERR(tlink); 203738c8a9a5SSteve French tcon = tlink_tcon(tlink); 203838c8a9a5SSteve French 203938c8a9a5SSteve French xid = get_xid(); 204038c8a9a5SSteve French 204138c8a9a5SSteve French page = alloc_dentry_path(); 204238c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 204338c8a9a5SSteve French if (IS_ERR(full_path)) { 204438c8a9a5SSteve French rc = PTR_ERR(full_path); 204538c8a9a5SSteve French goto mkdir_out; 204638c8a9a5SSteve French } 204738c8a9a5SSteve French 204838c8a9a5SSteve French server = tcon->ses->server; 204938c8a9a5SSteve French 205038c8a9a5SSteve French if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { 205138c8a9a5SSteve French rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, 205238c8a9a5SSteve French cifs_sb); 205338c8a9a5SSteve French d_drop(direntry); /* for time being always refresh inode info */ 205438c8a9a5SSteve French goto mkdir_out; 205538c8a9a5SSteve French } 205638c8a9a5SSteve French 205738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 205838c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 205938c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 206038c8a9a5SSteve French rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, 206138c8a9a5SSteve French tcon, xid); 206238c8a9a5SSteve French if (rc != -EOPNOTSUPP) 206338c8a9a5SSteve French goto mkdir_out; 206438c8a9a5SSteve French } 206538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 206638c8a9a5SSteve French 206738c8a9a5SSteve French if (!server->ops->mkdir) { 206838c8a9a5SSteve French rc = -ENOSYS; 206938c8a9a5SSteve French goto mkdir_out; 207038c8a9a5SSteve French } 207138c8a9a5SSteve French 207238c8a9a5SSteve French /* BB add setting the equivalent of mode via CreateX w/ACLs */ 207338c8a9a5SSteve French rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb); 207438c8a9a5SSteve French if (rc) { 207538c8a9a5SSteve French cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc); 207638c8a9a5SSteve French d_drop(direntry); 207738c8a9a5SSteve French goto mkdir_out; 207838c8a9a5SSteve French } 207938c8a9a5SSteve French 208038c8a9a5SSteve French /* TODO: skip this for smb2/smb3 */ 208138c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, 208238c8a9a5SSteve French xid); 208338c8a9a5SSteve French mkdir_out: 208438c8a9a5SSteve French /* 208538c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 208638c8a9a5SSteve French * attributes are invalid now. 208738c8a9a5SSteve French */ 208838c8a9a5SSteve French CIFS_I(inode)->time = 0; 208938c8a9a5SSteve French free_dentry_path(page); 209038c8a9a5SSteve French free_xid(xid); 209138c8a9a5SSteve French cifs_put_tlink(tlink); 209238c8a9a5SSteve French return rc; 209338c8a9a5SSteve French } 209438c8a9a5SSteve French 209538c8a9a5SSteve French int cifs_rmdir(struct inode *inode, struct dentry *direntry) 209638c8a9a5SSteve French { 209738c8a9a5SSteve French int rc = 0; 209838c8a9a5SSteve French unsigned int xid; 209938c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 210038c8a9a5SSteve French struct tcon_link *tlink; 210138c8a9a5SSteve French struct cifs_tcon *tcon; 210238c8a9a5SSteve French struct TCP_Server_Info *server; 210338c8a9a5SSteve French const char *full_path; 210438c8a9a5SSteve French void *page = alloc_dentry_path(); 210538c8a9a5SSteve French struct cifsInodeInfo *cifsInode; 210638c8a9a5SSteve French 210738c8a9a5SSteve French cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode); 210838c8a9a5SSteve French 210938c8a9a5SSteve French xid = get_xid(); 211038c8a9a5SSteve French 211138c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 211238c8a9a5SSteve French if (IS_ERR(full_path)) { 211338c8a9a5SSteve French rc = PTR_ERR(full_path); 211438c8a9a5SSteve French goto rmdir_exit; 211538c8a9a5SSteve French } 211638c8a9a5SSteve French 211738c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 211838c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) { 211938c8a9a5SSteve French rc = -EIO; 212038c8a9a5SSteve French goto rmdir_exit; 212138c8a9a5SSteve French } 212238c8a9a5SSteve French 212338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 212438c8a9a5SSteve French if (IS_ERR(tlink)) { 212538c8a9a5SSteve French rc = PTR_ERR(tlink); 212638c8a9a5SSteve French goto rmdir_exit; 212738c8a9a5SSteve French } 212838c8a9a5SSteve French tcon = tlink_tcon(tlink); 212938c8a9a5SSteve French server = tcon->ses->server; 213038c8a9a5SSteve French 213138c8a9a5SSteve French if (!server->ops->rmdir) { 213238c8a9a5SSteve French rc = -ENOSYS; 213338c8a9a5SSteve French cifs_put_tlink(tlink); 213438c8a9a5SSteve French goto rmdir_exit; 213538c8a9a5SSteve French } 213638c8a9a5SSteve French 213738c8a9a5SSteve French if (tcon->nodelete) { 213838c8a9a5SSteve French rc = -EACCES; 213938c8a9a5SSteve French cifs_put_tlink(tlink); 214038c8a9a5SSteve French goto rmdir_exit; 214138c8a9a5SSteve French } 214238c8a9a5SSteve French 214338c8a9a5SSteve French rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); 214438c8a9a5SSteve French cifs_put_tlink(tlink); 214538c8a9a5SSteve French 214638c8a9a5SSteve French if (!rc) { 214738c8a9a5SSteve French spin_lock(&d_inode(direntry)->i_lock); 214838c8a9a5SSteve French i_size_write(d_inode(direntry), 0); 214938c8a9a5SSteve French clear_nlink(d_inode(direntry)); 215038c8a9a5SSteve French spin_unlock(&d_inode(direntry)->i_lock); 215138c8a9a5SSteve French } 215238c8a9a5SSteve French 215338c8a9a5SSteve French cifsInode = CIFS_I(d_inode(direntry)); 215438c8a9a5SSteve French /* force revalidate to go get info when needed */ 215538c8a9a5SSteve French cifsInode->time = 0; 215638c8a9a5SSteve French 215738c8a9a5SSteve French cifsInode = CIFS_I(inode); 215838c8a9a5SSteve French /* 215938c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 216038c8a9a5SSteve French * attributes are invalid now. 216138c8a9a5SSteve French */ 216238c8a9a5SSteve French cifsInode->time = 0; 216338c8a9a5SSteve French 216494487653SJeff Layton inode_set_ctime_current(d_inode(direntry)); 216523171df5SJeff Layton inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); 216638c8a9a5SSteve French 216738c8a9a5SSteve French rmdir_exit: 216838c8a9a5SSteve French free_dentry_path(page); 216938c8a9a5SSteve French free_xid(xid); 217038c8a9a5SSteve French return rc; 217138c8a9a5SSteve French } 217238c8a9a5SSteve French 217338c8a9a5SSteve French static int 217438c8a9a5SSteve French cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, 217538c8a9a5SSteve French const char *from_path, struct dentry *to_dentry, 217638c8a9a5SSteve French const char *to_path) 217738c8a9a5SSteve French { 217838c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); 217938c8a9a5SSteve French struct tcon_link *tlink; 218038c8a9a5SSteve French struct cifs_tcon *tcon; 218138c8a9a5SSteve French struct TCP_Server_Info *server; 218238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 218338c8a9a5SSteve French struct cifs_fid fid; 218438c8a9a5SSteve French struct cifs_open_parms oparms; 218538c8a9a5SSteve French int oplock; 218638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 218738c8a9a5SSteve French int rc; 218838c8a9a5SSteve French 218938c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 219038c8a9a5SSteve French if (IS_ERR(tlink)) 219138c8a9a5SSteve French return PTR_ERR(tlink); 219238c8a9a5SSteve French tcon = tlink_tcon(tlink); 219338c8a9a5SSteve French server = tcon->ses->server; 219438c8a9a5SSteve French 219538c8a9a5SSteve French if (!server->ops->rename) 219638c8a9a5SSteve French return -ENOSYS; 219738c8a9a5SSteve French 219838c8a9a5SSteve French /* try path-based rename first */ 2199c586b0c7SPaulo Alcantara rc = server->ops->rename(xid, tcon, from_dentry, 2200c586b0c7SPaulo Alcantara from_path, to_path, cifs_sb); 220138c8a9a5SSteve French 220238c8a9a5SSteve French /* 220338c8a9a5SSteve French * Don't bother with rename by filehandle unless file is busy and 220438c8a9a5SSteve French * source. Note that cross directory moves do not work with 220538c8a9a5SSteve French * rename by filehandle to various Windows servers. 220638c8a9a5SSteve French */ 220738c8a9a5SSteve French if (rc == 0 || rc != -EBUSY) 220838c8a9a5SSteve French goto do_rename_exit; 220938c8a9a5SSteve French 221038c8a9a5SSteve French /* Don't fall back to using SMB on SMB 2+ mount */ 221138c8a9a5SSteve French if (server->vals->protocol_id != 0) 221238c8a9a5SSteve French goto do_rename_exit; 221338c8a9a5SSteve French 221438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 221538c8a9a5SSteve French /* open-file renames don't work across directories */ 221638c8a9a5SSteve French if (to_dentry->d_parent != from_dentry->d_parent) 221738c8a9a5SSteve French goto do_rename_exit; 221838c8a9a5SSteve French 221938c8a9a5SSteve French oparms = (struct cifs_open_parms) { 222038c8a9a5SSteve French .tcon = tcon, 222138c8a9a5SSteve French .cifs_sb = cifs_sb, 222238c8a9a5SSteve French /* open the file to be renamed -- we need DELETE perms */ 222338c8a9a5SSteve French .desired_access = DELETE, 222438c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 222538c8a9a5SSteve French .disposition = FILE_OPEN, 222638c8a9a5SSteve French .path = from_path, 222738c8a9a5SSteve French .fid = &fid, 222838c8a9a5SSteve French }; 222938c8a9a5SSteve French 223038c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 223138c8a9a5SSteve French if (rc == 0) { 223238c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, 223338c8a9a5SSteve French (const char *) to_dentry->d_name.name, 223438c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 223538c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 223638c8a9a5SSteve French } 223738c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 223838c8a9a5SSteve French do_rename_exit: 223938c8a9a5SSteve French if (rc == 0) 224038c8a9a5SSteve French d_move(from_dentry, to_dentry); 224138c8a9a5SSteve French cifs_put_tlink(tlink); 224238c8a9a5SSteve French return rc; 224338c8a9a5SSteve French } 224438c8a9a5SSteve French 224538c8a9a5SSteve French int 224638c8a9a5SSteve French cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, 224738c8a9a5SSteve French struct dentry *source_dentry, struct inode *target_dir, 224838c8a9a5SSteve French struct dentry *target_dentry, unsigned int flags) 224938c8a9a5SSteve French { 225038c8a9a5SSteve French const char *from_name, *to_name; 225138c8a9a5SSteve French void *page1, *page2; 225238c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 225338c8a9a5SSteve French struct tcon_link *tlink; 225438c8a9a5SSteve French struct cifs_tcon *tcon; 225538c8a9a5SSteve French unsigned int xid; 225638c8a9a5SSteve French int rc, tmprc; 225738c8a9a5SSteve French int retry_count = 0; 225838c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_source = NULL; 225938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 226038c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_target; 226138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 226238c8a9a5SSteve French 226338c8a9a5SSteve French if (flags & ~RENAME_NOREPLACE) 226438c8a9a5SSteve French return -EINVAL; 226538c8a9a5SSteve French 226638c8a9a5SSteve French cifs_sb = CIFS_SB(source_dir->i_sb); 226738c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 226838c8a9a5SSteve French return -EIO; 226938c8a9a5SSteve French 227038c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 227138c8a9a5SSteve French if (IS_ERR(tlink)) 227238c8a9a5SSteve French return PTR_ERR(tlink); 227338c8a9a5SSteve French tcon = tlink_tcon(tlink); 227438c8a9a5SSteve French 227538c8a9a5SSteve French page1 = alloc_dentry_path(); 227638c8a9a5SSteve French page2 = alloc_dentry_path(); 227738c8a9a5SSteve French xid = get_xid(); 227838c8a9a5SSteve French 227938c8a9a5SSteve French from_name = build_path_from_dentry(source_dentry, page1); 228038c8a9a5SSteve French if (IS_ERR(from_name)) { 228138c8a9a5SSteve French rc = PTR_ERR(from_name); 228238c8a9a5SSteve French goto cifs_rename_exit; 228338c8a9a5SSteve French } 228438c8a9a5SSteve French 228538c8a9a5SSteve French to_name = build_path_from_dentry(target_dentry, page2); 228638c8a9a5SSteve French if (IS_ERR(to_name)) { 228738c8a9a5SSteve French rc = PTR_ERR(to_name); 228838c8a9a5SSteve French goto cifs_rename_exit; 228938c8a9a5SSteve French } 229038c8a9a5SSteve French 229138c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, from_name); 229238c8a9a5SSteve French if (d_inode(target_dentry) != NULL) 229338c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, to_name); 229438c8a9a5SSteve French 229538c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 229638c8a9a5SSteve French to_name); 229738c8a9a5SSteve French 229838c8a9a5SSteve French if (rc == -EACCES) { 229938c8a9a5SSteve French while (retry_count < 3) { 230038c8a9a5SSteve French cifs_close_all_deferred_files(tcon); 230138c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 230238c8a9a5SSteve French to_name); 230338c8a9a5SSteve French if (rc != -EACCES) 230438c8a9a5SSteve French break; 230538c8a9a5SSteve French retry_count++; 230638c8a9a5SSteve French } 230738c8a9a5SSteve French } 230838c8a9a5SSteve French 230938c8a9a5SSteve French /* 231038c8a9a5SSteve French * No-replace is the natural behavior for CIFS, so skip unlink hacks. 231138c8a9a5SSteve French */ 231238c8a9a5SSteve French if (flags & RENAME_NOREPLACE) 231338c8a9a5SSteve French goto cifs_rename_exit; 231438c8a9a5SSteve French 231538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 231638c8a9a5SSteve French if (rc == -EEXIST && tcon->unix_ext) { 231738c8a9a5SSteve French /* 231838c8a9a5SSteve French * Are src and dst hardlinks of same inode? We can only tell 231938c8a9a5SSteve French * with unix extensions enabled. 232038c8a9a5SSteve French */ 232138c8a9a5SSteve French info_buf_source = 232238c8a9a5SSteve French kmalloc_array(2, sizeof(FILE_UNIX_BASIC_INFO), 232338c8a9a5SSteve French GFP_KERNEL); 232438c8a9a5SSteve French if (info_buf_source == NULL) { 232538c8a9a5SSteve French rc = -ENOMEM; 232638c8a9a5SSteve French goto cifs_rename_exit; 232738c8a9a5SSteve French } 232838c8a9a5SSteve French 232938c8a9a5SSteve French info_buf_target = info_buf_source + 1; 233038c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name, 233138c8a9a5SSteve French info_buf_source, 233238c8a9a5SSteve French cifs_sb->local_nls, 233338c8a9a5SSteve French cifs_remap(cifs_sb)); 233438c8a9a5SSteve French if (tmprc != 0) 233538c8a9a5SSteve French goto unlink_target; 233638c8a9a5SSteve French 233738c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name, 233838c8a9a5SSteve French info_buf_target, 233938c8a9a5SSteve French cifs_sb->local_nls, 234038c8a9a5SSteve French cifs_remap(cifs_sb)); 234138c8a9a5SSteve French 234238c8a9a5SSteve French if (tmprc == 0 && (info_buf_source->UniqueId == 234338c8a9a5SSteve French info_buf_target->UniqueId)) { 234438c8a9a5SSteve French /* same file, POSIX says that this is a noop */ 234538c8a9a5SSteve French rc = 0; 234638c8a9a5SSteve French goto cifs_rename_exit; 234738c8a9a5SSteve French } 234838c8a9a5SSteve French } 234938c8a9a5SSteve French /* 235038c8a9a5SSteve French * else ... BB we could add the same check for Windows by 235138c8a9a5SSteve French * checking the UniqueId via FILE_INTERNAL_INFO 235238c8a9a5SSteve French */ 235338c8a9a5SSteve French 235438c8a9a5SSteve French unlink_target: 235538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 235638c8a9a5SSteve French 235738c8a9a5SSteve French /* Try unlinking the target dentry if it's not negative */ 235838c8a9a5SSteve French if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) { 235938c8a9a5SSteve French if (d_is_dir(target_dentry)) 236038c8a9a5SSteve French tmprc = cifs_rmdir(target_dir, target_dentry); 236138c8a9a5SSteve French else 236238c8a9a5SSteve French tmprc = cifs_unlink(target_dir, target_dentry); 236338c8a9a5SSteve French if (tmprc) 236438c8a9a5SSteve French goto cifs_rename_exit; 236538c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, 236638c8a9a5SSteve French target_dentry, to_name); 236738c8a9a5SSteve French } 236838c8a9a5SSteve French 236938c8a9a5SSteve French /* force revalidate to go get info when needed */ 237038c8a9a5SSteve French CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; 237138c8a9a5SSteve French 237238c8a9a5SSteve French cifs_rename_exit: 237338c8a9a5SSteve French kfree(info_buf_source); 237438c8a9a5SSteve French free_dentry_path(page2); 237538c8a9a5SSteve French free_dentry_path(page1); 237638c8a9a5SSteve French free_xid(xid); 237738c8a9a5SSteve French cifs_put_tlink(tlink); 237838c8a9a5SSteve French return rc; 237938c8a9a5SSteve French } 238038c8a9a5SSteve French 238138c8a9a5SSteve French static bool 238238c8a9a5SSteve French cifs_dentry_needs_reval(struct dentry *dentry) 238338c8a9a5SSteve French { 238438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 238538c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 238638c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 238738c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 238838c8a9a5SSteve French struct cached_fid *cfid = NULL; 238938c8a9a5SSteve French 239038c8a9a5SSteve French if (cifs_i->time == 0) 239138c8a9a5SSteve French return true; 239238c8a9a5SSteve French 239338c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) 239438c8a9a5SSteve French return false; 239538c8a9a5SSteve French 239638c8a9a5SSteve French if (!lookupCacheEnabled) 239738c8a9a5SSteve French return true; 239838c8a9a5SSteve French 239938c8a9a5SSteve French if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) { 240038c8a9a5SSteve French spin_lock(&cfid->fid_lock); 240138c8a9a5SSteve French if (cfid->time && cifs_i->time > cfid->time) { 240238c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 240338c8a9a5SSteve French close_cached_dir(cfid); 240438c8a9a5SSteve French return false; 240538c8a9a5SSteve French } 240638c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 240738c8a9a5SSteve French close_cached_dir(cfid); 240838c8a9a5SSteve French } 240938c8a9a5SSteve French /* 241038c8a9a5SSteve French * depending on inode type, check if attribute caching disabled for 241138c8a9a5SSteve French * files or directories 241238c8a9a5SSteve French */ 241338c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) { 241438c8a9a5SSteve French if (!cifs_sb->ctx->acdirmax) 241538c8a9a5SSteve French return true; 241638c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 241738c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acdirmax)) 241838c8a9a5SSteve French return true; 241938c8a9a5SSteve French } else { /* file */ 242038c8a9a5SSteve French if (!cifs_sb->ctx->acregmax) 242138c8a9a5SSteve French return true; 242238c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 242338c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acregmax)) 242438c8a9a5SSteve French return true; 242538c8a9a5SSteve French } 242638c8a9a5SSteve French 242738c8a9a5SSteve French /* hardlinked files w/ noserverino get "special" treatment */ 242838c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 242938c8a9a5SSteve French S_ISREG(inode->i_mode) && inode->i_nlink != 1) 243038c8a9a5SSteve French return true; 243138c8a9a5SSteve French 243238c8a9a5SSteve French return false; 243338c8a9a5SSteve French } 243438c8a9a5SSteve French 243538c8a9a5SSteve French /* 243638c8a9a5SSteve French * Zap the cache. Called when invalid_mapping flag is set. 243738c8a9a5SSteve French */ 243838c8a9a5SSteve French int 243938c8a9a5SSteve French cifs_invalidate_mapping(struct inode *inode) 244038c8a9a5SSteve French { 244138c8a9a5SSteve French int rc = 0; 244238c8a9a5SSteve French 244338c8a9a5SSteve French if (inode->i_mapping && inode->i_mapping->nrpages != 0) { 244438c8a9a5SSteve French rc = invalidate_inode_pages2(inode->i_mapping); 244538c8a9a5SSteve French if (rc) 2446acf35d79SSteve French cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", 2447acf35d79SSteve French __func__, inode, rc); 244838c8a9a5SSteve French } 244938c8a9a5SSteve French 245038c8a9a5SSteve French return rc; 245138c8a9a5SSteve French } 245238c8a9a5SSteve French 245338c8a9a5SSteve French /** 245438c8a9a5SSteve French * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks 245538c8a9a5SSteve French * 245638c8a9a5SSteve French * @key: currently unused 245738c8a9a5SSteve French * @mode: the task state to sleep in 245838c8a9a5SSteve French */ 245938c8a9a5SSteve French static int 246038c8a9a5SSteve French cifs_wait_bit_killable(struct wait_bit_key *key, int mode) 246138c8a9a5SSteve French { 246238c8a9a5SSteve French schedule(); 246338c8a9a5SSteve French if (signal_pending_state(mode, current)) 246438c8a9a5SSteve French return -ERESTARTSYS; 246538c8a9a5SSteve French return 0; 246638c8a9a5SSteve French } 246738c8a9a5SSteve French 246838c8a9a5SSteve French int 246938c8a9a5SSteve French cifs_revalidate_mapping(struct inode *inode) 247038c8a9a5SSteve French { 247138c8a9a5SSteve French int rc; 247238c8a9a5SSteve French unsigned long *flags = &CIFS_I(inode)->flags; 247338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 247438c8a9a5SSteve French 247538c8a9a5SSteve French /* swapfiles are not supposed to be shared */ 247638c8a9a5SSteve French if (IS_SWAPFILE(inode)) 247738c8a9a5SSteve French return 0; 247838c8a9a5SSteve French 247938c8a9a5SSteve French rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable, 248038c8a9a5SSteve French TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 248138c8a9a5SSteve French if (rc) 248238c8a9a5SSteve French return rc; 248338c8a9a5SSteve French 248438c8a9a5SSteve French if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) { 248538c8a9a5SSteve French /* for cache=singleclient, do not invalidate */ 248638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) 248738c8a9a5SSteve French goto skip_invalidate; 248838c8a9a5SSteve French 248938c8a9a5SSteve French rc = cifs_invalidate_mapping(inode); 249038c8a9a5SSteve French if (rc) 249138c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, flags); 249238c8a9a5SSteve French } 249338c8a9a5SSteve French 249438c8a9a5SSteve French skip_invalidate: 249538c8a9a5SSteve French clear_bit_unlock(CIFS_INO_LOCK, flags); 249638c8a9a5SSteve French smp_mb__after_atomic(); 249738c8a9a5SSteve French wake_up_bit(flags, CIFS_INO_LOCK); 249838c8a9a5SSteve French 249938c8a9a5SSteve French return rc; 250038c8a9a5SSteve French } 250138c8a9a5SSteve French 250238c8a9a5SSteve French int 250338c8a9a5SSteve French cifs_zap_mapping(struct inode *inode) 250438c8a9a5SSteve French { 250538c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags); 250638c8a9a5SSteve French return cifs_revalidate_mapping(inode); 250738c8a9a5SSteve French } 250838c8a9a5SSteve French 250938c8a9a5SSteve French int cifs_revalidate_file_attr(struct file *filp) 251038c8a9a5SSteve French { 251138c8a9a5SSteve French int rc = 0; 251238c8a9a5SSteve French struct dentry *dentry = file_dentry(filp); 251338c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 251438c8a9a5SSteve French struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; 251538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 251638c8a9a5SSteve French 251738c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 251838c8a9a5SSteve French return rc; 251938c8a9a5SSteve French 252038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 252138c8a9a5SSteve French if (tlink_tcon(cfile->tlink)->unix_ext) 252238c8a9a5SSteve French rc = cifs_get_file_info_unix(filp); 252338c8a9a5SSteve French else 252438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 252538c8a9a5SSteve French rc = cifs_get_file_info(filp); 252638c8a9a5SSteve French 252738c8a9a5SSteve French return rc; 252838c8a9a5SSteve French } 252938c8a9a5SSteve French 253038c8a9a5SSteve French int cifs_revalidate_dentry_attr(struct dentry *dentry) 253138c8a9a5SSteve French { 253238c8a9a5SSteve French unsigned int xid; 253338c8a9a5SSteve French int rc = 0; 253438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 253538c8a9a5SSteve French struct super_block *sb = dentry->d_sb; 253638c8a9a5SSteve French const char *full_path; 253738c8a9a5SSteve French void *page; 253838c8a9a5SSteve French int count = 0; 253938c8a9a5SSteve French 254038c8a9a5SSteve French if (inode == NULL) 254138c8a9a5SSteve French return -ENOENT; 254238c8a9a5SSteve French 254338c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 254438c8a9a5SSteve French return rc; 254538c8a9a5SSteve French 254638c8a9a5SSteve French xid = get_xid(); 254738c8a9a5SSteve French 254838c8a9a5SSteve French page = alloc_dentry_path(); 254938c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 255038c8a9a5SSteve French if (IS_ERR(full_path)) { 255138c8a9a5SSteve French rc = PTR_ERR(full_path); 255238c8a9a5SSteve French goto out; 255338c8a9a5SSteve French } 255438c8a9a5SSteve French 255538c8a9a5SSteve French cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n", 255638c8a9a5SSteve French full_path, inode, inode->i_count.counter, 255738c8a9a5SSteve French dentry, cifs_get_time(dentry), jiffies); 255838c8a9a5SSteve French 255938c8a9a5SSteve French again: 256002bcf865SSteve French if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) { 256102bcf865SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, 256202bcf865SSteve French NULL, sb, xid); 256302bcf865SSteve French } else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) { 256438c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); 256502bcf865SSteve French } else { 256638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, sb, 256738c8a9a5SSteve French xid, NULL); 256802bcf865SSteve French } 256938c8a9a5SSteve French if (rc == -EAGAIN && count++ < 10) 257038c8a9a5SSteve French goto again; 257138c8a9a5SSteve French out: 257238c8a9a5SSteve French free_dentry_path(page); 257338c8a9a5SSteve French free_xid(xid); 257438c8a9a5SSteve French 257538c8a9a5SSteve French return rc; 257638c8a9a5SSteve French } 257738c8a9a5SSteve French 257838c8a9a5SSteve French int cifs_revalidate_file(struct file *filp) 257938c8a9a5SSteve French { 258038c8a9a5SSteve French int rc; 258138c8a9a5SSteve French struct inode *inode = file_inode(filp); 258238c8a9a5SSteve French 258338c8a9a5SSteve French rc = cifs_revalidate_file_attr(filp); 258438c8a9a5SSteve French if (rc) 258538c8a9a5SSteve French return rc; 258638c8a9a5SSteve French 258738c8a9a5SSteve French return cifs_revalidate_mapping(inode); 258838c8a9a5SSteve French } 258938c8a9a5SSteve French 259038c8a9a5SSteve French /* revalidate a dentry's inode attributes */ 259138c8a9a5SSteve French int cifs_revalidate_dentry(struct dentry *dentry) 259238c8a9a5SSteve French { 259338c8a9a5SSteve French int rc; 259438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 259538c8a9a5SSteve French 259638c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 259738c8a9a5SSteve French if (rc) 259838c8a9a5SSteve French return rc; 259938c8a9a5SSteve French 260038c8a9a5SSteve French return cifs_revalidate_mapping(inode); 260138c8a9a5SSteve French } 260238c8a9a5SSteve French 260338c8a9a5SSteve French int cifs_getattr(struct mnt_idmap *idmap, const struct path *path, 260438c8a9a5SSteve French struct kstat *stat, u32 request_mask, unsigned int flags) 260538c8a9a5SSteve French { 260638c8a9a5SSteve French struct dentry *dentry = path->dentry; 260738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); 260838c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 260938c8a9a5SSteve French struct inode *inode = d_inode(dentry); 261038c8a9a5SSteve French int rc; 261138c8a9a5SSteve French 261238c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) 261338c8a9a5SSteve French return -EIO; 261438c8a9a5SSteve French 261538c8a9a5SSteve French /* 261638c8a9a5SSteve French * We need to be sure that all dirty pages are written and the server 261738c8a9a5SSteve French * has actual ctime, mtime and file length. 261838c8a9a5SSteve French */ 261938c8a9a5SSteve French if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) && 262038c8a9a5SSteve French !CIFS_CACHE_READ(CIFS_I(inode)) && 262138c8a9a5SSteve French inode->i_mapping && inode->i_mapping->nrpages != 0) { 262238c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 262338c8a9a5SSteve French if (rc) { 262438c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 262538c8a9a5SSteve French return rc; 262638c8a9a5SSteve French } 262738c8a9a5SSteve French } 262838c8a9a5SSteve French 262938c8a9a5SSteve French if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC) 263038c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force revalidate */ 263138c8a9a5SSteve French 263238c8a9a5SSteve French /* 263338c8a9a5SSteve French * If the caller doesn't require syncing, only sync if 263438c8a9a5SSteve French * necessary (e.g. due to earlier truncate or setattr 263538c8a9a5SSteve French * invalidating the cached metadata) 263638c8a9a5SSteve French */ 263738c8a9a5SSteve French if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) || 263838c8a9a5SSteve French (CIFS_I(inode)->time == 0)) { 263938c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 264038c8a9a5SSteve French if (rc) 264138c8a9a5SSteve French return rc; 264238c8a9a5SSteve French } 264338c8a9a5SSteve French 26440d72b928SJeff Layton generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 264538c8a9a5SSteve French stat->blksize = cifs_sb->ctx->bsize; 264638c8a9a5SSteve French stat->ino = CIFS_I(inode)->uniqueid; 264738c8a9a5SSteve French 264838c8a9a5SSteve French /* old CIFS Unix Extensions doesn't return create time */ 264938c8a9a5SSteve French if (CIFS_I(inode)->createtime) { 265038c8a9a5SSteve French stat->result_mask |= STATX_BTIME; 265138c8a9a5SSteve French stat->btime = 265238c8a9a5SSteve French cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); 265338c8a9a5SSteve French } 265438c8a9a5SSteve French 265538c8a9a5SSteve French stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED); 265638c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) 265738c8a9a5SSteve French stat->attributes |= STATX_ATTR_COMPRESSED; 265838c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED) 265938c8a9a5SSteve French stat->attributes |= STATX_ATTR_ENCRYPTED; 266038c8a9a5SSteve French 266138c8a9a5SSteve French /* 266238c8a9a5SSteve French * If on a multiuser mount without unix extensions or cifsacl being 266338c8a9a5SSteve French * enabled, and the admin hasn't overridden them, set the ownership 266438c8a9a5SSteve French * to the fsuid/fsgid of the current process. 266538c8a9a5SSteve French */ 266638c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && 266738c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 266838c8a9a5SSteve French !tcon->unix_ext) { 266938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) 267038c8a9a5SSteve French stat->uid = current_fsuid(); 267138c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) 267238c8a9a5SSteve French stat->gid = current_fsgid(); 267338c8a9a5SSteve French } 267438c8a9a5SSteve French return 0; 267538c8a9a5SSteve French } 267638c8a9a5SSteve French 267738c8a9a5SSteve French int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, 267838c8a9a5SSteve French u64 len) 267938c8a9a5SSteve French { 268038c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 268138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->netfs.inode.i_sb); 268238c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 268338c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 268438c8a9a5SSteve French struct cifsFileInfo *cfile; 268538c8a9a5SSteve French int rc; 268638c8a9a5SSteve French 268738c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 268838c8a9a5SSteve French return -EIO; 268938c8a9a5SSteve French 269038c8a9a5SSteve French /* 269138c8a9a5SSteve French * We need to be sure that all dirty pages are written as they 269238c8a9a5SSteve French * might fill holes on the server. 269338c8a9a5SSteve French */ 269438c8a9a5SSteve French if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && 269538c8a9a5SSteve French inode->i_mapping->nrpages != 0) { 269638c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 269738c8a9a5SSteve French if (rc) { 269838c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 269938c8a9a5SSteve French return rc; 270038c8a9a5SSteve French } 270138c8a9a5SSteve French } 270238c8a9a5SSteve French 270338c8a9a5SSteve French cfile = find_readable_file(cifs_i, false); 270438c8a9a5SSteve French if (cfile == NULL) 270538c8a9a5SSteve French return -EINVAL; 270638c8a9a5SSteve French 270738c8a9a5SSteve French if (server->ops->fiemap) { 270838c8a9a5SSteve French rc = server->ops->fiemap(tcon, cfile, fei, start, len); 270938c8a9a5SSteve French cifsFileInfo_put(cfile); 271038c8a9a5SSteve French return rc; 271138c8a9a5SSteve French } 271238c8a9a5SSteve French 271338c8a9a5SSteve French cifsFileInfo_put(cfile); 2714ebc3d4e4SSteve French return -EOPNOTSUPP; 271538c8a9a5SSteve French } 271638c8a9a5SSteve French 271738c8a9a5SSteve French int cifs_truncate_page(struct address_space *mapping, loff_t from) 271838c8a9a5SSteve French { 271938c8a9a5SSteve French pgoff_t index = from >> PAGE_SHIFT; 272038c8a9a5SSteve French unsigned offset = from & (PAGE_SIZE - 1); 272138c8a9a5SSteve French struct page *page; 272238c8a9a5SSteve French int rc = 0; 272338c8a9a5SSteve French 272438c8a9a5SSteve French page = grab_cache_page(mapping, index); 272538c8a9a5SSteve French if (!page) 272638c8a9a5SSteve French return -ENOMEM; 272738c8a9a5SSteve French 272838c8a9a5SSteve French zero_user_segment(page, offset, PAGE_SIZE); 272938c8a9a5SSteve French unlock_page(page); 273038c8a9a5SSteve French put_page(page); 273138c8a9a5SSteve French return rc; 273238c8a9a5SSteve French } 273338c8a9a5SSteve French 273438c8a9a5SSteve French void cifs_setsize(struct inode *inode, loff_t offset) 273538c8a9a5SSteve French { 273638c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 273738c8a9a5SSteve French 273838c8a9a5SSteve French spin_lock(&inode->i_lock); 273938c8a9a5SSteve French i_size_write(inode, offset); 274038c8a9a5SSteve French spin_unlock(&inode->i_lock); 274138c8a9a5SSteve French 274238c8a9a5SSteve French /* Cached inode must be refreshed on truncate */ 274338c8a9a5SSteve French cifs_i->time = 0; 274438c8a9a5SSteve French truncate_pagecache(inode, offset); 274538c8a9a5SSteve French } 274638c8a9a5SSteve French 274738c8a9a5SSteve French static int 274838c8a9a5SSteve French cifs_set_file_size(struct inode *inode, struct iattr *attrs, 2749f93d145fSMeetakshi Setiya unsigned int xid, const char *full_path, struct dentry *dentry) 275038c8a9a5SSteve French { 275138c8a9a5SSteve French int rc; 275238c8a9a5SSteve French struct cifsFileInfo *open_file; 275338c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 275438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 275538c8a9a5SSteve French struct tcon_link *tlink = NULL; 275638c8a9a5SSteve French struct cifs_tcon *tcon = NULL; 275738c8a9a5SSteve French struct TCP_Server_Info *server; 275838c8a9a5SSteve French 275938c8a9a5SSteve French /* 276038c8a9a5SSteve French * To avoid spurious oplock breaks from server, in the case of 276138c8a9a5SSteve French * inodes that we already have open, avoid doing path based 276238c8a9a5SSteve French * setting of file size if we can do it by handle. 276338c8a9a5SSteve French * This keeps our caching token (oplock) and avoids timeouts 276438c8a9a5SSteve French * when the local oplock break takes longer to flush 276538c8a9a5SSteve French * writebehind data than the SMB timeout for the SetPathInfo 276638c8a9a5SSteve French * request would allow 276738c8a9a5SSteve French */ 276838c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 276938c8a9a5SSteve French if (open_file) { 277038c8a9a5SSteve French tcon = tlink_tcon(open_file->tlink); 277138c8a9a5SSteve French server = tcon->ses->server; 277238c8a9a5SSteve French if (server->ops->set_file_size) 277338c8a9a5SSteve French rc = server->ops->set_file_size(xid, tcon, open_file, 277438c8a9a5SSteve French attrs->ia_size, false); 277538c8a9a5SSteve French else 277638c8a9a5SSteve French rc = -ENOSYS; 277738c8a9a5SSteve French cifsFileInfo_put(open_file); 277838c8a9a5SSteve French cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc); 277938c8a9a5SSteve French } else 278038c8a9a5SSteve French rc = -EINVAL; 278138c8a9a5SSteve French 278238c8a9a5SSteve French if (!rc) 278338c8a9a5SSteve French goto set_size_out; 278438c8a9a5SSteve French 278538c8a9a5SSteve French if (tcon == NULL) { 278638c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 278738c8a9a5SSteve French if (IS_ERR(tlink)) 278838c8a9a5SSteve French return PTR_ERR(tlink); 278938c8a9a5SSteve French tcon = tlink_tcon(tlink); 279038c8a9a5SSteve French server = tcon->ses->server; 279138c8a9a5SSteve French } 279238c8a9a5SSteve French 279338c8a9a5SSteve French /* 279438c8a9a5SSteve French * Set file size by pathname rather than by handle either because no 279538c8a9a5SSteve French * valid, writeable file handle for it was found or because there was 279638c8a9a5SSteve French * an error setting it by handle. 279738c8a9a5SSteve French */ 279838c8a9a5SSteve French if (server->ops->set_path_size) 279938c8a9a5SSteve French rc = server->ops->set_path_size(xid, tcon, full_path, 2800f93d145fSMeetakshi Setiya attrs->ia_size, cifs_sb, false, dentry); 280138c8a9a5SSteve French else 280238c8a9a5SSteve French rc = -ENOSYS; 280338c8a9a5SSteve French cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc); 280438c8a9a5SSteve French 280538c8a9a5SSteve French if (tlink) 280638c8a9a5SSteve French cifs_put_tlink(tlink); 280738c8a9a5SSteve French 280838c8a9a5SSteve French set_size_out: 280938c8a9a5SSteve French if (rc == 0) { 281038c8a9a5SSteve French cifsInode->server_eof = attrs->ia_size; 281138c8a9a5SSteve French cifs_setsize(inode, attrs->ia_size); 281238c8a9a5SSteve French /* 281338c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), but instead 281438c8a9a5SSteve French * 512 byte (2**9) size is required for calculating num blocks. 281538c8a9a5SSteve French * Until we can query the server for actual allocation size, 281638c8a9a5SSteve French * this is best estimate we have for blocks allocated for a file 281738c8a9a5SSteve French * Number of blocks must be rounded up so size 1 is not 0 blocks 281838c8a9a5SSteve French */ 281938c8a9a5SSteve French inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9; 282038c8a9a5SSteve French 282138c8a9a5SSteve French /* 282238c8a9a5SSteve French * The man page of truncate says if the size changed, 282338c8a9a5SSteve French * then the st_ctime and st_mtime fields for the file 282438c8a9a5SSteve French * are updated. 282538c8a9a5SSteve French */ 282638c8a9a5SSteve French attrs->ia_ctime = attrs->ia_mtime = current_time(inode); 282738c8a9a5SSteve French attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME; 282838c8a9a5SSteve French 282938c8a9a5SSteve French cifs_truncate_page(inode->i_mapping, inode->i_size); 283038c8a9a5SSteve French } 283138c8a9a5SSteve French 283238c8a9a5SSteve French return rc; 283338c8a9a5SSteve French } 283438c8a9a5SSteve French 283538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 283638c8a9a5SSteve French static int 283738c8a9a5SSteve French cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 283838c8a9a5SSteve French { 283938c8a9a5SSteve French int rc; 284038c8a9a5SSteve French unsigned int xid; 284138c8a9a5SSteve French const char *full_path; 284238c8a9a5SSteve French void *page = alloc_dentry_path(); 284338c8a9a5SSteve French struct inode *inode = d_inode(direntry); 284438c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 284538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 284638c8a9a5SSteve French struct tcon_link *tlink; 284738c8a9a5SSteve French struct cifs_tcon *pTcon; 284838c8a9a5SSteve French struct cifs_unix_set_info_args *args = NULL; 284938c8a9a5SSteve French struct cifsFileInfo *open_file; 285038c8a9a5SSteve French 285138c8a9a5SSteve French cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n", 285238c8a9a5SSteve French direntry, attrs->ia_valid); 285338c8a9a5SSteve French 285438c8a9a5SSteve French xid = get_xid(); 285538c8a9a5SSteve French 285638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 285738c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 285838c8a9a5SSteve French 285938c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 286038c8a9a5SSteve French if (rc < 0) 286138c8a9a5SSteve French goto out; 286238c8a9a5SSteve French 286338c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 286438c8a9a5SSteve French if (IS_ERR(full_path)) { 286538c8a9a5SSteve French rc = PTR_ERR(full_path); 286638c8a9a5SSteve French goto out; 286738c8a9a5SSteve French } 286838c8a9a5SSteve French 286938c8a9a5SSteve French /* 287038c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 287138c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the 287238c8a9a5SSteve French * ownership or mode then we may also need to do this. Here, we take 287338c8a9a5SSteve French * the safe way out and just do the flush on all setattr requests. If 287438c8a9a5SSteve French * the flush returns error, store it to report later and continue. 287538c8a9a5SSteve French * 287638c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 287738c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 287838c8a9a5SSteve French * the flush returns error? 287938c8a9a5SSteve French */ 288038c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 288138c8a9a5SSteve French if (is_interrupt_error(rc)) { 288238c8a9a5SSteve French rc = -ERESTARTSYS; 288338c8a9a5SSteve French goto out; 288438c8a9a5SSteve French } 288538c8a9a5SSteve French 288638c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 288738c8a9a5SSteve French rc = 0; 288838c8a9a5SSteve French 288938c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 2890f93d145fSMeetakshi Setiya rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry); 289138c8a9a5SSteve French if (rc != 0) 289238c8a9a5SSteve French goto out; 289338c8a9a5SSteve French } 289438c8a9a5SSteve French 289538c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 289638c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 289738c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 289838c8a9a5SSteve French 289938c8a9a5SSteve French args = kmalloc(sizeof(*args), GFP_KERNEL); 290038c8a9a5SSteve French if (args == NULL) { 290138c8a9a5SSteve French rc = -ENOMEM; 290238c8a9a5SSteve French goto out; 290338c8a9a5SSteve French } 290438c8a9a5SSteve French 290538c8a9a5SSteve French /* set up the struct */ 290638c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) 290738c8a9a5SSteve French args->mode = attrs->ia_mode; 290838c8a9a5SSteve French else 290938c8a9a5SSteve French args->mode = NO_CHANGE_64; 291038c8a9a5SSteve French 291138c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 291238c8a9a5SSteve French args->uid = attrs->ia_uid; 291338c8a9a5SSteve French else 291438c8a9a5SSteve French args->uid = INVALID_UID; /* no change */ 291538c8a9a5SSteve French 291638c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 291738c8a9a5SSteve French args->gid = attrs->ia_gid; 291838c8a9a5SSteve French else 291938c8a9a5SSteve French args->gid = INVALID_GID; /* no change */ 292038c8a9a5SSteve French 292138c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) 292238c8a9a5SSteve French args->atime = cifs_UnixTimeToNT(attrs->ia_atime); 292338c8a9a5SSteve French else 292438c8a9a5SSteve French args->atime = NO_CHANGE_64; 292538c8a9a5SSteve French 292638c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) 292738c8a9a5SSteve French args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); 292838c8a9a5SSteve French else 292938c8a9a5SSteve French args->mtime = NO_CHANGE_64; 293038c8a9a5SSteve French 293138c8a9a5SSteve French if (attrs->ia_valid & ATTR_CTIME) 293238c8a9a5SSteve French args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); 293338c8a9a5SSteve French else 293438c8a9a5SSteve French args->ctime = NO_CHANGE_64; 293538c8a9a5SSteve French 293638c8a9a5SSteve French args->device = 0; 293738c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 293838c8a9a5SSteve French if (open_file) { 293938c8a9a5SSteve French u16 nfid = open_file->fid.netfid; 294038c8a9a5SSteve French u32 npid = open_file->pid; 294138c8a9a5SSteve French pTcon = tlink_tcon(open_file->tlink); 294238c8a9a5SSteve French rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); 294338c8a9a5SSteve French cifsFileInfo_put(open_file); 294438c8a9a5SSteve French } else { 294538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 294638c8a9a5SSteve French if (IS_ERR(tlink)) { 294738c8a9a5SSteve French rc = PTR_ERR(tlink); 294838c8a9a5SSteve French goto out; 294938c8a9a5SSteve French } 295038c8a9a5SSteve French pTcon = tlink_tcon(tlink); 295138c8a9a5SSteve French rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, 295238c8a9a5SSteve French cifs_sb->local_nls, 295338c8a9a5SSteve French cifs_remap(cifs_sb)); 295438c8a9a5SSteve French cifs_put_tlink(tlink); 295538c8a9a5SSteve French } 295638c8a9a5SSteve French 295738c8a9a5SSteve French if (rc) 295838c8a9a5SSteve French goto out; 295938c8a9a5SSteve French 296038c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 296138c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 296238c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 296338c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 296438c8a9a5SSteve French } 296538c8a9a5SSteve French 296638c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 296738c8a9a5SSteve French mark_inode_dirty(inode); 296838c8a9a5SSteve French 296938c8a9a5SSteve French /* force revalidate when any of these times are set since some 297038c8a9a5SSteve French of the fs types (eg ext3, fat) do not have fine enough 297138c8a9a5SSteve French time granularity to match protocol, and we do not have a 297238c8a9a5SSteve French a way (yet) to query the server fs's time granularity (and 297338c8a9a5SSteve French whether it rounds times down). 297438c8a9a5SSteve French */ 297538c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) 297638c8a9a5SSteve French cifsInode->time = 0; 297738c8a9a5SSteve French out: 297838c8a9a5SSteve French kfree(args); 297938c8a9a5SSteve French free_dentry_path(page); 298038c8a9a5SSteve French free_xid(xid); 298138c8a9a5SSteve French return rc; 298238c8a9a5SSteve French } 298338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 298438c8a9a5SSteve French 298538c8a9a5SSteve French static int 298638c8a9a5SSteve French cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) 298738c8a9a5SSteve French { 298838c8a9a5SSteve French unsigned int xid; 298938c8a9a5SSteve French kuid_t uid = INVALID_UID; 299038c8a9a5SSteve French kgid_t gid = INVALID_GID; 299138c8a9a5SSteve French struct inode *inode = d_inode(direntry); 299238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 299338c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 299438c8a9a5SSteve French struct cifsFileInfo *wfile; 299538c8a9a5SSteve French struct cifs_tcon *tcon; 299638c8a9a5SSteve French const char *full_path; 299738c8a9a5SSteve French void *page = alloc_dentry_path(); 299838c8a9a5SSteve French int rc = -EACCES; 299938c8a9a5SSteve French __u32 dosattr = 0; 300038c8a9a5SSteve French __u64 mode = NO_CHANGE_64; 300138c8a9a5SSteve French 300238c8a9a5SSteve French xid = get_xid(); 300338c8a9a5SSteve French 300438c8a9a5SSteve French cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n", 300538c8a9a5SSteve French direntry, attrs->ia_valid); 300638c8a9a5SSteve French 300738c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 300838c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 300938c8a9a5SSteve French 301038c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 301138c8a9a5SSteve French if (rc < 0) 301238c8a9a5SSteve French goto cifs_setattr_exit; 301338c8a9a5SSteve French 301438c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 301538c8a9a5SSteve French if (IS_ERR(full_path)) { 301638c8a9a5SSteve French rc = PTR_ERR(full_path); 301738c8a9a5SSteve French goto cifs_setattr_exit; 301838c8a9a5SSteve French } 301938c8a9a5SSteve French 302038c8a9a5SSteve French /* 302138c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 302238c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data 302338c8a9a5SSteve French * returns error, store it to report later and continue. 302438c8a9a5SSteve French * 302538c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 302638c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 302738c8a9a5SSteve French * the flush returns error? Do we need to check for ATTR_MTIME_SET flag? 302838c8a9a5SSteve French */ 302938c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) { 303038c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 303138c8a9a5SSteve French if (is_interrupt_error(rc)) { 303238c8a9a5SSteve French rc = -ERESTARTSYS; 303338c8a9a5SSteve French goto cifs_setattr_exit; 303438c8a9a5SSteve French } 303538c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 303638c8a9a5SSteve French } 303738c8a9a5SSteve French 303838c8a9a5SSteve French rc = 0; 303938c8a9a5SSteve French 304038c8a9a5SSteve French if ((attrs->ia_valid & ATTR_MTIME) && 304138c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { 304238c8a9a5SSteve French rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile); 304338c8a9a5SSteve French if (!rc) { 304438c8a9a5SSteve French tcon = tlink_tcon(wfile->tlink); 304538c8a9a5SSteve French rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid); 304638c8a9a5SSteve French cifsFileInfo_put(wfile); 304738c8a9a5SSteve French if (rc) 304838c8a9a5SSteve French goto cifs_setattr_exit; 304938c8a9a5SSteve French } else if (rc != -EBADF) 305038c8a9a5SSteve French goto cifs_setattr_exit; 305138c8a9a5SSteve French else 305238c8a9a5SSteve French rc = 0; 305338c8a9a5SSteve French } 305438c8a9a5SSteve French 305538c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 3056f93d145fSMeetakshi Setiya rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry); 305738c8a9a5SSteve French if (rc != 0) 305838c8a9a5SSteve French goto cifs_setattr_exit; 305938c8a9a5SSteve French } 306038c8a9a5SSteve French 306138c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 306238c8a9a5SSteve French uid = attrs->ia_uid; 306338c8a9a5SSteve French 306438c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 306538c8a9a5SSteve French gid = attrs->ia_gid; 306638c8a9a5SSteve French 306738c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 306838c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 306938c8a9a5SSteve French if (uid_valid(uid) || gid_valid(gid)) { 307038c8a9a5SSteve French mode = NO_CHANGE_64; 307138c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 307238c8a9a5SSteve French uid, gid); 307338c8a9a5SSteve French if (rc) { 307438c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting id failed with error: %d\n", 307538c8a9a5SSteve French __func__, rc); 307638c8a9a5SSteve French goto cifs_setattr_exit; 307738c8a9a5SSteve French } 307838c8a9a5SSteve French } 307938c8a9a5SSteve French } else 308038c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) 308138c8a9a5SSteve French attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 308238c8a9a5SSteve French 308338c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 308438c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 308538c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 308638c8a9a5SSteve French 308738c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) { 308838c8a9a5SSteve French mode = attrs->ia_mode; 308938c8a9a5SSteve French rc = 0; 309038c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 309138c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 309238c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 309338c8a9a5SSteve French INVALID_UID, INVALID_GID); 309438c8a9a5SSteve French if (rc) { 309538c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n", 309638c8a9a5SSteve French __func__, rc); 309738c8a9a5SSteve French goto cifs_setattr_exit; 309838c8a9a5SSteve French } 309938c8a9a5SSteve French 310038c8a9a5SSteve French /* 310138c8a9a5SSteve French * In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes. 310238c8a9a5SSteve French * Pick up the actual mode bits that were set. 310338c8a9a5SSteve French */ 310438c8a9a5SSteve French if (mode != attrs->ia_mode) 310538c8a9a5SSteve French attrs->ia_mode = mode; 310638c8a9a5SSteve French } else 310738c8a9a5SSteve French if (((mode & S_IWUGO) == 0) && 310838c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 310938c8a9a5SSteve French 311038c8a9a5SSteve French dosattr = cifsInode->cifsAttrs | ATTR_READONLY; 311138c8a9a5SSteve French 311238c8a9a5SSteve French /* fix up mode if we're not using dynperm */ 311338c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) 311438c8a9a5SSteve French attrs->ia_mode = inode->i_mode & ~S_IWUGO; 311538c8a9a5SSteve French } else if ((mode & S_IWUGO) && 311638c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY)) { 311738c8a9a5SSteve French 311838c8a9a5SSteve French dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; 311938c8a9a5SSteve French /* Attributes of 0 are ignored */ 312038c8a9a5SSteve French if (dosattr == 0) 312138c8a9a5SSteve French dosattr |= ATTR_NORMAL; 312238c8a9a5SSteve French 312338c8a9a5SSteve French /* reset local inode permissions to normal */ 312438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 312538c8a9a5SSteve French attrs->ia_mode &= ~(S_IALLUGO); 312638c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) 312738c8a9a5SSteve French attrs->ia_mode |= 312838c8a9a5SSteve French cifs_sb->ctx->dir_mode; 312938c8a9a5SSteve French else 313038c8a9a5SSteve French attrs->ia_mode |= 313138c8a9a5SSteve French cifs_sb->ctx->file_mode; 313238c8a9a5SSteve French } 313338c8a9a5SSteve French } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 313438c8a9a5SSteve French /* ignore mode change - ATTR_READONLY hasn't changed */ 313538c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 313638c8a9a5SSteve French } 313738c8a9a5SSteve French } 313838c8a9a5SSteve French 313938c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || 314038c8a9a5SSteve French ((attrs->ia_valid & ATTR_MODE) && dosattr)) { 314138c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 314238c8a9a5SSteve French /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ 314338c8a9a5SSteve French 314438c8a9a5SSteve French /* Even if error on time set, no sense failing the call if 314538c8a9a5SSteve French the server would set the time to a reasonable value anyway, 314638c8a9a5SSteve French and this check ensures that we are not being called from 314738c8a9a5SSteve French sys_utimes in which case we ought to fail the call back to 314838c8a9a5SSteve French the user when the server rejects the call */ 314938c8a9a5SSteve French if ((rc) && (attrs->ia_valid & 315038c8a9a5SSteve French (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) 315138c8a9a5SSteve French rc = 0; 315238c8a9a5SSteve French } 315338c8a9a5SSteve French 315438c8a9a5SSteve French /* do not need local check to inode_check_ok since the server does 315538c8a9a5SSteve French that */ 315638c8a9a5SSteve French if (rc) 315738c8a9a5SSteve French goto cifs_setattr_exit; 315838c8a9a5SSteve French 315938c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 316038c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 316138c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 316238c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 316338c8a9a5SSteve French } 316438c8a9a5SSteve French 316538c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 316638c8a9a5SSteve French mark_inode_dirty(inode); 316738c8a9a5SSteve French 316838c8a9a5SSteve French cifs_setattr_exit: 316938c8a9a5SSteve French free_xid(xid); 317038c8a9a5SSteve French free_dentry_path(page); 317138c8a9a5SSteve French return rc; 317238c8a9a5SSteve French } 317338c8a9a5SSteve French 317438c8a9a5SSteve French int 317538c8a9a5SSteve French cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry, 317638c8a9a5SSteve French struct iattr *attrs) 317738c8a9a5SSteve French { 317838c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 317938c8a9a5SSteve French int rc, retries = 0; 318038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 318138c8a9a5SSteve French struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); 318238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 318338c8a9a5SSteve French 318438c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 318538c8a9a5SSteve French return -EIO; 318638c8a9a5SSteve French 318738c8a9a5SSteve French do { 318838c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 318938c8a9a5SSteve French if (pTcon->unix_ext) 319038c8a9a5SSteve French rc = cifs_setattr_unix(direntry, attrs); 319138c8a9a5SSteve French else 319238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 319338c8a9a5SSteve French rc = cifs_setattr_nounix(direntry, attrs); 319438c8a9a5SSteve French retries++; 319538c8a9a5SSteve French } while (is_retryable_error(rc) && retries < 2); 319638c8a9a5SSteve French 319738c8a9a5SSteve French /* BB: add cifs_setattr_legacy for really old servers */ 319838c8a9a5SSteve French return rc; 319938c8a9a5SSteve French } 3200