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" 2938c8a9a5SSteve French 3038c8a9a5SSteve French static void cifs_set_ops(struct inode *inode) 3138c8a9a5SSteve French { 3238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 3338c8a9a5SSteve French 3438c8a9a5SSteve French switch (inode->i_mode & S_IFMT) { 3538c8a9a5SSteve French case S_IFREG: 3638c8a9a5SSteve French inode->i_op = &cifs_file_inode_ops; 3738c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { 3838c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 3938c8a9a5SSteve French inode->i_fop = &cifs_file_direct_nobrl_ops; 4038c8a9a5SSteve French else 4138c8a9a5SSteve French inode->i_fop = &cifs_file_direct_ops; 4238c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { 4338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 4438c8a9a5SSteve French inode->i_fop = &cifs_file_strict_nobrl_ops; 4538c8a9a5SSteve French else 4638c8a9a5SSteve French inode->i_fop = &cifs_file_strict_ops; 4738c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 4838c8a9a5SSteve French inode->i_fop = &cifs_file_nobrl_ops; 4938c8a9a5SSteve French else { /* not direct, send byte range locks */ 5038c8a9a5SSteve French inode->i_fop = &cifs_file_ops; 5138c8a9a5SSteve French } 5238c8a9a5SSteve French 5338c8a9a5SSteve French /* check if server can support readahead */ 5438c8a9a5SSteve French if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read < 5538c8a9a5SSteve French PAGE_SIZE + MAX_CIFS_HDR_SIZE) 5638c8a9a5SSteve French inode->i_data.a_ops = &cifs_addr_ops_smallbuf; 5738c8a9a5SSteve French else 5838c8a9a5SSteve French inode->i_data.a_ops = &cifs_addr_ops; 5938c8a9a5SSteve French break; 6038c8a9a5SSteve French case S_IFDIR: 6138c8a9a5SSteve French if (IS_AUTOMOUNT(inode)) { 620a049935SPaulo Alcantara inode->i_op = &cifs_namespace_inode_operations; 6338c8a9a5SSteve French } else { 6438c8a9a5SSteve French inode->i_op = &cifs_dir_inode_ops; 6538c8a9a5SSteve French inode->i_fop = &cifs_dir_ops; 6638c8a9a5SSteve French } 6738c8a9a5SSteve French break; 6838c8a9a5SSteve French case S_IFLNK: 6938c8a9a5SSteve French inode->i_op = &cifs_symlink_inode_ops; 7038c8a9a5SSteve French break; 7138c8a9a5SSteve French default: 7238c8a9a5SSteve French init_special_inode(inode, inode->i_mode, inode->i_rdev); 7338c8a9a5SSteve French break; 7438c8a9a5SSteve French } 7538c8a9a5SSteve French } 7638c8a9a5SSteve French 7738c8a9a5SSteve French /* check inode attributes against fattr. If they don't match, tag the 7838c8a9a5SSteve French * inode for cache invalidation 7938c8a9a5SSteve French */ 8038c8a9a5SSteve French static void 8138c8a9a5SSteve French cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) 8238c8a9a5SSteve French { 8338c8a9a5SSteve French struct cifs_fscache_inode_coherency_data cd; 8438c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 8523171df5SJeff Layton struct timespec64 mtime; 8638c8a9a5SSteve French 8738c8a9a5SSteve French cifs_dbg(FYI, "%s: revalidating inode %llu\n", 8838c8a9a5SSteve French __func__, cifs_i->uniqueid); 8938c8a9a5SSteve French 9038c8a9a5SSteve French if (inode->i_state & I_NEW) { 9138c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is new\n", 9238c8a9a5SSteve French __func__, cifs_i->uniqueid); 9338c8a9a5SSteve French return; 9438c8a9a5SSteve French } 9538c8a9a5SSteve French 9638c8a9a5SSteve French /* don't bother with revalidation if we have an oplock */ 9738c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) { 9838c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is oplocked\n", 9938c8a9a5SSteve French __func__, cifs_i->uniqueid); 10038c8a9a5SSteve French return; 10138c8a9a5SSteve French } 10238c8a9a5SSteve French 10338c8a9a5SSteve French /* revalidate if mtime or size have changed */ 10438c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 10523171df5SJeff Layton mtime = inode_get_mtime(inode); 10623171df5SJeff Layton if (timespec64_equal(&mtime, &fattr->cf_mtime) && 10738c8a9a5SSteve French cifs_i->server_eof == fattr->cf_eof) { 10838c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is unchanged\n", 10938c8a9a5SSteve French __func__, cifs_i->uniqueid); 11038c8a9a5SSteve French return; 11138c8a9a5SSteve French } 11238c8a9a5SSteve French 11338c8a9a5SSteve French cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n", 11438c8a9a5SSteve French __func__, cifs_i->uniqueid); 11538c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags); 11638c8a9a5SSteve French /* Invalidate fscache cookie */ 11738c8a9a5SSteve French cifs_fscache_fill_coherency(&cifs_i->netfs.inode, &cd); 11838c8a9a5SSteve French fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0); 11938c8a9a5SSteve French } 12038c8a9a5SSteve French 12138c8a9a5SSteve French /* 12238c8a9a5SSteve French * copy nlink to the inode, unless it wasn't provided. Provide 12338c8a9a5SSteve French * sane values if we don't have an existing one and none was provided 12438c8a9a5SSteve French */ 12538c8a9a5SSteve French static void 12638c8a9a5SSteve French cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) 12738c8a9a5SSteve French { 12838c8a9a5SSteve French /* 12938c8a9a5SSteve French * if we're in a situation where we can't trust what we 13038c8a9a5SSteve French * got from the server (readdir, some non-unix cases) 13138c8a9a5SSteve French * fake reasonable values 13238c8a9a5SSteve French */ 13338c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) { 13438c8a9a5SSteve French /* only provide fake values on a new inode */ 13538c8a9a5SSteve French if (inode->i_state & I_NEW) { 13638c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_DIRECTORY) 13738c8a9a5SSteve French set_nlink(inode, 2); 13838c8a9a5SSteve French else 13938c8a9a5SSteve French set_nlink(inode, 1); 14038c8a9a5SSteve French } 14138c8a9a5SSteve French return; 14238c8a9a5SSteve French } 14338c8a9a5SSteve French 14438c8a9a5SSteve French /* we trust the server, so update it */ 14538c8a9a5SSteve French set_nlink(inode, fattr->cf_nlink); 14638c8a9a5SSteve French } 14738c8a9a5SSteve French 14838c8a9a5SSteve French /* populate an inode with info from a cifs_fattr struct */ 14938c8a9a5SSteve French int 1509179aa27SBharath SM cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, 1519179aa27SBharath SM bool from_readdir) 15238c8a9a5SSteve French { 15338c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 15438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 15538c8a9a5SSteve French 15638c8a9a5SSteve French if (!(inode->i_state & I_NEW) && 15738c8a9a5SSteve French unlikely(inode_wrong_type(inode, fattr->cf_mode))) { 15838c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force reval */ 15938c8a9a5SSteve French return -ESTALE; 16038c8a9a5SSteve French } 16138c8a9a5SSteve French 16238c8a9a5SSteve French cifs_revalidate_cache(inode, fattr); 16338c8a9a5SSteve French 16438c8a9a5SSteve French spin_lock(&inode->i_lock); 16538c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 16638c8a9a5SSteve French fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode); 16738c8a9a5SSteve French fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode); 16838c8a9a5SSteve French /* we do not want atime to be less than mtime, it broke some apps */ 16938c8a9a5SSteve French if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0) 17023171df5SJeff Layton inode_set_atime_to_ts(inode, fattr->cf_mtime); 17138c8a9a5SSteve French else 17223171df5SJeff Layton inode_set_atime_to_ts(inode, fattr->cf_atime); 17323171df5SJeff Layton inode_set_mtime_to_ts(inode, fattr->cf_mtime); 17494487653SJeff Layton inode_set_ctime_to_ts(inode, fattr->cf_ctime); 17538c8a9a5SSteve French inode->i_rdev = fattr->cf_rdev; 17638c8a9a5SSteve French cifs_nlink_fattr_to_inode(inode, fattr); 17738c8a9a5SSteve French inode->i_uid = fattr->cf_uid; 17838c8a9a5SSteve French inode->i_gid = fattr->cf_gid; 17938c8a9a5SSteve French 18038c8a9a5SSteve French /* if dynperm is set, don't clobber existing mode */ 18138c8a9a5SSteve French if (inode->i_state & I_NEW || 18238c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) 18338c8a9a5SSteve French inode->i_mode = fattr->cf_mode; 18438c8a9a5SSteve French 18538c8a9a5SSteve French cifs_i->cifsAttrs = fattr->cf_cifsattrs; 186b9e741acSPaulo Alcantara cifs_i->reparse_tag = fattr->cf_cifstag; 18738c8a9a5SSteve French 18838c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) 18938c8a9a5SSteve French cifs_i->time = 0; 19038c8a9a5SSteve French else 19138c8a9a5SSteve French cifs_i->time = jiffies; 19238c8a9a5SSteve French 19338c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING) 19438c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19538c8a9a5SSteve French else 19638c8a9a5SSteve French clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19738c8a9a5SSteve French 19838c8a9a5SSteve French cifs_i->server_eof = fattr->cf_eof; 19938c8a9a5SSteve French /* 20038c8a9a5SSteve French * Can't safely change the file size here if the client is writing to 20138c8a9a5SSteve French * it due to potential races. 20238c8a9a5SSteve French */ 2039179aa27SBharath SM if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) { 20438c8a9a5SSteve French i_size_write(inode, fattr->cf_eof); 20538c8a9a5SSteve French 20638c8a9a5SSteve French /* 20738c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), 20838c8a9a5SSteve French * but instead 512 byte (2**9) size is required for 20938c8a9a5SSteve French * calculating num blocks. 21038c8a9a5SSteve French */ 21138c8a9a5SSteve French inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; 21238c8a9a5SSteve French } 21338c8a9a5SSteve French 214b9e741acSPaulo Alcantara if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) { 21538c8a9a5SSteve French kfree(cifs_i->symlink_target); 21638c8a9a5SSteve French cifs_i->symlink_target = fattr->cf_symlink_target; 21738c8a9a5SSteve French fattr->cf_symlink_target = NULL; 21838c8a9a5SSteve French } 21938c8a9a5SSteve French spin_unlock(&inode->i_lock); 22038c8a9a5SSteve French 221a18280e7SPaulo Alcantara if (fattr->cf_flags & CIFS_FATTR_JUNCTION) 22238c8a9a5SSteve French inode->i_flags |= S_AUTOMOUNT; 22338c8a9a5SSteve French if (inode->i_state & I_NEW) 22438c8a9a5SSteve French cifs_set_ops(inode); 22538c8a9a5SSteve French return 0; 22638c8a9a5SSteve French } 22738c8a9a5SSteve French 22838c8a9a5SSteve French void 22938c8a9a5SSteve French cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr) 23038c8a9a5SSteve French { 23138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 23238c8a9a5SSteve French 23338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 23438c8a9a5SSteve French return; 23538c8a9a5SSteve French 23638c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 23738c8a9a5SSteve French } 23838c8a9a5SSteve French 23938c8a9a5SSteve French /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ 24038c8a9a5SSteve French void 24138c8a9a5SSteve French cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, 24238c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 24338c8a9a5SSteve French { 24438c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 24538c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); 24638c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); 24738c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 24838c8a9a5SSteve French 24938c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 25038c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); 25138c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); 25238c8a9a5SSteve French /* old POSIX extensions don't get create time */ 25338c8a9a5SSteve French 25438c8a9a5SSteve French fattr->cf_mode = le64_to_cpu(info->Permissions); 25538c8a9a5SSteve French 25638c8a9a5SSteve French /* 25738c8a9a5SSteve French * Since we set the inode type below we need to mask off 25838c8a9a5SSteve French * to avoid strange results if bits set above. 25938c8a9a5SSteve French */ 26038c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 26138c8a9a5SSteve French switch (le32_to_cpu(info->Type)) { 26238c8a9a5SSteve French case UNIX_FILE: 26338c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 26438c8a9a5SSteve French fattr->cf_dtype = DT_REG; 26538c8a9a5SSteve French break; 26638c8a9a5SSteve French case UNIX_SYMLINK: 26738c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 26838c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 26938c8a9a5SSteve French break; 27038c8a9a5SSteve French case UNIX_DIR: 27138c8a9a5SSteve French fattr->cf_mode |= S_IFDIR; 27238c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 27338c8a9a5SSteve French break; 27438c8a9a5SSteve French case UNIX_CHARDEV: 27538c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 27638c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 27738c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 27838c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 27938c8a9a5SSteve French break; 28038c8a9a5SSteve French case UNIX_BLOCKDEV: 28138c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 28238c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 28338c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 28438c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 28538c8a9a5SSteve French break; 28638c8a9a5SSteve French case UNIX_FIFO: 28738c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 28838c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 28938c8a9a5SSteve French break; 29038c8a9a5SSteve French case UNIX_SOCKET: 29138c8a9a5SSteve French fattr->cf_mode |= S_IFSOCK; 29238c8a9a5SSteve French fattr->cf_dtype = DT_SOCK; 29338c8a9a5SSteve French break; 29438c8a9a5SSteve French default: 29538c8a9a5SSteve French /* safest to call it a file if we do not know */ 29638c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 29738c8a9a5SSteve French fattr->cf_dtype = DT_REG; 29838c8a9a5SSteve French cifs_dbg(FYI, "unknown type %d\n", le32_to_cpu(info->Type)); 29938c8a9a5SSteve French break; 30038c8a9a5SSteve French } 30138c8a9a5SSteve French 30238c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 30338c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { 30438c8a9a5SSteve French u64 id = le64_to_cpu(info->Uid); 30538c8a9a5SSteve French if (id < ((uid_t)-1)) { 30638c8a9a5SSteve French kuid_t uid = make_kuid(&init_user_ns, id); 30738c8a9a5SSteve French if (uid_valid(uid)) 30838c8a9a5SSteve French fattr->cf_uid = uid; 30938c8a9a5SSteve French } 31038c8a9a5SSteve French } 31138c8a9a5SSteve French 31238c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 31338c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { 31438c8a9a5SSteve French u64 id = le64_to_cpu(info->Gid); 31538c8a9a5SSteve French if (id < ((gid_t)-1)) { 31638c8a9a5SSteve French kgid_t gid = make_kgid(&init_user_ns, id); 31738c8a9a5SSteve French if (gid_valid(gid)) 31838c8a9a5SSteve French fattr->cf_gid = gid; 31938c8a9a5SSteve French } 32038c8a9a5SSteve French } 32138c8a9a5SSteve French 32238c8a9a5SSteve French fattr->cf_nlink = le64_to_cpu(info->Nlinks); 32338c8a9a5SSteve French } 32438c8a9a5SSteve French 32538c8a9a5SSteve French /* 32638c8a9a5SSteve French * Fill a cifs_fattr struct with fake inode info. 32738c8a9a5SSteve French * 32838c8a9a5SSteve French * Needed to setup cifs_fattr data for the directory which is the 32938c8a9a5SSteve French * junction to the new submount (ie to setup the fake directory 330a18280e7SPaulo Alcantara * which represents a DFS referral or reparse mount point). 33138c8a9a5SSteve French */ 332a18280e7SPaulo Alcantara static void cifs_create_junction_fattr(struct cifs_fattr *fattr, 333a18280e7SPaulo Alcantara struct super_block *sb) 33438c8a9a5SSteve French { 33538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 33638c8a9a5SSteve French 337a18280e7SPaulo Alcantara cifs_dbg(FYI, "%s: creating fake fattr\n", __func__); 33838c8a9a5SSteve French 33938c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 34038c8a9a5SSteve French fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; 34138c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 34238c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 34338c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_mtime); 34438c8a9a5SSteve French fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; 34538c8a9a5SSteve French fattr->cf_nlink = 2; 346a18280e7SPaulo Alcantara fattr->cf_flags = CIFS_FATTR_JUNCTION; 347a18280e7SPaulo Alcantara } 348a18280e7SPaulo Alcantara 349a18280e7SPaulo Alcantara /* Update inode with final fattr data */ 350a18280e7SPaulo Alcantara static int update_inode_info(struct super_block *sb, 351a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 352a18280e7SPaulo Alcantara struct inode **inode) 353a18280e7SPaulo Alcantara { 354a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 355a18280e7SPaulo Alcantara int rc = 0; 356a18280e7SPaulo Alcantara 357a18280e7SPaulo Alcantara if (!*inode) { 358a18280e7SPaulo Alcantara *inode = cifs_iget(sb, fattr); 359a18280e7SPaulo Alcantara if (!*inode) 360a18280e7SPaulo Alcantara rc = -ENOMEM; 361a18280e7SPaulo Alcantara return rc; 362a18280e7SPaulo Alcantara } 363a18280e7SPaulo Alcantara /* We already have inode, update it. 364a18280e7SPaulo Alcantara * 365a18280e7SPaulo Alcantara * If file type or uniqueid is different, return error. 366a18280e7SPaulo Alcantara */ 367a18280e7SPaulo Alcantara if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 368a18280e7SPaulo Alcantara CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) { 369a18280e7SPaulo Alcantara CIFS_I(*inode)->time = 0; /* force reval */ 370a18280e7SPaulo Alcantara return -ESTALE; 371a18280e7SPaulo Alcantara } 3729179aa27SBharath SM return cifs_fattr_to_inode(*inode, fattr, false); 37338c8a9a5SSteve French } 37438c8a9a5SSteve French 37538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 37638c8a9a5SSteve French static int 37738c8a9a5SSteve French cifs_get_file_info_unix(struct file *filp) 37838c8a9a5SSteve French { 37938c8a9a5SSteve French int rc; 38038c8a9a5SSteve French unsigned int xid; 38138c8a9a5SSteve French FILE_UNIX_BASIC_INFO find_data; 38238c8a9a5SSteve French struct cifs_fattr fattr = {}; 38338c8a9a5SSteve French struct inode *inode = file_inode(filp); 38438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 38538c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 38638c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 38738c8a9a5SSteve French 38838c8a9a5SSteve French xid = get_xid(); 38938c8a9a5SSteve French 39038c8a9a5SSteve French if (cfile->symlink_target) { 39138c8a9a5SSteve French fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 39238c8a9a5SSteve French if (!fattr.cf_symlink_target) { 39338c8a9a5SSteve French rc = -ENOMEM; 39438c8a9a5SSteve French goto cifs_gfiunix_out; 39538c8a9a5SSteve French } 39638c8a9a5SSteve French } 39738c8a9a5SSteve French 39838c8a9a5SSteve French rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data); 39938c8a9a5SSteve French if (!rc) { 40038c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); 40138c8a9a5SSteve French } else if (rc == -EREMOTE) { 402a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 40338c8a9a5SSteve French rc = 0; 40438c8a9a5SSteve French } else 40538c8a9a5SSteve French goto cifs_gfiunix_out; 40638c8a9a5SSteve French 4079179aa27SBharath SM rc = cifs_fattr_to_inode(inode, &fattr, false); 40838c8a9a5SSteve French 40938c8a9a5SSteve French cifs_gfiunix_out: 41038c8a9a5SSteve French free_xid(xid); 41138c8a9a5SSteve French return rc; 41238c8a9a5SSteve French } 41338c8a9a5SSteve French 414a18280e7SPaulo Alcantara static int cifs_get_unix_fattr(const unsigned char *full_path, 415a18280e7SPaulo Alcantara struct super_block *sb, 416a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 417a18280e7SPaulo Alcantara struct inode **pinode, 418a18280e7SPaulo Alcantara const unsigned int xid) 41938c8a9a5SSteve French { 42038c8a9a5SSteve French struct TCP_Server_Info *server; 42138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 422a18280e7SPaulo Alcantara FILE_UNIX_BASIC_INFO find_data; 423a18280e7SPaulo Alcantara struct cifs_tcon *tcon; 424a18280e7SPaulo Alcantara struct tcon_link *tlink; 425a18280e7SPaulo Alcantara int rc, tmprc; 42638c8a9a5SSteve French 42738c8a9a5SSteve French cifs_dbg(FYI, "Getting info on %s\n", full_path); 42838c8a9a5SSteve French 42938c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 43038c8a9a5SSteve French if (IS_ERR(tlink)) 43138c8a9a5SSteve French return PTR_ERR(tlink); 43238c8a9a5SSteve French tcon = tlink_tcon(tlink); 43338c8a9a5SSteve French server = tcon->ses->server; 43438c8a9a5SSteve French 43538c8a9a5SSteve French /* could have done a find first instead but this returns more info */ 43638c8a9a5SSteve French rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, 43738c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 43838c8a9a5SSteve French cifs_dbg(FYI, "%s: query path info: rc = %d\n", __func__, rc); 43938c8a9a5SSteve French cifs_put_tlink(tlink); 44038c8a9a5SSteve French 44138c8a9a5SSteve French if (!rc) { 442a18280e7SPaulo Alcantara cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb); 44338c8a9a5SSteve French } else if (rc == -EREMOTE) { 444a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 44538c8a9a5SSteve French rc = 0; 44638c8a9a5SSteve French } else { 44738c8a9a5SSteve French return rc; 44838c8a9a5SSteve French } 44938c8a9a5SSteve French 450a18280e7SPaulo Alcantara if (!*pinode) 451a18280e7SPaulo Alcantara cifs_fill_uniqueid(sb, fattr); 452a18280e7SPaulo Alcantara 45338c8a9a5SSteve French /* check for Minshall+French symlinks */ 45438c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 455a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 45638c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 45738c8a9a5SSteve French } 45838c8a9a5SSteve French 459a18280e7SPaulo Alcantara if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { 46038c8a9a5SSteve French if (!server->ops->query_symlink) 46138c8a9a5SSteve French return -EOPNOTSUPP; 462a18280e7SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 463a18280e7SPaulo Alcantara cifs_sb, full_path, 4644d07e5dfSPaulo Alcantara &fattr->cf_symlink_target); 46538c8a9a5SSteve French cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 46638c8a9a5SSteve French } 467a18280e7SPaulo Alcantara return rc; 46838c8a9a5SSteve French } 46938c8a9a5SSteve French 470a18280e7SPaulo Alcantara int cifs_get_inode_info_unix(struct inode **pinode, 471a18280e7SPaulo Alcantara const unsigned char *full_path, 472a18280e7SPaulo Alcantara struct super_block *sb, unsigned int xid) 473a18280e7SPaulo Alcantara { 474a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 475a18280e7SPaulo Alcantara int rc; 47638c8a9a5SSteve French 477a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid); 478a18280e7SPaulo Alcantara if (rc) 479a18280e7SPaulo Alcantara goto out; 48038c8a9a5SSteve French 481a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, pinode); 482a18280e7SPaulo Alcantara out: 48338c8a9a5SSteve French kfree(fattr.cf_symlink_target); 48438c8a9a5SSteve French return rc; 48538c8a9a5SSteve French } 48638c8a9a5SSteve French #else 487a18280e7SPaulo Alcantara static inline int cifs_get_unix_fattr(const unsigned char *full_path, 488a18280e7SPaulo Alcantara struct super_block *sb, 489a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 490a18280e7SPaulo Alcantara struct inode **pinode, 491a18280e7SPaulo Alcantara const unsigned int xid) 492a18280e7SPaulo Alcantara { 493a18280e7SPaulo Alcantara return -EOPNOTSUPP; 494a18280e7SPaulo Alcantara } 495a18280e7SPaulo Alcantara 49638c8a9a5SSteve French int cifs_get_inode_info_unix(struct inode **pinode, 49738c8a9a5SSteve French const unsigned char *full_path, 49838c8a9a5SSteve French struct super_block *sb, unsigned int xid) 49938c8a9a5SSteve French { 50038c8a9a5SSteve French return -EOPNOTSUPP; 50138c8a9a5SSteve French } 50238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 50338c8a9a5SSteve French 50438c8a9a5SSteve French static int 50538c8a9a5SSteve French cifs_sfu_type(struct cifs_fattr *fattr, const char *path, 50638c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 50738c8a9a5SSteve French { 50838c8a9a5SSteve French int rc; 50938c8a9a5SSteve French __u32 oplock; 51038c8a9a5SSteve French struct tcon_link *tlink; 51138c8a9a5SSteve French struct cifs_tcon *tcon; 51238c8a9a5SSteve French struct cifs_fid fid; 51338c8a9a5SSteve French struct cifs_open_parms oparms; 51438c8a9a5SSteve French struct cifs_io_parms io_parms = {0}; 51538c8a9a5SSteve French char buf[24]; 51638c8a9a5SSteve French unsigned int bytes_read; 51738c8a9a5SSteve French char *pbuf; 51838c8a9a5SSteve French int buf_type = CIFS_NO_BUFFER; 51938c8a9a5SSteve French 52038c8a9a5SSteve French pbuf = buf; 52138c8a9a5SSteve French 52238c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 52338c8a9a5SSteve French 52438c8a9a5SSteve French if (fattr->cf_eof == 0) { 52538c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 52638c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 52738c8a9a5SSteve French return 0; 52838c8a9a5SSteve French } else if (fattr->cf_eof < 8) { 52938c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 53038c8a9a5SSteve French fattr->cf_dtype = DT_REG; 53138c8a9a5SSteve French return -EINVAL; /* EOPNOTSUPP? */ 53238c8a9a5SSteve French } 53338c8a9a5SSteve French 53438c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 53538c8a9a5SSteve French if (IS_ERR(tlink)) 53638c8a9a5SSteve French return PTR_ERR(tlink); 53738c8a9a5SSteve French tcon = tlink_tcon(tlink); 53838c8a9a5SSteve French 53938c8a9a5SSteve French oparms = (struct cifs_open_parms) { 54038c8a9a5SSteve French .tcon = tcon, 54138c8a9a5SSteve French .cifs_sb = cifs_sb, 54238c8a9a5SSteve French .desired_access = GENERIC_READ, 54338c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 54438c8a9a5SSteve French .disposition = FILE_OPEN, 54538c8a9a5SSteve French .path = path, 54638c8a9a5SSteve French .fid = &fid, 54738c8a9a5SSteve French }; 54838c8a9a5SSteve French 54938c8a9a5SSteve French if (tcon->ses->server->oplocks) 55038c8a9a5SSteve French oplock = REQ_OPLOCK; 55138c8a9a5SSteve French else 55238c8a9a5SSteve French oplock = 0; 55338c8a9a5SSteve French rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); 55438c8a9a5SSteve French if (rc) { 55538c8a9a5SSteve French cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc); 55638c8a9a5SSteve French cifs_put_tlink(tlink); 55738c8a9a5SSteve French return rc; 55838c8a9a5SSteve French } 55938c8a9a5SSteve French 56038c8a9a5SSteve French /* Read header */ 56138c8a9a5SSteve French io_parms.netfid = fid.netfid; 56238c8a9a5SSteve French io_parms.pid = current->tgid; 56338c8a9a5SSteve French io_parms.tcon = tcon; 56438c8a9a5SSteve French io_parms.offset = 0; 56538c8a9a5SSteve French io_parms.length = 24; 56638c8a9a5SSteve French 56738c8a9a5SSteve French rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms, 56838c8a9a5SSteve French &bytes_read, &pbuf, &buf_type); 56938c8a9a5SSteve French if ((rc == 0) && (bytes_read >= 8)) { 57038c8a9a5SSteve French if (memcmp("IntxBLK", pbuf, 8) == 0) { 57138c8a9a5SSteve French cifs_dbg(FYI, "Block device\n"); 57238c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 57338c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 57438c8a9a5SSteve French if (bytes_read == 24) { 57538c8a9a5SSteve French /* we have enough to decode dev num */ 57638c8a9a5SSteve French __u64 mjr; /* major */ 57738c8a9a5SSteve French __u64 mnr; /* minor */ 57838c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 57938c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 58038c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 58138c8a9a5SSteve French } 58238c8a9a5SSteve French } else if (memcmp("IntxCHR", pbuf, 8) == 0) { 58338c8a9a5SSteve French cifs_dbg(FYI, "Char device\n"); 58438c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 58538c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 58638c8a9a5SSteve French if (bytes_read == 24) { 58738c8a9a5SSteve French /* we have enough to decode dev num */ 58838c8a9a5SSteve French __u64 mjr; /* major */ 58938c8a9a5SSteve French __u64 mnr; /* minor */ 59038c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 59138c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 59238c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 59338c8a9a5SSteve French } 59438c8a9a5SSteve French } else if (memcmp("IntxLNK", pbuf, 7) == 0) { 59538c8a9a5SSteve French cifs_dbg(FYI, "Symlink\n"); 59638c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 59738c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 598d6120327SSteve French } else if (memcmp("LnxFIFO", pbuf, 8) == 0) { 599d6120327SSteve French cifs_dbg(FYI, "FIFO\n"); 600d6120327SSteve French fattr->cf_mode |= S_IFIFO; 601d6120327SSteve French fattr->cf_dtype = DT_FIFO; 60238c8a9a5SSteve French } else { 60338c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* file? */ 60438c8a9a5SSteve French fattr->cf_dtype = DT_REG; 60538c8a9a5SSteve French rc = -EOPNOTSUPP; 60638c8a9a5SSteve French } 60738c8a9a5SSteve French } else { 60838c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* then it is a file */ 60938c8a9a5SSteve French fattr->cf_dtype = DT_REG; 61038c8a9a5SSteve French rc = -EOPNOTSUPP; /* or some unknown SFU type */ 61138c8a9a5SSteve French } 61238c8a9a5SSteve French 61338c8a9a5SSteve French tcon->ses->server->ops->close(xid, tcon, &fid); 61438c8a9a5SSteve French cifs_put_tlink(tlink); 61538c8a9a5SSteve French return rc; 61638c8a9a5SSteve French } 61738c8a9a5SSteve French 61838c8a9a5SSteve French #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ 61938c8a9a5SSteve French 62038c8a9a5SSteve French /* 62138c8a9a5SSteve French * Fetch mode bits as provided by SFU. 62238c8a9a5SSteve French * 62338c8a9a5SSteve French * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? 62438c8a9a5SSteve French */ 62538c8a9a5SSteve French static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, 62638c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 62738c8a9a5SSteve French { 62838c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR 62938c8a9a5SSteve French ssize_t rc; 63038c8a9a5SSteve French char ea_value[4]; 63138c8a9a5SSteve French __u32 mode; 63238c8a9a5SSteve French struct tcon_link *tlink; 63338c8a9a5SSteve French struct cifs_tcon *tcon; 63438c8a9a5SSteve French 63538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 63638c8a9a5SSteve French if (IS_ERR(tlink)) 63738c8a9a5SSteve French return PTR_ERR(tlink); 63838c8a9a5SSteve French tcon = tlink_tcon(tlink); 63938c8a9a5SSteve French 64038c8a9a5SSteve French if (tcon->ses->server->ops->query_all_EAs == NULL) { 64138c8a9a5SSteve French cifs_put_tlink(tlink); 64238c8a9a5SSteve French return -EOPNOTSUPP; 64338c8a9a5SSteve French } 64438c8a9a5SSteve French 64538c8a9a5SSteve French rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, 64638c8a9a5SSteve French "SETFILEBITS", ea_value, 4 /* size of buf */, 64738c8a9a5SSteve French cifs_sb); 64838c8a9a5SSteve French cifs_put_tlink(tlink); 64938c8a9a5SSteve French if (rc < 0) 65038c8a9a5SSteve French return (int)rc; 65138c8a9a5SSteve French else if (rc > 3) { 65238c8a9a5SSteve French mode = le32_to_cpu(*((__le32 *)ea_value)); 65338c8a9a5SSteve French fattr->cf_mode &= ~SFBITS_MASK; 65438c8a9a5SSteve French cifs_dbg(FYI, "special bits 0%o org mode 0%o\n", 65538c8a9a5SSteve French mode, fattr->cf_mode); 65638c8a9a5SSteve French fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; 65738c8a9a5SSteve French cifs_dbg(FYI, "special mode bits 0%o\n", mode); 65838c8a9a5SSteve French } 65938c8a9a5SSteve French 66038c8a9a5SSteve French return 0; 66138c8a9a5SSteve French #else 66238c8a9a5SSteve French return -EOPNOTSUPP; 66338c8a9a5SSteve French #endif 66438c8a9a5SSteve French } 66538c8a9a5SSteve French 66638c8a9a5SSteve French /* Fill a cifs_fattr struct with info from POSIX info struct */ 6678b4e285dSPaulo Alcantara static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 6688b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 66938c8a9a5SSteve French struct cifs_sid *owner, 67038c8a9a5SSteve French struct cifs_sid *group, 6718b4e285dSPaulo Alcantara struct super_block *sb) 67238c8a9a5SSteve French { 67338c8a9a5SSteve French struct smb311_posix_qinfo *info = &data->posix_fi; 67438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 67538c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 67638c8a9a5SSteve French 67738c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 67838c8a9a5SSteve French 67938c8a9a5SSteve French /* no fattr->flags to set */ 68038c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); 68138c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->Inode); 68238c8a9a5SSteve French 68338c8a9a5SSteve French if (info->LastAccessTime) 68438c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 68538c8a9a5SSteve French else 68638c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 68738c8a9a5SSteve French 68838c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 68938c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 69038c8a9a5SSteve French 6918b4e285dSPaulo Alcantara if (data->adjust_tz) { 69238c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 69338c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 69438c8a9a5SSteve French } 69538c8a9a5SSteve French 69638c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 69738c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 69838c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 69938c8a9a5SSteve French 70038c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->HardLinks); 70138c8a9a5SSteve French fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); 70238c8a9a5SSteve French /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ 70338c8a9a5SSteve French /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ 70438c8a9a5SSteve French 7058b4e285dSPaulo Alcantara if (data->symlink) { 70638c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 70738c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 70838c8a9a5SSteve French fattr->cf_symlink_target = data->symlink_target; 70938c8a9a5SSteve French data->symlink_target = NULL; 71038c8a9a5SSteve French } else 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 /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ 71838c8a9a5SSteve French 71938c8a9a5SSteve French sid_to_id(cifs_sb, owner, fattr, SIDOWNER); 72038c8a9a5SSteve French sid_to_id(cifs_sb, group, fattr, SIDGROUP); 72138c8a9a5SSteve French 72238c8a9a5SSteve French cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", 72338c8a9a5SSteve French fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 72438c8a9a5SSteve French } 72538c8a9a5SSteve French 726df32e887SPaulo Alcantara static inline dev_t nfs_mkdev(struct reparse_posix_data *buf) 727df32e887SPaulo Alcantara { 728df32e887SPaulo Alcantara u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer); 729df32e887SPaulo Alcantara 730df32e887SPaulo Alcantara return MKDEV(v >> 32, v & 0xffffffff); 731df32e887SPaulo Alcantara } 732df32e887SPaulo Alcantara 7335f71ebc4SPaulo Alcantara bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 7345f71ebc4SPaulo Alcantara struct cifs_fattr *fattr, 735df32e887SPaulo Alcantara struct cifs_open_info_data *data) 7365f71ebc4SPaulo Alcantara { 737df32e887SPaulo Alcantara struct reparse_posix_data *buf = data->reparse.posix; 738df32e887SPaulo Alcantara u32 tag = data->reparse.tag; 739df32e887SPaulo Alcantara 740df32e887SPaulo Alcantara if (tag == IO_REPARSE_TAG_NFS && buf) { 741df32e887SPaulo Alcantara switch (le64_to_cpu(buf->InodeType)) { 742df32e887SPaulo Alcantara case NFS_SPECFILE_CHR: 743df32e887SPaulo Alcantara fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 744df32e887SPaulo Alcantara fattr->cf_dtype = DT_CHR; 745df32e887SPaulo Alcantara fattr->cf_rdev = nfs_mkdev(buf); 746df32e887SPaulo Alcantara break; 747df32e887SPaulo Alcantara case NFS_SPECFILE_BLK: 748df32e887SPaulo Alcantara fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 749df32e887SPaulo Alcantara fattr->cf_dtype = DT_BLK; 750df32e887SPaulo Alcantara fattr->cf_rdev = nfs_mkdev(buf); 751df32e887SPaulo Alcantara break; 752df32e887SPaulo Alcantara case NFS_SPECFILE_FIFO: 753df32e887SPaulo Alcantara fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 754df32e887SPaulo Alcantara fattr->cf_dtype = DT_FIFO; 755df32e887SPaulo Alcantara break; 756df32e887SPaulo Alcantara case NFS_SPECFILE_SOCK: 757df32e887SPaulo Alcantara fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 758df32e887SPaulo Alcantara fattr->cf_dtype = DT_SOCK; 759df32e887SPaulo Alcantara break; 760df32e887SPaulo Alcantara case NFS_SPECFILE_LNK: 761df32e887SPaulo Alcantara fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; 762df32e887SPaulo Alcantara fattr->cf_dtype = DT_LNK; 763df32e887SPaulo Alcantara break; 764df32e887SPaulo Alcantara default: 765df32e887SPaulo Alcantara WARN_ON_ONCE(1); 766df32e887SPaulo Alcantara return false; 767df32e887SPaulo Alcantara } 768df32e887SPaulo Alcantara return true; 769df32e887SPaulo Alcantara } 770df32e887SPaulo Alcantara 7715f71ebc4SPaulo Alcantara switch (tag) { 7725f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_SYMLINK: 7735f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; 7745f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_LNK; 7755f71ebc4SPaulo Alcantara break; 7765f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_FIFO: 7775f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 7785f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_FIFO; 7795f71ebc4SPaulo Alcantara break; 7805f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_AF_UNIX: 7815f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 7825f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_SOCK; 7835f71ebc4SPaulo Alcantara break; 7845f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_CHR: 7855f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 7865f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_CHR; 7875f71ebc4SPaulo Alcantara break; 7885f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_BLK: 7895f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 7905f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_BLK; 7915f71ebc4SPaulo Alcantara break; 7925f71ebc4SPaulo Alcantara case 0: /* SMB1 symlink */ 7935f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_SYMLINK: 7945f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_NFS: 795b6abe338SPaulo Alcantara fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; 7965f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_LNK; 7975f71ebc4SPaulo Alcantara break; 7985f71ebc4SPaulo Alcantara default: 7995f71ebc4SPaulo Alcantara return false; 8005f71ebc4SPaulo Alcantara } 8015f71ebc4SPaulo Alcantara return true; 8025f71ebc4SPaulo Alcantara } 8035f71ebc4SPaulo Alcantara 8048b4e285dSPaulo Alcantara static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, 8058b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 8068b4e285dSPaulo Alcantara struct super_block *sb) 80738c8a9a5SSteve French { 80838c8a9a5SSteve French struct smb2_file_all_info *info = &data->fi; 80938c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 81038c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 81138c8a9a5SSteve French 81238c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 81338c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); 81438c8a9a5SSteve French if (info->DeletePending) 81538c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; 81638c8a9a5SSteve French 81738c8a9a5SSteve French if (info->LastAccessTime) 81838c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 81938c8a9a5SSteve French else 82038c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 82138c8a9a5SSteve French 82238c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 82338c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 82438c8a9a5SSteve French 8258b4e285dSPaulo Alcantara if (data->adjust_tz) { 82638c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 82738c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 82838c8a9a5SSteve French } 82938c8a9a5SSteve French 83038c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 83138c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 83238c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 83338c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 8345f71ebc4SPaulo Alcantara 8355f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data) && 836df32e887SPaulo Alcantara cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) 8375f71ebc4SPaulo Alcantara goto out_reparse; 8385f71ebc4SPaulo Alcantara 8395f71ebc4SPaulo Alcantara if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 84038c8a9a5SSteve French fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; 84138c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 84238c8a9a5SSteve French /* 84338c8a9a5SSteve French * Server can return wrong NumberOfLinks value for directories 84438c8a9a5SSteve French * when Unix extensions are disabled - fake it. 84538c8a9a5SSteve French */ 84638c8a9a5SSteve French if (!tcon->unix_ext) 84738c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 84838c8a9a5SSteve French } else { 84938c8a9a5SSteve French fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; 85038c8a9a5SSteve French fattr->cf_dtype = DT_REG; 85138c8a9a5SSteve French 85238c8a9a5SSteve French /* clear write bits if ATTR_READONLY is set */ 85338c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_READONLY) 85438c8a9a5SSteve French fattr->cf_mode &= ~(S_IWUGO); 85538c8a9a5SSteve French 85638c8a9a5SSteve French /* 85738c8a9a5SSteve French * Don't accept zero nlink from non-unix servers unless 85838c8a9a5SSteve French * delete is pending. Instead mark it as unknown. 85938c8a9a5SSteve French */ 86038c8a9a5SSteve French if ((fattr->cf_nlink < 1) && !tcon->unix_ext && 86138c8a9a5SSteve French !info->DeletePending) { 86238c8a9a5SSteve French cifs_dbg(VFS, "bogus file nlink value %u\n", 86338c8a9a5SSteve French fattr->cf_nlink); 86438c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 86538c8a9a5SSteve French } 86638c8a9a5SSteve French } 86738c8a9a5SSteve French 8685f71ebc4SPaulo Alcantara out_reparse: 86938c8a9a5SSteve French if (S_ISLNK(fattr->cf_mode)) { 8701de3dbd9SPaulo Alcantara if (likely(data->symlink_target)) 8711de3dbd9SPaulo Alcantara fattr->cf_eof = strnlen(data->symlink_target, PATH_MAX); 87238c8a9a5SSteve French fattr->cf_symlink_target = data->symlink_target; 87338c8a9a5SSteve French data->symlink_target = NULL; 87438c8a9a5SSteve French } 87538c8a9a5SSteve French 87638c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 87738c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 87838c8a9a5SSteve French } 87938c8a9a5SSteve French 88038c8a9a5SSteve French static int 88138c8a9a5SSteve French cifs_get_file_info(struct file *filp) 88238c8a9a5SSteve French { 88338c8a9a5SSteve French int rc; 88438c8a9a5SSteve French unsigned int xid; 88538c8a9a5SSteve French struct cifs_open_info_data data = {}; 88638c8a9a5SSteve French struct cifs_fattr fattr; 88738c8a9a5SSteve French struct inode *inode = file_inode(filp); 88838c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 88938c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 89038c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 89138c8a9a5SSteve French 89238c8a9a5SSteve French if (!server->ops->query_file_info) 89338c8a9a5SSteve French return -ENOSYS; 89438c8a9a5SSteve French 89538c8a9a5SSteve French xid = get_xid(); 89638c8a9a5SSteve French rc = server->ops->query_file_info(xid, tcon, cfile, &data); 89738c8a9a5SSteve French switch (rc) { 89838c8a9a5SSteve French case 0: 89938c8a9a5SSteve French /* TODO: add support to query reparse tag */ 9008b4e285dSPaulo Alcantara data.adjust_tz = false; 90138c8a9a5SSteve French if (data.symlink_target) { 9028b4e285dSPaulo Alcantara data.symlink = true; 903df32e887SPaulo Alcantara data.reparse.tag = IO_REPARSE_TAG_SYMLINK; 90438c8a9a5SSteve French } 9058b4e285dSPaulo Alcantara cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); 90638c8a9a5SSteve French break; 90738c8a9a5SSteve French case -EREMOTE: 908a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 90938c8a9a5SSteve French rc = 0; 91038c8a9a5SSteve French break; 91138c8a9a5SSteve French case -EOPNOTSUPP: 91238c8a9a5SSteve French case -EINVAL: 91338c8a9a5SSteve French /* 91438c8a9a5SSteve French * FIXME: legacy server -- fall back to path-based call? 91538c8a9a5SSteve French * for now, just skip revalidating and mark inode for 91638c8a9a5SSteve French * immediate reval. 91738c8a9a5SSteve French */ 91838c8a9a5SSteve French rc = 0; 91938c8a9a5SSteve French CIFS_I(inode)->time = 0; 92038c8a9a5SSteve French goto cgfi_exit; 92138c8a9a5SSteve French default: 92238c8a9a5SSteve French goto cgfi_exit; 92338c8a9a5SSteve French } 92438c8a9a5SSteve French 92538c8a9a5SSteve French /* 92638c8a9a5SSteve French * don't bother with SFU junk here -- just mark inode as needing 92738c8a9a5SSteve French * revalidation. 92838c8a9a5SSteve French */ 92938c8a9a5SSteve French fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; 93038c8a9a5SSteve French fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; 93138c8a9a5SSteve French /* if filetype is different, return error */ 9329179aa27SBharath SM rc = cifs_fattr_to_inode(inode, &fattr, false); 93338c8a9a5SSteve French cgfi_exit: 93438c8a9a5SSteve French cifs_free_open_info(&data); 93538c8a9a5SSteve French free_xid(xid); 93638c8a9a5SSteve French return rc; 93738c8a9a5SSteve French } 93838c8a9a5SSteve French 93938c8a9a5SSteve French /* Simple function to return a 64 bit hash of string. Rarely called */ 94038c8a9a5SSteve French static __u64 simple_hashstr(const char *str) 94138c8a9a5SSteve French { 94238c8a9a5SSteve French const __u64 hash_mult = 1125899906842597ULL; /* a big enough prime */ 94338c8a9a5SSteve French __u64 hash = 0; 94438c8a9a5SSteve French 94538c8a9a5SSteve French while (*str) 94638c8a9a5SSteve French hash = (hash + (__u64) *str++) * hash_mult; 94738c8a9a5SSteve French 94838c8a9a5SSteve French return hash; 94938c8a9a5SSteve French } 95038c8a9a5SSteve French 95138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 95238c8a9a5SSteve French /** 95338c8a9a5SSteve French * cifs_backup_query_path_info - SMB1 fallback code to get ino 95438c8a9a5SSteve French * 95538c8a9a5SSteve French * Fallback code to get file metadata when we don't have access to 95638c8a9a5SSteve French * full_path (EACCES) and have backup creds. 95738c8a9a5SSteve French * 95838c8a9a5SSteve French * @xid: transaction id used to identify original request in logs 95938c8a9a5SSteve French * @tcon: information about the server share we have mounted 96038c8a9a5SSteve French * @sb: the superblock stores info such as disk space available 96138c8a9a5SSteve French * @full_path: name of the file we are getting the metadata for 96238c8a9a5SSteve French * @resp_buf: will be set to cifs resp buf and needs to be freed with 96338c8a9a5SSteve French * cifs_buf_release() when done with @data 96438c8a9a5SSteve French * @data: will be set to search info result buffer 96538c8a9a5SSteve French */ 96638c8a9a5SSteve French static int 96738c8a9a5SSteve French cifs_backup_query_path_info(int xid, 96838c8a9a5SSteve French struct cifs_tcon *tcon, 96938c8a9a5SSteve French struct super_block *sb, 97038c8a9a5SSteve French const char *full_path, 97138c8a9a5SSteve French void **resp_buf, 97238c8a9a5SSteve French FILE_ALL_INFO **data) 97338c8a9a5SSteve French { 97438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 97538c8a9a5SSteve French struct cifs_search_info info = {0}; 97638c8a9a5SSteve French u16 flags; 97738c8a9a5SSteve French int rc; 97838c8a9a5SSteve French 97938c8a9a5SSteve French *resp_buf = NULL; 98038c8a9a5SSteve French info.endOfSearch = false; 98138c8a9a5SSteve French if (tcon->unix_ext) 98238c8a9a5SSteve French info.info_level = SMB_FIND_FILE_UNIX; 98338c8a9a5SSteve French else if ((tcon->ses->capabilities & 98438c8a9a5SSteve French tcon->ses->server->vals->cap_nt_find) == 0) 98538c8a9a5SSteve French info.info_level = SMB_FIND_FILE_INFO_STANDARD; 98638c8a9a5SSteve French else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 98738c8a9a5SSteve French info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 98838c8a9a5SSteve French else /* no srvino useful for fallback to some netapp */ 98938c8a9a5SSteve French info.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 99038c8a9a5SSteve French 99138c8a9a5SSteve French flags = CIFS_SEARCH_CLOSE_ALWAYS | 99238c8a9a5SSteve French CIFS_SEARCH_CLOSE_AT_END | 99338c8a9a5SSteve French CIFS_SEARCH_BACKUP_SEARCH; 99438c8a9a5SSteve French 99538c8a9a5SSteve French rc = CIFSFindFirst(xid, tcon, full_path, 99638c8a9a5SSteve French cifs_sb, NULL, flags, &info, false); 99738c8a9a5SSteve French if (rc) 99838c8a9a5SSteve French return rc; 99938c8a9a5SSteve French 100038c8a9a5SSteve French *resp_buf = (void *)info.ntwrk_buf_start; 100138c8a9a5SSteve French *data = (FILE_ALL_INFO *)info.srch_entries_start; 100238c8a9a5SSteve French return 0; 100338c8a9a5SSteve French } 100438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 100538c8a9a5SSteve French 100638c8a9a5SSteve French static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_block *sb, 100738c8a9a5SSteve French struct inode **inode, const char *full_path, 100838c8a9a5SSteve French struct cifs_open_info_data *data, struct cifs_fattr *fattr) 100938c8a9a5SSteve French { 101038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 101138c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 101238c8a9a5SSteve French int rc; 101338c8a9a5SSteve French 101438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 101538c8a9a5SSteve French if (*inode) 101638c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 101738c8a9a5SSteve French else 101838c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 101938c8a9a5SSteve French return; 102038c8a9a5SSteve French } 102138c8a9a5SSteve French 102238c8a9a5SSteve French /* 102338c8a9a5SSteve French * If we have an inode pass a NULL tcon to ensure we don't 102438c8a9a5SSteve French * make a round trip to the server. This only works for SMB2+. 102538c8a9a5SSteve French */ 102638c8a9a5SSteve French rc = server->ops->get_srv_inum(xid, *inode ? NULL : tcon, cifs_sb, full_path, 102738c8a9a5SSteve French &fattr->cf_uniqueid, data); 102838c8a9a5SSteve French if (rc) { 102938c8a9a5SSteve French /* 103038c8a9a5SSteve French * If that fails reuse existing ino or generate one 103138c8a9a5SSteve French * and disable server ones 103238c8a9a5SSteve French */ 103338c8a9a5SSteve French if (*inode) 103438c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 103538c8a9a5SSteve French else { 103638c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 103738c8a9a5SSteve French cifs_autodisable_serverino(cifs_sb); 103838c8a9a5SSteve French } 103938c8a9a5SSteve French return; 104038c8a9a5SSteve French } 104138c8a9a5SSteve French 104238c8a9a5SSteve French /* If no errors, check for zero root inode (invalid) */ 104338c8a9a5SSteve French if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) { 104438c8a9a5SSteve French cifs_dbg(FYI, "Invalid (0) inodenum\n"); 104538c8a9a5SSteve French if (*inode) { 104638c8a9a5SSteve French /* reuse */ 104738c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 104838c8a9a5SSteve French } else { 104938c8a9a5SSteve French /* make an ino by hashing the UNC */ 105038c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO; 105138c8a9a5SSteve French fattr->cf_uniqueid = simple_hashstr(tcon->tree_name); 105238c8a9a5SSteve French } 105338c8a9a5SSteve French } 105438c8a9a5SSteve French } 105538c8a9a5SSteve French 105638c8a9a5SSteve French static inline bool is_inode_cache_good(struct inode *ino) 105738c8a9a5SSteve French { 105838c8a9a5SSteve French return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0; 105938c8a9a5SSteve French } 106038c8a9a5SSteve French 1061a18280e7SPaulo Alcantara static int reparse_info_to_fattr(struct cifs_open_info_data *data, 10625f71ebc4SPaulo Alcantara struct super_block *sb, 10635f71ebc4SPaulo Alcantara const unsigned int xid, 10645f71ebc4SPaulo Alcantara struct cifs_tcon *tcon, 10655f71ebc4SPaulo Alcantara const char *full_path, 106602bcf865SSteve French struct cifs_fattr *fattr, 106702bcf865SSteve French struct cifs_sid *owner, 106802bcf865SSteve French struct cifs_sid *group) 106938c8a9a5SSteve French { 10705f71ebc4SPaulo Alcantara struct TCP_Server_Info *server = tcon->ses->server; 10715f71ebc4SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 10729a49e221SPaulo Alcantara struct kvec rsp_iov, *iov = NULL; 10739a49e221SPaulo Alcantara int rsp_buftype = CIFS_NO_BUFFER; 1074df32e887SPaulo Alcantara u32 tag = data->reparse.tag; 10755f71ebc4SPaulo Alcantara int rc = 0; 10765f71ebc4SPaulo Alcantara 10779a49e221SPaulo Alcantara if (!tag && server->ops->query_reparse_point) { 10789a49e221SPaulo Alcantara rc = server->ops->query_reparse_point(xid, tcon, cifs_sb, 10799a49e221SPaulo Alcantara full_path, &tag, 10809a49e221SPaulo Alcantara &rsp_iov, &rsp_buftype); 10819a49e221SPaulo Alcantara if (!rc) 10829a49e221SPaulo Alcantara iov = &rsp_iov; 10835f71ebc4SPaulo Alcantara } 10844d07e5dfSPaulo Alcantara 10854d07e5dfSPaulo Alcantara rc = -EOPNOTSUPP; 1086df32e887SPaulo Alcantara switch ((data->reparse.tag = tag)) { 10875f71ebc4SPaulo Alcantara case 0: /* SMB1 symlink */ 10884d07e5dfSPaulo Alcantara if (server->ops->query_symlink) { 10895f71ebc4SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 10905f71ebc4SPaulo Alcantara cifs_sb, full_path, 10914d07e5dfSPaulo Alcantara &data->symlink_target); 10925f71ebc4SPaulo Alcantara } 10935f71ebc4SPaulo Alcantara break; 1094a18280e7SPaulo Alcantara case IO_REPARSE_TAG_MOUNT_POINT: 1095a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 10964d07e5dfSPaulo Alcantara rc = 0; 1097a18280e7SPaulo Alcantara goto out; 10984d07e5dfSPaulo Alcantara default: 109902bcf865SSteve French /* Check for cached reparse point data */ 110002bcf865SSteve French if (data->symlink_target || data->reparse.buf) { 11014d07e5dfSPaulo Alcantara rc = 0; 11024d07e5dfSPaulo Alcantara } else if (server->ops->parse_reparse_point) { 11034d07e5dfSPaulo Alcantara rc = server->ops->parse_reparse_point(cifs_sb, 11044d07e5dfSPaulo Alcantara iov, data); 11054d07e5dfSPaulo Alcantara } 11064d07e5dfSPaulo Alcantara break; 11075f71ebc4SPaulo Alcantara } 1108a18280e7SPaulo Alcantara 110902bcf865SSteve French if (tcon->posix_extensions) 111002bcf865SSteve French smb311_posix_info_to_fattr(fattr, data, owner, group, sb); 111102bcf865SSteve French else 1112a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 1113a18280e7SPaulo Alcantara out: 1114b9e741acSPaulo Alcantara fattr->cf_cifstag = data->reparse.tag; 11159a49e221SPaulo Alcantara free_rsp_buf(rsp_buftype, rsp_iov.iov_base); 11165f71ebc4SPaulo Alcantara return rc; 11175f71ebc4SPaulo Alcantara } 11185f71ebc4SPaulo Alcantara 1119a18280e7SPaulo Alcantara static int cifs_get_fattr(struct cifs_open_info_data *data, 1120a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1121a18280e7SPaulo Alcantara const struct cifs_fid *fid, 1122a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 1123a18280e7SPaulo Alcantara struct inode **inode, 1124a18280e7SPaulo Alcantara const char *full_path) 112538c8a9a5SSteve French { 1126a18280e7SPaulo Alcantara struct cifs_open_info_data tmp_data = {}; 112738c8a9a5SSteve French struct cifs_tcon *tcon; 112838c8a9a5SSteve French struct TCP_Server_Info *server; 112938c8a9a5SSteve French struct tcon_link *tlink; 113038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 113138c8a9a5SSteve French void *smb1_backup_rsp_buf = NULL; 113238c8a9a5SSteve French int rc = 0; 113338c8a9a5SSteve French int tmprc = 0; 113438c8a9a5SSteve French 113538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 113638c8a9a5SSteve French if (IS_ERR(tlink)) 113738c8a9a5SSteve French return PTR_ERR(tlink); 113838c8a9a5SSteve French tcon = tlink_tcon(tlink); 113938c8a9a5SSteve French server = tcon->ses->server; 114038c8a9a5SSteve French 114138c8a9a5SSteve French /* 114238c8a9a5SSteve French * 1. Fetch file metadata if not provided (data) 114338c8a9a5SSteve French */ 114438c8a9a5SSteve French 114538c8a9a5SSteve French if (!data) { 11468b4e285dSPaulo Alcantara rc = server->ops->query_path_info(xid, tcon, cifs_sb, 11478b4e285dSPaulo Alcantara full_path, &tmp_data); 114838c8a9a5SSteve French data = &tmp_data; 114938c8a9a5SSteve French } 115038c8a9a5SSteve French 115138c8a9a5SSteve French /* 115238c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 115338c8a9a5SSteve French */ 115438c8a9a5SSteve French 115538c8a9a5SSteve French switch (rc) { 115638c8a9a5SSteve French case 0: 115738c8a9a5SSteve French /* 115838c8a9a5SSteve French * If the file is a reparse point, it is more complicated 115938c8a9a5SSteve French * since we have to check if its reparse tag matches a known 116038c8a9a5SSteve French * special file type e.g. symlink or fifo or char etc. 116138c8a9a5SSteve French */ 11625f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data)) { 1163a18280e7SPaulo Alcantara rc = reparse_info_to_fattr(data, sb, xid, tcon, 116402bcf865SSteve French full_path, fattr, 116502bcf865SSteve French NULL, NULL); 1166a18280e7SPaulo Alcantara } else { 1167a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 116838c8a9a5SSteve French } 116938c8a9a5SSteve French break; 117038c8a9a5SSteve French case -EREMOTE: 117138c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1172a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 117338c8a9a5SSteve French rc = 0; 117438c8a9a5SSteve French break; 117538c8a9a5SSteve French case -EACCES: 117638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 117738c8a9a5SSteve French /* 117838c8a9a5SSteve French * perm errors, try again with backup flags if possible 117938c8a9a5SSteve French * 118038c8a9a5SSteve French * For SMB2 and later the backup intent flag 118138c8a9a5SSteve French * is already sent if needed on open and there 118238c8a9a5SSteve French * is no path based FindFirst operation to use 118338c8a9a5SSteve French * to retry with 118438c8a9a5SSteve French */ 118538c8a9a5SSteve French if (backup_cred(cifs_sb) && is_smb1_server(server)) { 118638c8a9a5SSteve French /* for easier reading */ 118738c8a9a5SSteve French FILE_ALL_INFO *fi; 118838c8a9a5SSteve French FILE_DIRECTORY_INFO *fdi; 118938c8a9a5SSteve French SEARCH_ID_FULL_DIR_INFO *si; 119038c8a9a5SSteve French 119138c8a9a5SSteve French rc = cifs_backup_query_path_info(xid, tcon, sb, 119238c8a9a5SSteve French full_path, 119338c8a9a5SSteve French &smb1_backup_rsp_buf, 119438c8a9a5SSteve French &fi); 119538c8a9a5SSteve French if (rc) 119638c8a9a5SSteve French goto out; 119738c8a9a5SSteve French 119838c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, fi); 119938c8a9a5SSteve French fdi = (FILE_DIRECTORY_INFO *)fi; 120038c8a9a5SSteve French si = (SEARCH_ID_FULL_DIR_INFO *)fi; 120138c8a9a5SSteve French 1202a18280e7SPaulo Alcantara cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); 1203a18280e7SPaulo Alcantara fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); 120438c8a9a5SSteve French /* uniqueid set, skip get inum step */ 120538c8a9a5SSteve French goto handle_mnt_opt; 120638c8a9a5SSteve French } else { 120738c8a9a5SSteve French /* nothing we can do, bail out */ 120838c8a9a5SSteve French goto out; 120938c8a9a5SSteve French } 121038c8a9a5SSteve French #else 121138c8a9a5SSteve French goto out; 121238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 121338c8a9a5SSteve French break; 121438c8a9a5SSteve French default: 121538c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 121638c8a9a5SSteve French goto out; 121738c8a9a5SSteve French } 121838c8a9a5SSteve French 121938c8a9a5SSteve French /* 1220a18280e7SPaulo Alcantara * 3. Get or update inode number (fattr->cf_uniqueid) 122138c8a9a5SSteve French */ 122238c8a9a5SSteve French 1223a18280e7SPaulo Alcantara cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr); 122438c8a9a5SSteve French 122538c8a9a5SSteve French /* 122638c8a9a5SSteve French * 4. Tweak fattr based on mount options 122738c8a9a5SSteve French */ 122838c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 122938c8a9a5SSteve French handle_mnt_opt: 123038c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 123138c8a9a5SSteve French /* query for SFU type info if supported and needed */ 1232a18280e7SPaulo Alcantara if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && 1233a18280e7SPaulo Alcantara (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { 1234a18280e7SPaulo Alcantara tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid); 123538c8a9a5SSteve French if (tmprc) 123638c8a9a5SSteve French cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); 123738c8a9a5SSteve French } 123838c8a9a5SSteve French 123938c8a9a5SSteve French /* fill in 0777 bits from ACL */ 124038c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { 1241a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1242a18280e7SPaulo Alcantara true, full_path, fid); 124338c8a9a5SSteve French if (rc == -EREMOTE) 124438c8a9a5SSteve French rc = 0; 124538c8a9a5SSteve French if (rc) { 124638c8a9a5SSteve French cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n", 124738c8a9a5SSteve French __func__, rc); 124838c8a9a5SSteve French goto out; 124938c8a9a5SSteve French } 125038c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 1251a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1252a18280e7SPaulo Alcantara false, full_path, fid); 125338c8a9a5SSteve French if (rc == -EREMOTE) 125438c8a9a5SSteve French rc = 0; 125538c8a9a5SSteve French if (rc) { 125638c8a9a5SSteve French cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n", 125738c8a9a5SSteve French __func__, rc); 125838c8a9a5SSteve French goto out; 125938c8a9a5SSteve French } 126038c8a9a5SSteve French } 126138c8a9a5SSteve French 126238c8a9a5SSteve French /* fill in remaining high mode bits e.g. SUID, VTX */ 126338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) 1264a18280e7SPaulo Alcantara cifs_sfu_mode(fattr, full_path, cifs_sb, xid); 126538c8a9a5SSteve French 126638c8a9a5SSteve French /* check for Minshall+French symlinks */ 126738c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1268a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 126938c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 127038c8a9a5SSteve French } 127138c8a9a5SSteve French 127238c8a9a5SSteve French out: 127338c8a9a5SSteve French cifs_buf_release(smb1_backup_rsp_buf); 127438c8a9a5SSteve French cifs_put_tlink(tlink); 127538c8a9a5SSteve French cifs_free_open_info(&tmp_data); 1276a18280e7SPaulo Alcantara return rc; 1277a18280e7SPaulo Alcantara } 1278a18280e7SPaulo Alcantara 1279a18280e7SPaulo Alcantara int cifs_get_inode_info(struct inode **inode, 1280a18280e7SPaulo Alcantara const char *full_path, 1281a18280e7SPaulo Alcantara struct cifs_open_info_data *data, 1282a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1283a18280e7SPaulo Alcantara const struct cifs_fid *fid) 1284a18280e7SPaulo Alcantara { 1285a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1286a18280e7SPaulo Alcantara int rc; 1287a18280e7SPaulo Alcantara 1288a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1289a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1290a18280e7SPaulo Alcantara return 0; 1291a18280e7SPaulo Alcantara } 1292a18280e7SPaulo Alcantara 1293a18280e7SPaulo Alcantara rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path); 1294a18280e7SPaulo Alcantara if (rc) 1295a18280e7SPaulo Alcantara goto out; 1296a18280e7SPaulo Alcantara 1297a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 1298a18280e7SPaulo Alcantara out: 129938c8a9a5SSteve French kfree(fattr.cf_symlink_target); 130038c8a9a5SSteve French return rc; 130138c8a9a5SSteve French } 130238c8a9a5SSteve French 130302bcf865SSteve French static int smb311_posix_get_fattr(struct cifs_open_info_data *data, 130402bcf865SSteve French struct cifs_fattr *fattr, 130538c8a9a5SSteve French const char *full_path, 1306a18280e7SPaulo Alcantara struct super_block *sb, 1307a18280e7SPaulo Alcantara const unsigned int xid) 130838c8a9a5SSteve French { 130902bcf865SSteve French struct cifs_open_info_data tmp_data = {}; 1310a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 131138c8a9a5SSteve French struct cifs_tcon *tcon; 131238c8a9a5SSteve French struct tcon_link *tlink; 131338c8a9a5SSteve French struct cifs_sid owner, group; 1314a18280e7SPaulo Alcantara int tmprc; 131502bcf865SSteve French int rc = 0; 131638c8a9a5SSteve French 131738c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 131838c8a9a5SSteve French if (IS_ERR(tlink)) 131938c8a9a5SSteve French return PTR_ERR(tlink); 132038c8a9a5SSteve French tcon = tlink_tcon(tlink); 132138c8a9a5SSteve French 132238c8a9a5SSteve French /* 132302bcf865SSteve French * 1. Fetch file metadata if not provided (data) 132438c8a9a5SSteve French */ 132502bcf865SSteve French if (!data) { 13268b4e285dSPaulo Alcantara rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, 132702bcf865SSteve French full_path, &tmp_data, 13288b4e285dSPaulo Alcantara &owner, &group); 132902bcf865SSteve French data = &tmp_data; 133002bcf865SSteve French } 133138c8a9a5SSteve French 133238c8a9a5SSteve French /* 133338c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 133438c8a9a5SSteve French */ 133538c8a9a5SSteve French 133638c8a9a5SSteve French switch (rc) { 133738c8a9a5SSteve French case 0: 133802bcf865SSteve French if (cifs_open_data_reparse(data)) { 133902bcf865SSteve French rc = reparse_info_to_fattr(data, sb, xid, tcon, 134002bcf865SSteve French full_path, fattr, 134102bcf865SSteve French &owner, &group); 134202bcf865SSteve French } else { 134302bcf865SSteve French smb311_posix_info_to_fattr(fattr, data, 134402bcf865SSteve French &owner, &group, sb); 134502bcf865SSteve French } 134638c8a9a5SSteve French break; 134738c8a9a5SSteve French case -EREMOTE: 134838c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1349a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 135038c8a9a5SSteve French rc = 0; 135138c8a9a5SSteve French break; 135238c8a9a5SSteve French case -EACCES: 135338c8a9a5SSteve French /* 135438c8a9a5SSteve French * For SMB2 and later the backup intent flag 135538c8a9a5SSteve French * is already sent if needed on open and there 135638c8a9a5SSteve French * is no path based FindFirst operation to use 135738c8a9a5SSteve French * to retry with so nothing we can do, bail out 135838c8a9a5SSteve French */ 135938c8a9a5SSteve French goto out; 136038c8a9a5SSteve French default: 136138c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 136238c8a9a5SSteve French goto out; 136338c8a9a5SSteve French } 136438c8a9a5SSteve French 136538c8a9a5SSteve French /* 136638c8a9a5SSteve French * 3. Tweak fattr based on mount options 136738c8a9a5SSteve French */ 136838c8a9a5SSteve French /* check for Minshall+French symlinks */ 136938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1370a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 137138c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 137238c8a9a5SSteve French } 137338c8a9a5SSteve French 137438c8a9a5SSteve French out: 137538c8a9a5SSteve French cifs_put_tlink(tlink); 137602bcf865SSteve French cifs_free_open_info(data); 137738c8a9a5SSteve French return rc; 137838c8a9a5SSteve French } 137938c8a9a5SSteve French 138002bcf865SSteve French int smb311_posix_get_inode_info(struct inode **inode, 138102bcf865SSteve French const char *full_path, 138202bcf865SSteve French struct cifs_open_info_data *data, 138302bcf865SSteve French struct super_block *sb, 138402bcf865SSteve French const unsigned int xid) 1385a18280e7SPaulo Alcantara { 1386a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1387a18280e7SPaulo Alcantara int rc; 1388a18280e7SPaulo Alcantara 1389a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1390a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1391a18280e7SPaulo Alcantara return 0; 1392a18280e7SPaulo Alcantara } 1393a18280e7SPaulo Alcantara 139402bcf865SSteve French rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid); 1395a18280e7SPaulo Alcantara if (rc) 1396a18280e7SPaulo Alcantara goto out; 1397a18280e7SPaulo Alcantara 1398a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 1399a18280e7SPaulo Alcantara out: 1400a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 1401a18280e7SPaulo Alcantara return rc; 1402a18280e7SPaulo Alcantara } 140338c8a9a5SSteve French 140438c8a9a5SSteve French static const struct inode_operations cifs_ipc_inode_ops = { 140538c8a9a5SSteve French .lookup = cifs_lookup, 140638c8a9a5SSteve French }; 140738c8a9a5SSteve French 140838c8a9a5SSteve French static int 140938c8a9a5SSteve French cifs_find_inode(struct inode *inode, void *opaque) 141038c8a9a5SSteve French { 141138c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 141238c8a9a5SSteve French 1413614bc8c7SDavid Howells /* [!] The compared values must be the same in struct cifs_fscache_inode_key. */ 1414614bc8c7SDavid Howells 141538c8a9a5SSteve French /* don't match inode with different uniqueid */ 141638c8a9a5SSteve French if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) 141738c8a9a5SSteve French return 0; 141838c8a9a5SSteve French 141938c8a9a5SSteve French /* use createtime like an i_generation field */ 142038c8a9a5SSteve French if (CIFS_I(inode)->createtime != fattr->cf_createtime) 142138c8a9a5SSteve French return 0; 142238c8a9a5SSteve French 142338c8a9a5SSteve French /* don't match inode of different type */ 142438c8a9a5SSteve French if (inode_wrong_type(inode, fattr->cf_mode)) 142538c8a9a5SSteve French return 0; 142638c8a9a5SSteve French 142738c8a9a5SSteve French /* if it's not a directory or has no dentries, then flag it */ 142838c8a9a5SSteve French if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) 142938c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; 143038c8a9a5SSteve French 143138c8a9a5SSteve French return 1; 143238c8a9a5SSteve French } 143338c8a9a5SSteve French 143438c8a9a5SSteve French static int 143538c8a9a5SSteve French cifs_init_inode(struct inode *inode, void *opaque) 143638c8a9a5SSteve French { 143738c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 143838c8a9a5SSteve French 143938c8a9a5SSteve French CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; 144038c8a9a5SSteve French CIFS_I(inode)->createtime = fattr->cf_createtime; 144138c8a9a5SSteve French return 0; 144238c8a9a5SSteve French } 144338c8a9a5SSteve French 144438c8a9a5SSteve French /* 144538c8a9a5SSteve French * walk dentry list for an inode and report whether it has aliases that 144638c8a9a5SSteve French * are hashed. We use this to determine if a directory inode can actually 144738c8a9a5SSteve French * be used. 144838c8a9a5SSteve French */ 144938c8a9a5SSteve French static bool 145038c8a9a5SSteve French inode_has_hashed_dentries(struct inode *inode) 145138c8a9a5SSteve French { 145238c8a9a5SSteve French struct dentry *dentry; 145338c8a9a5SSteve French 145438c8a9a5SSteve French spin_lock(&inode->i_lock); 145538c8a9a5SSteve French hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { 145638c8a9a5SSteve French if (!d_unhashed(dentry) || IS_ROOT(dentry)) { 145738c8a9a5SSteve French spin_unlock(&inode->i_lock); 145838c8a9a5SSteve French return true; 145938c8a9a5SSteve French } 146038c8a9a5SSteve French } 146138c8a9a5SSteve French spin_unlock(&inode->i_lock); 146238c8a9a5SSteve French return false; 146338c8a9a5SSteve French } 146438c8a9a5SSteve French 146538c8a9a5SSteve French /* Given fattrs, get a corresponding inode */ 146638c8a9a5SSteve French struct inode * 146738c8a9a5SSteve French cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) 146838c8a9a5SSteve French { 146938c8a9a5SSteve French unsigned long hash; 147038c8a9a5SSteve French struct inode *inode; 147138c8a9a5SSteve French 147238c8a9a5SSteve French retry_iget5_locked: 147338c8a9a5SSteve French cifs_dbg(FYI, "looking for uniqueid=%llu\n", fattr->cf_uniqueid); 147438c8a9a5SSteve French 147538c8a9a5SSteve French /* hash down to 32-bits on 32-bit arch */ 147638c8a9a5SSteve French hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); 147738c8a9a5SSteve French 147838c8a9a5SSteve French inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); 147938c8a9a5SSteve French if (inode) { 148038c8a9a5SSteve French /* was there a potentially problematic inode collision? */ 148138c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { 148238c8a9a5SSteve French fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; 148338c8a9a5SSteve French 148438c8a9a5SSteve French if (inode_has_hashed_dentries(inode)) { 148538c8a9a5SSteve French cifs_autodisable_serverino(CIFS_SB(sb)); 148638c8a9a5SSteve French iput(inode); 148738c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 148838c8a9a5SSteve French goto retry_iget5_locked; 148938c8a9a5SSteve French } 149038c8a9a5SSteve French } 149138c8a9a5SSteve French 149238c8a9a5SSteve French /* can't fail - see cifs_find_inode() */ 14939179aa27SBharath SM cifs_fattr_to_inode(inode, fattr, false); 149438c8a9a5SSteve French if (sb->s_flags & SB_NOATIME) 149538c8a9a5SSteve French inode->i_flags |= S_NOATIME | S_NOCMTIME; 149638c8a9a5SSteve French if (inode->i_state & I_NEW) { 149738c8a9a5SSteve French inode->i_ino = hash; 149838c8a9a5SSteve French cifs_fscache_get_inode_cookie(inode); 149938c8a9a5SSteve French unlock_new_inode(inode); 150038c8a9a5SSteve French } 150138c8a9a5SSteve French } 150238c8a9a5SSteve French 150338c8a9a5SSteve French return inode; 150438c8a9a5SSteve French } 150538c8a9a5SSteve French 150638c8a9a5SSteve French /* gets root inode */ 150738c8a9a5SSteve French struct inode *cifs_root_iget(struct super_block *sb) 150838c8a9a5SSteve French { 150938c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1510a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 151138c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1512a18280e7SPaulo Alcantara struct inode *inode = NULL; 1513a18280e7SPaulo Alcantara unsigned int xid; 151438c8a9a5SSteve French char *path = NULL; 151538c8a9a5SSteve French int len; 1516a18280e7SPaulo Alcantara int rc; 151738c8a9a5SSteve French 151838c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 151938c8a9a5SSteve French && cifs_sb->prepath) { 152038c8a9a5SSteve French len = strlen(cifs_sb->prepath); 152138c8a9a5SSteve French path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL); 152238c8a9a5SSteve French if (path == NULL) 152338c8a9a5SSteve French return ERR_PTR(-ENOMEM); 152438c8a9a5SSteve French path[0] = '/'; 152538c8a9a5SSteve French memcpy(path+1, cifs_sb->prepath, len); 152638c8a9a5SSteve French } else { 152738c8a9a5SSteve French path = kstrdup("", GFP_KERNEL); 152838c8a9a5SSteve French if (path == NULL) 152938c8a9a5SSteve French return ERR_PTR(-ENOMEM); 153038c8a9a5SSteve French } 153138c8a9a5SSteve French 153238c8a9a5SSteve French xid = get_xid(); 153338c8a9a5SSteve French if (tcon->unix_ext) { 1534a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid); 153538c8a9a5SSteve French /* some servers mistakenly claim POSIX support */ 153638c8a9a5SSteve French if (rc != -EOPNOTSUPP) 1537a18280e7SPaulo Alcantara goto iget_root; 153838c8a9a5SSteve French cifs_dbg(VFS, "server does not support POSIX extensions\n"); 153938c8a9a5SSteve French tcon->unix_ext = false; 154038c8a9a5SSteve French } 154138c8a9a5SSteve French 154238c8a9a5SSteve French convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); 154338c8a9a5SSteve French if (tcon->posix_extensions) 154402bcf865SSteve French rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid); 154538c8a9a5SSteve French else 1546a18280e7SPaulo Alcantara rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); 154738c8a9a5SSteve French 1548a18280e7SPaulo Alcantara iget_root: 1549a18280e7SPaulo Alcantara if (!rc) { 1550a18280e7SPaulo Alcantara if (fattr.cf_flags & CIFS_FATTR_JUNCTION) { 1551a18280e7SPaulo Alcantara fattr.cf_flags &= ~CIFS_FATTR_JUNCTION; 1552a18280e7SPaulo Alcantara cifs_autodisable_serverino(cifs_sb); 1553a18280e7SPaulo Alcantara } 1554a18280e7SPaulo Alcantara inode = cifs_iget(sb, &fattr); 1555a18280e7SPaulo Alcantara } 1556a18280e7SPaulo Alcantara 155738c8a9a5SSteve French if (!inode) { 155838c8a9a5SSteve French inode = ERR_PTR(rc); 155938c8a9a5SSteve French goto out; 156038c8a9a5SSteve French } 156138c8a9a5SSteve French 156238c8a9a5SSteve French if (rc && tcon->pipe) { 156338c8a9a5SSteve French cifs_dbg(FYI, "ipc connection - fake read inode\n"); 156438c8a9a5SSteve French spin_lock(&inode->i_lock); 156538c8a9a5SSteve French inode->i_mode |= S_IFDIR; 156638c8a9a5SSteve French set_nlink(inode, 2); 156738c8a9a5SSteve French inode->i_op = &cifs_ipc_inode_ops; 156838c8a9a5SSteve French inode->i_fop = &simple_dir_operations; 156938c8a9a5SSteve French inode->i_uid = cifs_sb->ctx->linux_uid; 157038c8a9a5SSteve French inode->i_gid = cifs_sb->ctx->linux_gid; 157138c8a9a5SSteve French spin_unlock(&inode->i_lock); 157238c8a9a5SSteve French } else if (rc) { 157338c8a9a5SSteve French iget_failed(inode); 157438c8a9a5SSteve French inode = ERR_PTR(rc); 157538c8a9a5SSteve French } 157638c8a9a5SSteve French 157738c8a9a5SSteve French out: 157838c8a9a5SSteve French kfree(path); 157938c8a9a5SSteve French free_xid(xid); 1580a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 158138c8a9a5SSteve French return inode; 158238c8a9a5SSteve French } 158338c8a9a5SSteve French 158438c8a9a5SSteve French int 158538c8a9a5SSteve French cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, 158638c8a9a5SSteve French const char *full_path, __u32 dosattr) 158738c8a9a5SSteve French { 158838c8a9a5SSteve French bool set_time = false; 158938c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 159038c8a9a5SSteve French struct TCP_Server_Info *server; 159138c8a9a5SSteve French FILE_BASIC_INFO info_buf; 159238c8a9a5SSteve French 159338c8a9a5SSteve French if (attrs == NULL) 159438c8a9a5SSteve French return -EINVAL; 159538c8a9a5SSteve French 159638c8a9a5SSteve French server = cifs_sb_master_tcon(cifs_sb)->ses->server; 159738c8a9a5SSteve French if (!server->ops->set_file_info) 159838c8a9a5SSteve French return -ENOSYS; 159938c8a9a5SSteve French 160038c8a9a5SSteve French info_buf.Pad = 0; 160138c8a9a5SSteve French 160238c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) { 160338c8a9a5SSteve French set_time = true; 160438c8a9a5SSteve French info_buf.LastAccessTime = 160538c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); 160638c8a9a5SSteve French } else 160738c8a9a5SSteve French info_buf.LastAccessTime = 0; 160838c8a9a5SSteve French 160938c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) { 161038c8a9a5SSteve French set_time = true; 161138c8a9a5SSteve French info_buf.LastWriteTime = 161238c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); 161338c8a9a5SSteve French } else 161438c8a9a5SSteve French info_buf.LastWriteTime = 0; 161538c8a9a5SSteve French 161638c8a9a5SSteve French /* 161738c8a9a5SSteve French * Samba throws this field away, but windows may actually use it. 161838c8a9a5SSteve French * Do not set ctime unless other time stamps are changed explicitly 161938c8a9a5SSteve French * (i.e. by utimes()) since we would then have a mix of client and 162038c8a9a5SSteve French * server times. 162138c8a9a5SSteve French */ 162238c8a9a5SSteve French if (set_time && (attrs->ia_valid & ATTR_CTIME)) { 162338c8a9a5SSteve French cifs_dbg(FYI, "CIFS - CTIME changed\n"); 162438c8a9a5SSteve French info_buf.ChangeTime = 162538c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); 162638c8a9a5SSteve French } else 162738c8a9a5SSteve French info_buf.ChangeTime = 0; 162838c8a9a5SSteve French 162938c8a9a5SSteve French info_buf.CreationTime = 0; /* don't change */ 163038c8a9a5SSteve French info_buf.Attributes = cpu_to_le32(dosattr); 163138c8a9a5SSteve French 163238c8a9a5SSteve French return server->ops->set_file_info(inode, full_path, &info_buf, xid); 163338c8a9a5SSteve French } 163438c8a9a5SSteve French 163538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 163638c8a9a5SSteve French /* 163738c8a9a5SSteve French * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit 163838c8a9a5SSteve French * and rename it to a random name that hopefully won't conflict with 163938c8a9a5SSteve French * anything else. 164038c8a9a5SSteve French */ 164138c8a9a5SSteve French int 164238c8a9a5SSteve French cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, 164338c8a9a5SSteve French const unsigned int xid) 164438c8a9a5SSteve French { 164538c8a9a5SSteve French int oplock = 0; 164638c8a9a5SSteve French int rc; 164738c8a9a5SSteve French struct cifs_fid fid; 164838c8a9a5SSteve French struct cifs_open_parms oparms; 164938c8a9a5SSteve French struct inode *inode = d_inode(dentry); 165038c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 165138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 165238c8a9a5SSteve French struct tcon_link *tlink; 165338c8a9a5SSteve French struct cifs_tcon *tcon; 165438c8a9a5SSteve French __u32 dosattr, origattr; 165538c8a9a5SSteve French FILE_BASIC_INFO *info_buf = NULL; 165638c8a9a5SSteve French 165738c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 165838c8a9a5SSteve French if (IS_ERR(tlink)) 165938c8a9a5SSteve French return PTR_ERR(tlink); 166038c8a9a5SSteve French tcon = tlink_tcon(tlink); 166138c8a9a5SSteve French 166238c8a9a5SSteve French /* 166338c8a9a5SSteve French * We cannot rename the file if the server doesn't support 166438c8a9a5SSteve French * CAP_INFOLEVEL_PASSTHRU 166538c8a9a5SSteve French */ 166638c8a9a5SSteve French if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) { 166738c8a9a5SSteve French rc = -EBUSY; 166838c8a9a5SSteve French goto out; 166938c8a9a5SSteve French } 167038c8a9a5SSteve French 167138c8a9a5SSteve French oparms = (struct cifs_open_parms) { 167238c8a9a5SSteve French .tcon = tcon, 167338c8a9a5SSteve French .cifs_sb = cifs_sb, 167438c8a9a5SSteve French .desired_access = DELETE | FILE_WRITE_ATTRIBUTES, 167538c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 167638c8a9a5SSteve French .disposition = FILE_OPEN, 167738c8a9a5SSteve French .path = full_path, 167838c8a9a5SSteve French .fid = &fid, 167938c8a9a5SSteve French }; 168038c8a9a5SSteve French 168138c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 168238c8a9a5SSteve French if (rc != 0) 168338c8a9a5SSteve French goto out; 168438c8a9a5SSteve French 168538c8a9a5SSteve French origattr = cifsInode->cifsAttrs; 168638c8a9a5SSteve French if (origattr == 0) 168738c8a9a5SSteve French origattr |= ATTR_NORMAL; 168838c8a9a5SSteve French 168938c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 169038c8a9a5SSteve French if (dosattr == 0) 169138c8a9a5SSteve French dosattr |= ATTR_NORMAL; 169238c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 169338c8a9a5SSteve French 169438c8a9a5SSteve French /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */ 169538c8a9a5SSteve French if (dosattr != origattr) { 169638c8a9a5SSteve French info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); 169738c8a9a5SSteve French if (info_buf == NULL) { 169838c8a9a5SSteve French rc = -ENOMEM; 169938c8a9a5SSteve French goto out_close; 170038c8a9a5SSteve French } 170138c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(dosattr); 170238c8a9a5SSteve French rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 170338c8a9a5SSteve French current->tgid); 170438c8a9a5SSteve French /* although we would like to mark the file hidden 170538c8a9a5SSteve French if that fails we will still try to rename it */ 170638c8a9a5SSteve French if (!rc) 170738c8a9a5SSteve French cifsInode->cifsAttrs = dosattr; 170838c8a9a5SSteve French else 170938c8a9a5SSteve French dosattr = origattr; /* since not able to change them */ 171038c8a9a5SSteve French } 171138c8a9a5SSteve French 171238c8a9a5SSteve French /* rename the file */ 171338c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, 171438c8a9a5SSteve French cifs_sb->local_nls, 171538c8a9a5SSteve French cifs_remap(cifs_sb)); 171638c8a9a5SSteve French if (rc != 0) { 171738c8a9a5SSteve French rc = -EBUSY; 171838c8a9a5SSteve French goto undo_setattr; 171938c8a9a5SSteve French } 172038c8a9a5SSteve French 172138c8a9a5SSteve French /* try to set DELETE_ON_CLOSE */ 172238c8a9a5SSteve French if (!test_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags)) { 172338c8a9a5SSteve French rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid, 172438c8a9a5SSteve French current->tgid); 172538c8a9a5SSteve French /* 172638c8a9a5SSteve French * some samba versions return -ENOENT when we try to set the 172738c8a9a5SSteve French * file disposition here. Likely a samba bug, but work around 172838c8a9a5SSteve French * it for now. This means that some cifsXXX files may hang 172938c8a9a5SSteve French * around after they shouldn't. 173038c8a9a5SSteve French * 173138c8a9a5SSteve French * BB: remove this hack after more servers have the fix 173238c8a9a5SSteve French */ 173338c8a9a5SSteve French if (rc == -ENOENT) 173438c8a9a5SSteve French rc = 0; 173538c8a9a5SSteve French else if (rc != 0) { 173638c8a9a5SSteve French rc = -EBUSY; 173738c8a9a5SSteve French goto undo_rename; 173838c8a9a5SSteve French } 173938c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags); 174038c8a9a5SSteve French } 174138c8a9a5SSteve French 174238c8a9a5SSteve French out_close: 174338c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 174438c8a9a5SSteve French out: 174538c8a9a5SSteve French kfree(info_buf); 174638c8a9a5SSteve French cifs_put_tlink(tlink); 174738c8a9a5SSteve French return rc; 174838c8a9a5SSteve French 174938c8a9a5SSteve French /* 175038c8a9a5SSteve French * reset everything back to the original state. Don't bother 175138c8a9a5SSteve French * dealing with errors here since we can't do anything about 175238c8a9a5SSteve French * them anyway. 175338c8a9a5SSteve French */ 175438c8a9a5SSteve French undo_rename: 175538c8a9a5SSteve French CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, 175638c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 175738c8a9a5SSteve French undo_setattr: 175838c8a9a5SSteve French if (dosattr != origattr) { 175938c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(origattr); 176038c8a9a5SSteve French if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 176138c8a9a5SSteve French current->tgid)) 176238c8a9a5SSteve French cifsInode->cifsAttrs = origattr; 176338c8a9a5SSteve French } 176438c8a9a5SSteve French 176538c8a9a5SSteve French goto out_close; 176638c8a9a5SSteve French } 176738c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 176838c8a9a5SSteve French 176938c8a9a5SSteve French /* copied from fs/nfs/dir.c with small changes */ 177038c8a9a5SSteve French static void 177138c8a9a5SSteve French cifs_drop_nlink(struct inode *inode) 177238c8a9a5SSteve French { 177338c8a9a5SSteve French spin_lock(&inode->i_lock); 177438c8a9a5SSteve French if (inode->i_nlink > 0) 177538c8a9a5SSteve French drop_nlink(inode); 177638c8a9a5SSteve French spin_unlock(&inode->i_lock); 177738c8a9a5SSteve French } 177838c8a9a5SSteve French 177938c8a9a5SSteve French /* 178038c8a9a5SSteve French * If d_inode(dentry) is null (usually meaning the cached dentry 178138c8a9a5SSteve French * is a negative dentry) then we would attempt a standard SMB delete, but 178238c8a9a5SSteve French * if that fails we can not attempt the fall back mechanisms on EACCES 178338c8a9a5SSteve French * but will return the EACCES to the caller. Note that the VFS does not call 178438c8a9a5SSteve French * unlink on negative dentries currently. 178538c8a9a5SSteve French */ 178638c8a9a5SSteve French int cifs_unlink(struct inode *dir, struct dentry *dentry) 178738c8a9a5SSteve French { 178838c8a9a5SSteve French int rc = 0; 178938c8a9a5SSteve French unsigned int xid; 179038c8a9a5SSteve French const char *full_path; 179138c8a9a5SSteve French void *page; 179238c8a9a5SSteve French struct inode *inode = d_inode(dentry); 179338c8a9a5SSteve French struct cifsInodeInfo *cifs_inode; 179438c8a9a5SSteve French struct super_block *sb = dir->i_sb; 179538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 179638c8a9a5SSteve French struct tcon_link *tlink; 179738c8a9a5SSteve French struct cifs_tcon *tcon; 179838c8a9a5SSteve French struct TCP_Server_Info *server; 179938c8a9a5SSteve French struct iattr *attrs = NULL; 180038c8a9a5SSteve French __u32 dosattr = 0, origattr = 0; 180138c8a9a5SSteve French 180238c8a9a5SSteve French cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); 180338c8a9a5SSteve French 180438c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 180538c8a9a5SSteve French return -EIO; 180638c8a9a5SSteve French 180738c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 180838c8a9a5SSteve French if (IS_ERR(tlink)) 180938c8a9a5SSteve French return PTR_ERR(tlink); 181038c8a9a5SSteve French tcon = tlink_tcon(tlink); 181138c8a9a5SSteve French server = tcon->ses->server; 181238c8a9a5SSteve French 181338c8a9a5SSteve French xid = get_xid(); 181438c8a9a5SSteve French page = alloc_dentry_path(); 181538c8a9a5SSteve French 181638c8a9a5SSteve French if (tcon->nodelete) { 181738c8a9a5SSteve French rc = -EACCES; 181838c8a9a5SSteve French goto unlink_out; 181938c8a9a5SSteve French } 182038c8a9a5SSteve French 182138c8a9a5SSteve French /* Unlink can be called from rename so we can not take the 182238c8a9a5SSteve French * sb->s_vfs_rename_mutex here */ 182338c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 182438c8a9a5SSteve French if (IS_ERR(full_path)) { 182538c8a9a5SSteve French rc = PTR_ERR(full_path); 182638c8a9a5SSteve French goto unlink_out; 182738c8a9a5SSteve French } 182838c8a9a5SSteve French 182938c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, full_path); 183038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 183138c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 183238c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 183338c8a9a5SSteve French rc = CIFSPOSIXDelFile(xid, tcon, full_path, 183438c8a9a5SSteve French SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 183538c8a9a5SSteve French cifs_remap(cifs_sb)); 183638c8a9a5SSteve French cifs_dbg(FYI, "posix del rc %d\n", rc); 183738c8a9a5SSteve French if ((rc == 0) || (rc == -ENOENT)) 183838c8a9a5SSteve French goto psx_del_no_retry; 183938c8a9a5SSteve French } 184038c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 184138c8a9a5SSteve French 184238c8a9a5SSteve French retry_std_delete: 184338c8a9a5SSteve French if (!server->ops->unlink) { 184438c8a9a5SSteve French rc = -ENOSYS; 184538c8a9a5SSteve French goto psx_del_no_retry; 184638c8a9a5SSteve French } 184738c8a9a5SSteve French 184838c8a9a5SSteve French rc = server->ops->unlink(xid, tcon, full_path, cifs_sb); 184938c8a9a5SSteve French 185038c8a9a5SSteve French psx_del_no_retry: 185138c8a9a5SSteve French if (!rc) { 185238c8a9a5SSteve French if (inode) 185338c8a9a5SSteve French cifs_drop_nlink(inode); 185438c8a9a5SSteve French } else if (rc == -ENOENT) { 185538c8a9a5SSteve French d_drop(dentry); 185638c8a9a5SSteve French } else if (rc == -EBUSY) { 185738c8a9a5SSteve French if (server->ops->rename_pending_delete) { 185838c8a9a5SSteve French rc = server->ops->rename_pending_delete(full_path, 185938c8a9a5SSteve French dentry, xid); 186038c8a9a5SSteve French if (rc == 0) 186138c8a9a5SSteve French cifs_drop_nlink(inode); 186238c8a9a5SSteve French } 186338c8a9a5SSteve French } else if ((rc == -EACCES) && (dosattr == 0) && inode) { 186438c8a9a5SSteve French attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 186538c8a9a5SSteve French if (attrs == NULL) { 186638c8a9a5SSteve French rc = -ENOMEM; 186738c8a9a5SSteve French goto out_reval; 186838c8a9a5SSteve French } 186938c8a9a5SSteve French 187038c8a9a5SSteve French /* try to reset dos attributes */ 187138c8a9a5SSteve French cifs_inode = CIFS_I(inode); 187238c8a9a5SSteve French origattr = cifs_inode->cifsAttrs; 187338c8a9a5SSteve French if (origattr == 0) 187438c8a9a5SSteve French origattr |= ATTR_NORMAL; 187538c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 187638c8a9a5SSteve French if (dosattr == 0) 187738c8a9a5SSteve French dosattr |= ATTR_NORMAL; 187838c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 187938c8a9a5SSteve French 188038c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 188138c8a9a5SSteve French if (rc != 0) 188238c8a9a5SSteve French goto out_reval; 188338c8a9a5SSteve French 188438c8a9a5SSteve French goto retry_std_delete; 188538c8a9a5SSteve French } 188638c8a9a5SSteve French 188738c8a9a5SSteve French /* undo the setattr if we errored out and it's needed */ 188838c8a9a5SSteve French if (rc != 0 && dosattr != 0) 188938c8a9a5SSteve French cifs_set_file_info(inode, attrs, xid, full_path, origattr); 189038c8a9a5SSteve French 189138c8a9a5SSteve French out_reval: 189238c8a9a5SSteve French if (inode) { 189338c8a9a5SSteve French cifs_inode = CIFS_I(inode); 189438c8a9a5SSteve French cifs_inode->time = 0; /* will force revalidate to get info 189538c8a9a5SSteve French when needed */ 189694487653SJeff Layton inode_set_ctime_current(inode); 189738c8a9a5SSteve French } 189823171df5SJeff Layton inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); 189938c8a9a5SSteve French cifs_inode = CIFS_I(dir); 190038c8a9a5SSteve French CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ 190138c8a9a5SSteve French unlink_out: 190238c8a9a5SSteve French free_dentry_path(page); 190338c8a9a5SSteve French kfree(attrs); 190438c8a9a5SSteve French free_xid(xid); 190538c8a9a5SSteve French cifs_put_tlink(tlink); 190638c8a9a5SSteve French return rc; 190738c8a9a5SSteve French } 190838c8a9a5SSteve French 190938c8a9a5SSteve French static int 191038c8a9a5SSteve French cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, 191138c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 191238c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 191338c8a9a5SSteve French { 191438c8a9a5SSteve French int rc = 0; 191538c8a9a5SSteve French struct inode *inode = NULL; 191638c8a9a5SSteve French 191702bcf865SSteve French if (tcon->posix_extensions) { 191802bcf865SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, 191902bcf865SSteve French NULL, parent->i_sb, xid); 192038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 192102bcf865SSteve French } else if (tcon->unix_ext) { 192238c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, 192338c8a9a5SSteve French xid); 192438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 192502bcf865SSteve French } else { 192638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb, 192738c8a9a5SSteve French xid, NULL); 192802bcf865SSteve French } 192938c8a9a5SSteve French 193038c8a9a5SSteve French if (rc) 193138c8a9a5SSteve French return rc; 193238c8a9a5SSteve French 193338c8a9a5SSteve French if (!S_ISDIR(inode->i_mode)) { 193438c8a9a5SSteve French /* 193538c8a9a5SSteve French * mkdir succeeded, but another client has managed to remove the 193638c8a9a5SSteve French * sucker and replace it with non-directory. Return success, 193738c8a9a5SSteve French * but don't leave the child in dcache. 193838c8a9a5SSteve French */ 193938c8a9a5SSteve French iput(inode); 194038c8a9a5SSteve French d_drop(dentry); 194138c8a9a5SSteve French return 0; 194238c8a9a5SSteve French } 194338c8a9a5SSteve French /* 194438c8a9a5SSteve French * setting nlink not necessary except in cases where we failed to get it 194538c8a9a5SSteve French * from the server or was set bogus. Also, since this is a brand new 194638c8a9a5SSteve French * inode, no need to grab the i_lock before setting the i_nlink. 194738c8a9a5SSteve French */ 194838c8a9a5SSteve French if (inode->i_nlink < 2) 194938c8a9a5SSteve French set_nlink(inode, 2); 195038c8a9a5SSteve French mode &= ~current_umask(); 195138c8a9a5SSteve French /* must turn on setgid bit if parent dir has it */ 195238c8a9a5SSteve French if (parent->i_mode & S_ISGID) 195338c8a9a5SSteve French mode |= S_ISGID; 195438c8a9a5SSteve French 195538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 195638c8a9a5SSteve French if (tcon->unix_ext) { 195738c8a9a5SSteve French struct cifs_unix_set_info_args args = { 195838c8a9a5SSteve French .mode = mode, 195938c8a9a5SSteve French .ctime = NO_CHANGE_64, 196038c8a9a5SSteve French .atime = NO_CHANGE_64, 196138c8a9a5SSteve French .mtime = NO_CHANGE_64, 196238c8a9a5SSteve French .device = 0, 196338c8a9a5SSteve French }; 196438c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 196538c8a9a5SSteve French args.uid = current_fsuid(); 196638c8a9a5SSteve French if (parent->i_mode & S_ISGID) 196738c8a9a5SSteve French args.gid = parent->i_gid; 196838c8a9a5SSteve French else 196938c8a9a5SSteve French args.gid = current_fsgid(); 197038c8a9a5SSteve French } else { 197138c8a9a5SSteve French args.uid = INVALID_UID; /* no change */ 197238c8a9a5SSteve French args.gid = INVALID_GID; /* no change */ 197338c8a9a5SSteve French } 197438c8a9a5SSteve French CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, 197538c8a9a5SSteve French cifs_sb->local_nls, 197638c8a9a5SSteve French cifs_remap(cifs_sb)); 197738c8a9a5SSteve French } else { 197838c8a9a5SSteve French #else 197938c8a9a5SSteve French { 198038c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 198138c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 198238c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 198338c8a9a5SSteve French (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) 198438c8a9a5SSteve French server->ops->mkdir_setinfo(inode, full_path, cifs_sb, 198538c8a9a5SSteve French tcon, xid); 198638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 198738c8a9a5SSteve French inode->i_mode = (mode | S_IFDIR); 198838c8a9a5SSteve French 198938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 199038c8a9a5SSteve French inode->i_uid = current_fsuid(); 199138c8a9a5SSteve French if (inode->i_mode & S_ISGID) 199238c8a9a5SSteve French inode->i_gid = parent->i_gid; 199338c8a9a5SSteve French else 199438c8a9a5SSteve French inode->i_gid = current_fsgid(); 199538c8a9a5SSteve French } 199638c8a9a5SSteve French } 199738c8a9a5SSteve French d_instantiate(dentry, inode); 199838c8a9a5SSteve French return 0; 199938c8a9a5SSteve French } 200038c8a9a5SSteve French 200138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 200238c8a9a5SSteve French static int 200338c8a9a5SSteve French cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, 200438c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 200538c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 200638c8a9a5SSteve French { 200738c8a9a5SSteve French int rc = 0; 200838c8a9a5SSteve French u32 oplock = 0; 200938c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info = NULL; 201038c8a9a5SSteve French struct inode *newinode = NULL; 201138c8a9a5SSteve French struct cifs_fattr fattr; 201238c8a9a5SSteve French 201338c8a9a5SSteve French info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 201438c8a9a5SSteve French if (info == NULL) { 201538c8a9a5SSteve French rc = -ENOMEM; 201638c8a9a5SSteve French goto posix_mkdir_out; 201738c8a9a5SSteve French } 201838c8a9a5SSteve French 201938c8a9a5SSteve French mode &= ~current_umask(); 202038c8a9a5SSteve French rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, 202138c8a9a5SSteve French NULL /* netfid */, info, &oplock, full_path, 202238c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 202338c8a9a5SSteve French if (rc == -EOPNOTSUPP) 202438c8a9a5SSteve French goto posix_mkdir_out; 202538c8a9a5SSteve French else if (rc) { 202638c8a9a5SSteve French cifs_dbg(FYI, "posix mkdir returned 0x%x\n", rc); 202738c8a9a5SSteve French d_drop(dentry); 202838c8a9a5SSteve French goto posix_mkdir_out; 202938c8a9a5SSteve French } 203038c8a9a5SSteve French 203138c8a9a5SSteve French if (info->Type == cpu_to_le32(-1)) 203238c8a9a5SSteve French /* no return info, go query for it */ 203338c8a9a5SSteve French goto posix_mkdir_get_info; 203438c8a9a5SSteve French /* 203538c8a9a5SSteve French * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if 203638c8a9a5SSteve French * need to set uid/gid. 203738c8a9a5SSteve French */ 203838c8a9a5SSteve French 203938c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); 204038c8a9a5SSteve French cifs_fill_uniqueid(inode->i_sb, &fattr); 204138c8a9a5SSteve French newinode = cifs_iget(inode->i_sb, &fattr); 204238c8a9a5SSteve French if (!newinode) 204338c8a9a5SSteve French goto posix_mkdir_get_info; 204438c8a9a5SSteve French 204538c8a9a5SSteve French d_instantiate(dentry, newinode); 204638c8a9a5SSteve French 204738c8a9a5SSteve French #ifdef CONFIG_CIFS_DEBUG2 204838c8a9a5SSteve French cifs_dbg(FYI, "instantiated dentry %p %pd to inode %p\n", 204938c8a9a5SSteve French dentry, dentry, newinode); 205038c8a9a5SSteve French 205138c8a9a5SSteve French if (newinode->i_nlink != 2) 205238c8a9a5SSteve French cifs_dbg(FYI, "unexpected number of links %d\n", 205338c8a9a5SSteve French newinode->i_nlink); 205438c8a9a5SSteve French #endif 205538c8a9a5SSteve French 205638c8a9a5SSteve French posix_mkdir_out: 205738c8a9a5SSteve French kfree(info); 205838c8a9a5SSteve French return rc; 205938c8a9a5SSteve French posix_mkdir_get_info: 206038c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, 206138c8a9a5SSteve French xid); 206238c8a9a5SSteve French goto posix_mkdir_out; 206338c8a9a5SSteve French } 206438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 206538c8a9a5SSteve French 206638c8a9a5SSteve French int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, 206738c8a9a5SSteve French struct dentry *direntry, umode_t mode) 206838c8a9a5SSteve French { 206938c8a9a5SSteve French int rc = 0; 207038c8a9a5SSteve French unsigned int xid; 207138c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 207238c8a9a5SSteve French struct tcon_link *tlink; 207338c8a9a5SSteve French struct cifs_tcon *tcon; 207438c8a9a5SSteve French struct TCP_Server_Info *server; 207538c8a9a5SSteve French const char *full_path; 207638c8a9a5SSteve French void *page; 207738c8a9a5SSteve French 207838c8a9a5SSteve French cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n", 207938c8a9a5SSteve French mode, inode); 208038c8a9a5SSteve French 208138c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 208238c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 208338c8a9a5SSteve French return -EIO; 208438c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 208538c8a9a5SSteve French if (IS_ERR(tlink)) 208638c8a9a5SSteve French return PTR_ERR(tlink); 208738c8a9a5SSteve French tcon = tlink_tcon(tlink); 208838c8a9a5SSteve French 208938c8a9a5SSteve French xid = get_xid(); 209038c8a9a5SSteve French 209138c8a9a5SSteve French page = alloc_dentry_path(); 209238c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 209338c8a9a5SSteve French if (IS_ERR(full_path)) { 209438c8a9a5SSteve French rc = PTR_ERR(full_path); 209538c8a9a5SSteve French goto mkdir_out; 209638c8a9a5SSteve French } 209738c8a9a5SSteve French 209838c8a9a5SSteve French server = tcon->ses->server; 209938c8a9a5SSteve French 210038c8a9a5SSteve French if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { 210138c8a9a5SSteve French rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, 210238c8a9a5SSteve French cifs_sb); 210338c8a9a5SSteve French d_drop(direntry); /* for time being always refresh inode info */ 210438c8a9a5SSteve French goto mkdir_out; 210538c8a9a5SSteve French } 210638c8a9a5SSteve French 210738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 210838c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 210938c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 211038c8a9a5SSteve French rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, 211138c8a9a5SSteve French tcon, xid); 211238c8a9a5SSteve French if (rc != -EOPNOTSUPP) 211338c8a9a5SSteve French goto mkdir_out; 211438c8a9a5SSteve French } 211538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 211638c8a9a5SSteve French 211738c8a9a5SSteve French if (!server->ops->mkdir) { 211838c8a9a5SSteve French rc = -ENOSYS; 211938c8a9a5SSteve French goto mkdir_out; 212038c8a9a5SSteve French } 212138c8a9a5SSteve French 212238c8a9a5SSteve French /* BB add setting the equivalent of mode via CreateX w/ACLs */ 212338c8a9a5SSteve French rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb); 212438c8a9a5SSteve French if (rc) { 212538c8a9a5SSteve French cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc); 212638c8a9a5SSteve French d_drop(direntry); 212738c8a9a5SSteve French goto mkdir_out; 212838c8a9a5SSteve French } 212938c8a9a5SSteve French 213038c8a9a5SSteve French /* TODO: skip this for smb2/smb3 */ 213138c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, 213238c8a9a5SSteve French xid); 213338c8a9a5SSteve French mkdir_out: 213438c8a9a5SSteve French /* 213538c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 213638c8a9a5SSteve French * attributes are invalid now. 213738c8a9a5SSteve French */ 213838c8a9a5SSteve French CIFS_I(inode)->time = 0; 213938c8a9a5SSteve French free_dentry_path(page); 214038c8a9a5SSteve French free_xid(xid); 214138c8a9a5SSteve French cifs_put_tlink(tlink); 214238c8a9a5SSteve French return rc; 214338c8a9a5SSteve French } 214438c8a9a5SSteve French 214538c8a9a5SSteve French int cifs_rmdir(struct inode *inode, struct dentry *direntry) 214638c8a9a5SSteve French { 214738c8a9a5SSteve French int rc = 0; 214838c8a9a5SSteve French unsigned int xid; 214938c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 215038c8a9a5SSteve French struct tcon_link *tlink; 215138c8a9a5SSteve French struct cifs_tcon *tcon; 215238c8a9a5SSteve French struct TCP_Server_Info *server; 215338c8a9a5SSteve French const char *full_path; 215438c8a9a5SSteve French void *page = alloc_dentry_path(); 215538c8a9a5SSteve French struct cifsInodeInfo *cifsInode; 215638c8a9a5SSteve French 215738c8a9a5SSteve French cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode); 215838c8a9a5SSteve French 215938c8a9a5SSteve French xid = get_xid(); 216038c8a9a5SSteve French 216138c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 216238c8a9a5SSteve French if (IS_ERR(full_path)) { 216338c8a9a5SSteve French rc = PTR_ERR(full_path); 216438c8a9a5SSteve French goto rmdir_exit; 216538c8a9a5SSteve French } 216638c8a9a5SSteve French 216738c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 216838c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) { 216938c8a9a5SSteve French rc = -EIO; 217038c8a9a5SSteve French goto rmdir_exit; 217138c8a9a5SSteve French } 217238c8a9a5SSteve French 217338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 217438c8a9a5SSteve French if (IS_ERR(tlink)) { 217538c8a9a5SSteve French rc = PTR_ERR(tlink); 217638c8a9a5SSteve French goto rmdir_exit; 217738c8a9a5SSteve French } 217838c8a9a5SSteve French tcon = tlink_tcon(tlink); 217938c8a9a5SSteve French server = tcon->ses->server; 218038c8a9a5SSteve French 218138c8a9a5SSteve French if (!server->ops->rmdir) { 218238c8a9a5SSteve French rc = -ENOSYS; 218338c8a9a5SSteve French cifs_put_tlink(tlink); 218438c8a9a5SSteve French goto rmdir_exit; 218538c8a9a5SSteve French } 218638c8a9a5SSteve French 218738c8a9a5SSteve French if (tcon->nodelete) { 218838c8a9a5SSteve French rc = -EACCES; 218938c8a9a5SSteve French cifs_put_tlink(tlink); 219038c8a9a5SSteve French goto rmdir_exit; 219138c8a9a5SSteve French } 219238c8a9a5SSteve French 219338c8a9a5SSteve French rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); 219438c8a9a5SSteve French cifs_put_tlink(tlink); 219538c8a9a5SSteve French 219638c8a9a5SSteve French if (!rc) { 219738c8a9a5SSteve French spin_lock(&d_inode(direntry)->i_lock); 219838c8a9a5SSteve French i_size_write(d_inode(direntry), 0); 219938c8a9a5SSteve French clear_nlink(d_inode(direntry)); 220038c8a9a5SSteve French spin_unlock(&d_inode(direntry)->i_lock); 220138c8a9a5SSteve French } 220238c8a9a5SSteve French 220338c8a9a5SSteve French cifsInode = CIFS_I(d_inode(direntry)); 220438c8a9a5SSteve French /* force revalidate to go get info when needed */ 220538c8a9a5SSteve French cifsInode->time = 0; 220638c8a9a5SSteve French 220738c8a9a5SSteve French cifsInode = CIFS_I(inode); 220838c8a9a5SSteve French /* 220938c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 221038c8a9a5SSteve French * attributes are invalid now. 221138c8a9a5SSteve French */ 221238c8a9a5SSteve French cifsInode->time = 0; 221338c8a9a5SSteve French 221494487653SJeff Layton inode_set_ctime_current(d_inode(direntry)); 221523171df5SJeff Layton inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); 221638c8a9a5SSteve French 221738c8a9a5SSteve French rmdir_exit: 221838c8a9a5SSteve French free_dentry_path(page); 221938c8a9a5SSteve French free_xid(xid); 222038c8a9a5SSteve French return rc; 222138c8a9a5SSteve French } 222238c8a9a5SSteve French 222338c8a9a5SSteve French static int 222438c8a9a5SSteve French cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, 222538c8a9a5SSteve French const char *from_path, struct dentry *to_dentry, 222638c8a9a5SSteve French const char *to_path) 222738c8a9a5SSteve French { 222838c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); 222938c8a9a5SSteve French struct tcon_link *tlink; 223038c8a9a5SSteve French struct cifs_tcon *tcon; 223138c8a9a5SSteve French struct TCP_Server_Info *server; 223238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 223338c8a9a5SSteve French struct cifs_fid fid; 223438c8a9a5SSteve French struct cifs_open_parms oparms; 223538c8a9a5SSteve French int oplock; 223638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 223738c8a9a5SSteve French int rc; 223838c8a9a5SSteve French 223938c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 224038c8a9a5SSteve French if (IS_ERR(tlink)) 224138c8a9a5SSteve French return PTR_ERR(tlink); 224238c8a9a5SSteve French tcon = tlink_tcon(tlink); 224338c8a9a5SSteve French server = tcon->ses->server; 224438c8a9a5SSteve French 224538c8a9a5SSteve French if (!server->ops->rename) 224638c8a9a5SSteve French return -ENOSYS; 224738c8a9a5SSteve French 224838c8a9a5SSteve French /* try path-based rename first */ 2249c586b0c7SPaulo Alcantara rc = server->ops->rename(xid, tcon, from_dentry, 2250c586b0c7SPaulo Alcantara from_path, to_path, cifs_sb); 225138c8a9a5SSteve French 225238c8a9a5SSteve French /* 225338c8a9a5SSteve French * Don't bother with rename by filehandle unless file is busy and 225438c8a9a5SSteve French * source. Note that cross directory moves do not work with 225538c8a9a5SSteve French * rename by filehandle to various Windows servers. 225638c8a9a5SSteve French */ 225738c8a9a5SSteve French if (rc == 0 || rc != -EBUSY) 225838c8a9a5SSteve French goto do_rename_exit; 225938c8a9a5SSteve French 226038c8a9a5SSteve French /* Don't fall back to using SMB on SMB 2+ mount */ 226138c8a9a5SSteve French if (server->vals->protocol_id != 0) 226238c8a9a5SSteve French goto do_rename_exit; 226338c8a9a5SSteve French 226438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 226538c8a9a5SSteve French /* open-file renames don't work across directories */ 226638c8a9a5SSteve French if (to_dentry->d_parent != from_dentry->d_parent) 226738c8a9a5SSteve French goto do_rename_exit; 226838c8a9a5SSteve French 226938c8a9a5SSteve French oparms = (struct cifs_open_parms) { 227038c8a9a5SSteve French .tcon = tcon, 227138c8a9a5SSteve French .cifs_sb = cifs_sb, 227238c8a9a5SSteve French /* open the file to be renamed -- we need DELETE perms */ 227338c8a9a5SSteve French .desired_access = DELETE, 227438c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 227538c8a9a5SSteve French .disposition = FILE_OPEN, 227638c8a9a5SSteve French .path = from_path, 227738c8a9a5SSteve French .fid = &fid, 227838c8a9a5SSteve French }; 227938c8a9a5SSteve French 228038c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 228138c8a9a5SSteve French if (rc == 0) { 228238c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, 228338c8a9a5SSteve French (const char *) to_dentry->d_name.name, 228438c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 228538c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 228638c8a9a5SSteve French } 228738c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 228838c8a9a5SSteve French do_rename_exit: 228938c8a9a5SSteve French if (rc == 0) 229038c8a9a5SSteve French d_move(from_dentry, to_dentry); 229138c8a9a5SSteve French cifs_put_tlink(tlink); 229238c8a9a5SSteve French return rc; 229338c8a9a5SSteve French } 229438c8a9a5SSteve French 229538c8a9a5SSteve French int 229638c8a9a5SSteve French cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, 229738c8a9a5SSteve French struct dentry *source_dentry, struct inode *target_dir, 229838c8a9a5SSteve French struct dentry *target_dentry, unsigned int flags) 229938c8a9a5SSteve French { 230038c8a9a5SSteve French const char *from_name, *to_name; 230138c8a9a5SSteve French void *page1, *page2; 230238c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 230338c8a9a5SSteve French struct tcon_link *tlink; 230438c8a9a5SSteve French struct cifs_tcon *tcon; 230538c8a9a5SSteve French unsigned int xid; 230638c8a9a5SSteve French int rc, tmprc; 230738c8a9a5SSteve French int retry_count = 0; 230838c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_source = NULL; 230938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 231038c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_target; 231138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 231238c8a9a5SSteve French 231338c8a9a5SSteve French if (flags & ~RENAME_NOREPLACE) 231438c8a9a5SSteve French return -EINVAL; 231538c8a9a5SSteve French 231638c8a9a5SSteve French cifs_sb = CIFS_SB(source_dir->i_sb); 231738c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 231838c8a9a5SSteve French return -EIO; 231938c8a9a5SSteve French 232038c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 232138c8a9a5SSteve French if (IS_ERR(tlink)) 232238c8a9a5SSteve French return PTR_ERR(tlink); 232338c8a9a5SSteve French tcon = tlink_tcon(tlink); 232438c8a9a5SSteve French 232538c8a9a5SSteve French page1 = alloc_dentry_path(); 232638c8a9a5SSteve French page2 = alloc_dentry_path(); 232738c8a9a5SSteve French xid = get_xid(); 232838c8a9a5SSteve French 232938c8a9a5SSteve French from_name = build_path_from_dentry(source_dentry, page1); 233038c8a9a5SSteve French if (IS_ERR(from_name)) { 233138c8a9a5SSteve French rc = PTR_ERR(from_name); 233238c8a9a5SSteve French goto cifs_rename_exit; 233338c8a9a5SSteve French } 233438c8a9a5SSteve French 233538c8a9a5SSteve French to_name = build_path_from_dentry(target_dentry, page2); 233638c8a9a5SSteve French if (IS_ERR(to_name)) { 233738c8a9a5SSteve French rc = PTR_ERR(to_name); 233838c8a9a5SSteve French goto cifs_rename_exit; 233938c8a9a5SSteve French } 234038c8a9a5SSteve French 234138c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, from_name); 234238c8a9a5SSteve French if (d_inode(target_dentry) != NULL) 234338c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, to_name); 234438c8a9a5SSteve French 234538c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 234638c8a9a5SSteve French to_name); 234738c8a9a5SSteve French 234838c8a9a5SSteve French if (rc == -EACCES) { 234938c8a9a5SSteve French while (retry_count < 3) { 235038c8a9a5SSteve French cifs_close_all_deferred_files(tcon); 235138c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 235238c8a9a5SSteve French to_name); 235338c8a9a5SSteve French if (rc != -EACCES) 235438c8a9a5SSteve French break; 235538c8a9a5SSteve French retry_count++; 235638c8a9a5SSteve French } 235738c8a9a5SSteve French } 235838c8a9a5SSteve French 235938c8a9a5SSteve French /* 236038c8a9a5SSteve French * No-replace is the natural behavior for CIFS, so skip unlink hacks. 236138c8a9a5SSteve French */ 236238c8a9a5SSteve French if (flags & RENAME_NOREPLACE) 236338c8a9a5SSteve French goto cifs_rename_exit; 236438c8a9a5SSteve French 236538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 236638c8a9a5SSteve French if (rc == -EEXIST && tcon->unix_ext) { 236738c8a9a5SSteve French /* 236838c8a9a5SSteve French * Are src and dst hardlinks of same inode? We can only tell 236938c8a9a5SSteve French * with unix extensions enabled. 237038c8a9a5SSteve French */ 237138c8a9a5SSteve French info_buf_source = 237238c8a9a5SSteve French kmalloc_array(2, sizeof(FILE_UNIX_BASIC_INFO), 237338c8a9a5SSteve French GFP_KERNEL); 237438c8a9a5SSteve French if (info_buf_source == NULL) { 237538c8a9a5SSteve French rc = -ENOMEM; 237638c8a9a5SSteve French goto cifs_rename_exit; 237738c8a9a5SSteve French } 237838c8a9a5SSteve French 237938c8a9a5SSteve French info_buf_target = info_buf_source + 1; 238038c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name, 238138c8a9a5SSteve French info_buf_source, 238238c8a9a5SSteve French cifs_sb->local_nls, 238338c8a9a5SSteve French cifs_remap(cifs_sb)); 238438c8a9a5SSteve French if (tmprc != 0) 238538c8a9a5SSteve French goto unlink_target; 238638c8a9a5SSteve French 238738c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name, 238838c8a9a5SSteve French info_buf_target, 238938c8a9a5SSteve French cifs_sb->local_nls, 239038c8a9a5SSteve French cifs_remap(cifs_sb)); 239138c8a9a5SSteve French 239238c8a9a5SSteve French if (tmprc == 0 && (info_buf_source->UniqueId == 239338c8a9a5SSteve French info_buf_target->UniqueId)) { 239438c8a9a5SSteve French /* same file, POSIX says that this is a noop */ 239538c8a9a5SSteve French rc = 0; 239638c8a9a5SSteve French goto cifs_rename_exit; 239738c8a9a5SSteve French } 239838c8a9a5SSteve French } 239938c8a9a5SSteve French /* 240038c8a9a5SSteve French * else ... BB we could add the same check for Windows by 240138c8a9a5SSteve French * checking the UniqueId via FILE_INTERNAL_INFO 240238c8a9a5SSteve French */ 240338c8a9a5SSteve French 240438c8a9a5SSteve French unlink_target: 240538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 240638c8a9a5SSteve French 240738c8a9a5SSteve French /* Try unlinking the target dentry if it's not negative */ 240838c8a9a5SSteve French if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) { 240938c8a9a5SSteve French if (d_is_dir(target_dentry)) 241038c8a9a5SSteve French tmprc = cifs_rmdir(target_dir, target_dentry); 241138c8a9a5SSteve French else 241238c8a9a5SSteve French tmprc = cifs_unlink(target_dir, target_dentry); 241338c8a9a5SSteve French if (tmprc) 241438c8a9a5SSteve French goto cifs_rename_exit; 241538c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, 241638c8a9a5SSteve French target_dentry, to_name); 241738c8a9a5SSteve French } 241838c8a9a5SSteve French 241938c8a9a5SSteve French /* force revalidate to go get info when needed */ 242038c8a9a5SSteve French CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; 242138c8a9a5SSteve French 242238c8a9a5SSteve French cifs_rename_exit: 242338c8a9a5SSteve French kfree(info_buf_source); 242438c8a9a5SSteve French free_dentry_path(page2); 242538c8a9a5SSteve French free_dentry_path(page1); 242638c8a9a5SSteve French free_xid(xid); 242738c8a9a5SSteve French cifs_put_tlink(tlink); 242838c8a9a5SSteve French return rc; 242938c8a9a5SSteve French } 243038c8a9a5SSteve French 243138c8a9a5SSteve French static bool 243238c8a9a5SSteve French cifs_dentry_needs_reval(struct dentry *dentry) 243338c8a9a5SSteve French { 243438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 243538c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 243638c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 243738c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 243838c8a9a5SSteve French struct cached_fid *cfid = NULL; 243938c8a9a5SSteve French 244038c8a9a5SSteve French if (cifs_i->time == 0) 244138c8a9a5SSteve French return true; 244238c8a9a5SSteve French 244338c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) 244438c8a9a5SSteve French return false; 244538c8a9a5SSteve French 244638c8a9a5SSteve French if (!lookupCacheEnabled) 244738c8a9a5SSteve French return true; 244838c8a9a5SSteve French 244938c8a9a5SSteve French if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) { 245038c8a9a5SSteve French spin_lock(&cfid->fid_lock); 245138c8a9a5SSteve French if (cfid->time && cifs_i->time > cfid->time) { 245238c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 245338c8a9a5SSteve French close_cached_dir(cfid); 245438c8a9a5SSteve French return false; 245538c8a9a5SSteve French } 245638c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 245738c8a9a5SSteve French close_cached_dir(cfid); 245838c8a9a5SSteve French } 245938c8a9a5SSteve French /* 246038c8a9a5SSteve French * depending on inode type, check if attribute caching disabled for 246138c8a9a5SSteve French * files or directories 246238c8a9a5SSteve French */ 246338c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) { 246438c8a9a5SSteve French if (!cifs_sb->ctx->acdirmax) 246538c8a9a5SSteve French return true; 246638c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 246738c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acdirmax)) 246838c8a9a5SSteve French return true; 246938c8a9a5SSteve French } else { /* file */ 247038c8a9a5SSteve French if (!cifs_sb->ctx->acregmax) 247138c8a9a5SSteve French return true; 247238c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 247338c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acregmax)) 247438c8a9a5SSteve French return true; 247538c8a9a5SSteve French } 247638c8a9a5SSteve French 247738c8a9a5SSteve French /* hardlinked files w/ noserverino get "special" treatment */ 247838c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 247938c8a9a5SSteve French S_ISREG(inode->i_mode) && inode->i_nlink != 1) 248038c8a9a5SSteve French return true; 248138c8a9a5SSteve French 248238c8a9a5SSteve French return false; 248338c8a9a5SSteve French } 248438c8a9a5SSteve French 248538c8a9a5SSteve French /* 248638c8a9a5SSteve French * Zap the cache. Called when invalid_mapping flag is set. 248738c8a9a5SSteve French */ 248838c8a9a5SSteve French int 248938c8a9a5SSteve French cifs_invalidate_mapping(struct inode *inode) 249038c8a9a5SSteve French { 249138c8a9a5SSteve French int rc = 0; 249238c8a9a5SSteve French 249338c8a9a5SSteve French if (inode->i_mapping && inode->i_mapping->nrpages != 0) { 249438c8a9a5SSteve French rc = invalidate_inode_pages2(inode->i_mapping); 249538c8a9a5SSteve French if (rc) 2496acf35d79SSteve French cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", 2497acf35d79SSteve French __func__, inode, rc); 249838c8a9a5SSteve French } 249938c8a9a5SSteve French 250038c8a9a5SSteve French return rc; 250138c8a9a5SSteve French } 250238c8a9a5SSteve French 250338c8a9a5SSteve French /** 250438c8a9a5SSteve French * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks 250538c8a9a5SSteve French * 250638c8a9a5SSteve French * @key: currently unused 250738c8a9a5SSteve French * @mode: the task state to sleep in 250838c8a9a5SSteve French */ 250938c8a9a5SSteve French static int 251038c8a9a5SSteve French cifs_wait_bit_killable(struct wait_bit_key *key, int mode) 251138c8a9a5SSteve French { 251238c8a9a5SSteve French schedule(); 251338c8a9a5SSteve French if (signal_pending_state(mode, current)) 251438c8a9a5SSteve French return -ERESTARTSYS; 251538c8a9a5SSteve French return 0; 251638c8a9a5SSteve French } 251738c8a9a5SSteve French 251838c8a9a5SSteve French int 251938c8a9a5SSteve French cifs_revalidate_mapping(struct inode *inode) 252038c8a9a5SSteve French { 252138c8a9a5SSteve French int rc; 252238c8a9a5SSteve French unsigned long *flags = &CIFS_I(inode)->flags; 252338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 252438c8a9a5SSteve French 252538c8a9a5SSteve French /* swapfiles are not supposed to be shared */ 252638c8a9a5SSteve French if (IS_SWAPFILE(inode)) 252738c8a9a5SSteve French return 0; 252838c8a9a5SSteve French 252938c8a9a5SSteve French rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable, 253038c8a9a5SSteve French TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 253138c8a9a5SSteve French if (rc) 253238c8a9a5SSteve French return rc; 253338c8a9a5SSteve French 253438c8a9a5SSteve French if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) { 253538c8a9a5SSteve French /* for cache=singleclient, do not invalidate */ 253638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) 253738c8a9a5SSteve French goto skip_invalidate; 253838c8a9a5SSteve French 253938c8a9a5SSteve French rc = cifs_invalidate_mapping(inode); 254038c8a9a5SSteve French if (rc) 254138c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, flags); 254238c8a9a5SSteve French } 254338c8a9a5SSteve French 254438c8a9a5SSteve French skip_invalidate: 254538c8a9a5SSteve French clear_bit_unlock(CIFS_INO_LOCK, flags); 254638c8a9a5SSteve French smp_mb__after_atomic(); 254738c8a9a5SSteve French wake_up_bit(flags, CIFS_INO_LOCK); 254838c8a9a5SSteve French 254938c8a9a5SSteve French return rc; 255038c8a9a5SSteve French } 255138c8a9a5SSteve French 255238c8a9a5SSteve French int 255338c8a9a5SSteve French cifs_zap_mapping(struct inode *inode) 255438c8a9a5SSteve French { 255538c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags); 255638c8a9a5SSteve French return cifs_revalidate_mapping(inode); 255738c8a9a5SSteve French } 255838c8a9a5SSteve French 255938c8a9a5SSteve French int cifs_revalidate_file_attr(struct file *filp) 256038c8a9a5SSteve French { 256138c8a9a5SSteve French int rc = 0; 256238c8a9a5SSteve French struct dentry *dentry = file_dentry(filp); 256338c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 256438c8a9a5SSteve French struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; 256538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 256638c8a9a5SSteve French 256738c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 256838c8a9a5SSteve French return rc; 256938c8a9a5SSteve French 257038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 257138c8a9a5SSteve French if (tlink_tcon(cfile->tlink)->unix_ext) 257238c8a9a5SSteve French rc = cifs_get_file_info_unix(filp); 257338c8a9a5SSteve French else 257438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 257538c8a9a5SSteve French rc = cifs_get_file_info(filp); 257638c8a9a5SSteve French 257738c8a9a5SSteve French return rc; 257838c8a9a5SSteve French } 257938c8a9a5SSteve French 258038c8a9a5SSteve French int cifs_revalidate_dentry_attr(struct dentry *dentry) 258138c8a9a5SSteve French { 258238c8a9a5SSteve French unsigned int xid; 258338c8a9a5SSteve French int rc = 0; 258438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 258538c8a9a5SSteve French struct super_block *sb = dentry->d_sb; 258638c8a9a5SSteve French const char *full_path; 258738c8a9a5SSteve French void *page; 258838c8a9a5SSteve French int count = 0; 258938c8a9a5SSteve French 259038c8a9a5SSteve French if (inode == NULL) 259138c8a9a5SSteve French return -ENOENT; 259238c8a9a5SSteve French 259338c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 259438c8a9a5SSteve French return rc; 259538c8a9a5SSteve French 259638c8a9a5SSteve French xid = get_xid(); 259738c8a9a5SSteve French 259838c8a9a5SSteve French page = alloc_dentry_path(); 259938c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 260038c8a9a5SSteve French if (IS_ERR(full_path)) { 260138c8a9a5SSteve French rc = PTR_ERR(full_path); 260238c8a9a5SSteve French goto out; 260338c8a9a5SSteve French } 260438c8a9a5SSteve French 260538c8a9a5SSteve French cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n", 260638c8a9a5SSteve French full_path, inode, inode->i_count.counter, 260738c8a9a5SSteve French dentry, cifs_get_time(dentry), jiffies); 260838c8a9a5SSteve French 260938c8a9a5SSteve French again: 261002bcf865SSteve French if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) { 261102bcf865SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, 261202bcf865SSteve French NULL, sb, xid); 261302bcf865SSteve French } else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) { 261438c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); 261502bcf865SSteve French } else { 261638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, sb, 261738c8a9a5SSteve French xid, NULL); 261802bcf865SSteve French } 261938c8a9a5SSteve French if (rc == -EAGAIN && count++ < 10) 262038c8a9a5SSteve French goto again; 262138c8a9a5SSteve French out: 262238c8a9a5SSteve French free_dentry_path(page); 262338c8a9a5SSteve French free_xid(xid); 262438c8a9a5SSteve French 262538c8a9a5SSteve French return rc; 262638c8a9a5SSteve French } 262738c8a9a5SSteve French 262838c8a9a5SSteve French int cifs_revalidate_file(struct file *filp) 262938c8a9a5SSteve French { 263038c8a9a5SSteve French int rc; 263138c8a9a5SSteve French struct inode *inode = file_inode(filp); 263238c8a9a5SSteve French 263338c8a9a5SSteve French rc = cifs_revalidate_file_attr(filp); 263438c8a9a5SSteve French if (rc) 263538c8a9a5SSteve French return rc; 263638c8a9a5SSteve French 263738c8a9a5SSteve French return cifs_revalidate_mapping(inode); 263838c8a9a5SSteve French } 263938c8a9a5SSteve French 264038c8a9a5SSteve French /* revalidate a dentry's inode attributes */ 264138c8a9a5SSteve French int cifs_revalidate_dentry(struct dentry *dentry) 264238c8a9a5SSteve French { 264338c8a9a5SSteve French int rc; 264438c8a9a5SSteve French struct inode *inode = d_inode(dentry); 264538c8a9a5SSteve French 264638c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 264738c8a9a5SSteve French if (rc) 264838c8a9a5SSteve French return rc; 264938c8a9a5SSteve French 265038c8a9a5SSteve French return cifs_revalidate_mapping(inode); 265138c8a9a5SSteve French } 265238c8a9a5SSteve French 265338c8a9a5SSteve French int cifs_getattr(struct mnt_idmap *idmap, const struct path *path, 265438c8a9a5SSteve French struct kstat *stat, u32 request_mask, unsigned int flags) 265538c8a9a5SSteve French { 265638c8a9a5SSteve French struct dentry *dentry = path->dentry; 265738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); 265838c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 265938c8a9a5SSteve French struct inode *inode = d_inode(dentry); 266038c8a9a5SSteve French int rc; 266138c8a9a5SSteve French 266238c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) 266338c8a9a5SSteve French return -EIO; 266438c8a9a5SSteve French 266538c8a9a5SSteve French /* 266638c8a9a5SSteve French * We need to be sure that all dirty pages are written and the server 266738c8a9a5SSteve French * has actual ctime, mtime and file length. 266838c8a9a5SSteve French */ 266938c8a9a5SSteve French if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) && 267038c8a9a5SSteve French !CIFS_CACHE_READ(CIFS_I(inode)) && 267138c8a9a5SSteve French inode->i_mapping && inode->i_mapping->nrpages != 0) { 267238c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 267338c8a9a5SSteve French if (rc) { 267438c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 267538c8a9a5SSteve French return rc; 267638c8a9a5SSteve French } 267738c8a9a5SSteve French } 267838c8a9a5SSteve French 267938c8a9a5SSteve French if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC) 268038c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force revalidate */ 268138c8a9a5SSteve French 268238c8a9a5SSteve French /* 268338c8a9a5SSteve French * If the caller doesn't require syncing, only sync if 268438c8a9a5SSteve French * necessary (e.g. due to earlier truncate or setattr 268538c8a9a5SSteve French * invalidating the cached metadata) 268638c8a9a5SSteve French */ 268738c8a9a5SSteve French if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) || 268838c8a9a5SSteve French (CIFS_I(inode)->time == 0)) { 268938c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 269038c8a9a5SSteve French if (rc) 269138c8a9a5SSteve French return rc; 269238c8a9a5SSteve French } 269338c8a9a5SSteve French 26940d72b928SJeff Layton generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 269538c8a9a5SSteve French stat->blksize = cifs_sb->ctx->bsize; 269638c8a9a5SSteve French stat->ino = CIFS_I(inode)->uniqueid; 269738c8a9a5SSteve French 269838c8a9a5SSteve French /* old CIFS Unix Extensions doesn't return create time */ 269938c8a9a5SSteve French if (CIFS_I(inode)->createtime) { 270038c8a9a5SSteve French stat->result_mask |= STATX_BTIME; 270138c8a9a5SSteve French stat->btime = 270238c8a9a5SSteve French cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); 270338c8a9a5SSteve French } 270438c8a9a5SSteve French 270538c8a9a5SSteve French stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED); 270638c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) 270738c8a9a5SSteve French stat->attributes |= STATX_ATTR_COMPRESSED; 270838c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED) 270938c8a9a5SSteve French stat->attributes |= STATX_ATTR_ENCRYPTED; 271038c8a9a5SSteve French 271138c8a9a5SSteve French /* 271238c8a9a5SSteve French * If on a multiuser mount without unix extensions or cifsacl being 271338c8a9a5SSteve French * enabled, and the admin hasn't overridden them, set the ownership 271438c8a9a5SSteve French * to the fsuid/fsgid of the current process. 271538c8a9a5SSteve French */ 271638c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && 271738c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 271838c8a9a5SSteve French !tcon->unix_ext) { 271938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) 272038c8a9a5SSteve French stat->uid = current_fsuid(); 272138c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) 272238c8a9a5SSteve French stat->gid = current_fsgid(); 272338c8a9a5SSteve French } 272438c8a9a5SSteve French return 0; 272538c8a9a5SSteve French } 272638c8a9a5SSteve French 272738c8a9a5SSteve French int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, 272838c8a9a5SSteve French u64 len) 272938c8a9a5SSteve French { 273038c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 273138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->netfs.inode.i_sb); 273238c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 273338c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 273438c8a9a5SSteve French struct cifsFileInfo *cfile; 273538c8a9a5SSteve French int rc; 273638c8a9a5SSteve French 273738c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 273838c8a9a5SSteve French return -EIO; 273938c8a9a5SSteve French 274038c8a9a5SSteve French /* 274138c8a9a5SSteve French * We need to be sure that all dirty pages are written as they 274238c8a9a5SSteve French * might fill holes on the server. 274338c8a9a5SSteve French */ 274438c8a9a5SSteve French if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && 274538c8a9a5SSteve French inode->i_mapping->nrpages != 0) { 274638c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 274738c8a9a5SSteve French if (rc) { 274838c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 274938c8a9a5SSteve French return rc; 275038c8a9a5SSteve French } 275138c8a9a5SSteve French } 275238c8a9a5SSteve French 275338c8a9a5SSteve French cfile = find_readable_file(cifs_i, false); 275438c8a9a5SSteve French if (cfile == NULL) 275538c8a9a5SSteve French return -EINVAL; 275638c8a9a5SSteve French 275738c8a9a5SSteve French if (server->ops->fiemap) { 275838c8a9a5SSteve French rc = server->ops->fiemap(tcon, cfile, fei, start, len); 275938c8a9a5SSteve French cifsFileInfo_put(cfile); 276038c8a9a5SSteve French return rc; 276138c8a9a5SSteve French } 276238c8a9a5SSteve French 276338c8a9a5SSteve French cifsFileInfo_put(cfile); 2764ebc3d4e4SSteve French return -EOPNOTSUPP; 276538c8a9a5SSteve French } 276638c8a9a5SSteve French 276738c8a9a5SSteve French int cifs_truncate_page(struct address_space *mapping, loff_t from) 276838c8a9a5SSteve French { 276938c8a9a5SSteve French pgoff_t index = from >> PAGE_SHIFT; 277038c8a9a5SSteve French unsigned offset = from & (PAGE_SIZE - 1); 277138c8a9a5SSteve French struct page *page; 277238c8a9a5SSteve French int rc = 0; 277338c8a9a5SSteve French 277438c8a9a5SSteve French page = grab_cache_page(mapping, index); 277538c8a9a5SSteve French if (!page) 277638c8a9a5SSteve French return -ENOMEM; 277738c8a9a5SSteve French 277838c8a9a5SSteve French zero_user_segment(page, offset, PAGE_SIZE); 277938c8a9a5SSteve French unlock_page(page); 278038c8a9a5SSteve French put_page(page); 278138c8a9a5SSteve French return rc; 278238c8a9a5SSteve French } 278338c8a9a5SSteve French 278438c8a9a5SSteve French void cifs_setsize(struct inode *inode, loff_t offset) 278538c8a9a5SSteve French { 278638c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 278738c8a9a5SSteve French 278838c8a9a5SSteve French spin_lock(&inode->i_lock); 278938c8a9a5SSteve French i_size_write(inode, offset); 279038c8a9a5SSteve French spin_unlock(&inode->i_lock); 279138c8a9a5SSteve French 279238c8a9a5SSteve French /* Cached inode must be refreshed on truncate */ 279338c8a9a5SSteve French cifs_i->time = 0; 279438c8a9a5SSteve French truncate_pagecache(inode, offset); 279538c8a9a5SSteve French } 279638c8a9a5SSteve French 279738c8a9a5SSteve French static int 279838c8a9a5SSteve French cifs_set_file_size(struct inode *inode, struct iattr *attrs, 279938c8a9a5SSteve French unsigned int xid, const char *full_path) 280038c8a9a5SSteve French { 280138c8a9a5SSteve French int rc; 280238c8a9a5SSteve French struct cifsFileInfo *open_file; 280338c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 280438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 280538c8a9a5SSteve French struct tcon_link *tlink = NULL; 280638c8a9a5SSteve French struct cifs_tcon *tcon = NULL; 280738c8a9a5SSteve French struct TCP_Server_Info *server; 280838c8a9a5SSteve French 280938c8a9a5SSteve French /* 281038c8a9a5SSteve French * To avoid spurious oplock breaks from server, in the case of 281138c8a9a5SSteve French * inodes that we already have open, avoid doing path based 281238c8a9a5SSteve French * setting of file size if we can do it by handle. 281338c8a9a5SSteve French * This keeps our caching token (oplock) and avoids timeouts 281438c8a9a5SSteve French * when the local oplock break takes longer to flush 281538c8a9a5SSteve French * writebehind data than the SMB timeout for the SetPathInfo 281638c8a9a5SSteve French * request would allow 281738c8a9a5SSteve French */ 281838c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 281938c8a9a5SSteve French if (open_file) { 282038c8a9a5SSteve French tcon = tlink_tcon(open_file->tlink); 282138c8a9a5SSteve French server = tcon->ses->server; 282238c8a9a5SSteve French if (server->ops->set_file_size) 282338c8a9a5SSteve French rc = server->ops->set_file_size(xid, tcon, open_file, 282438c8a9a5SSteve French attrs->ia_size, false); 282538c8a9a5SSteve French else 282638c8a9a5SSteve French rc = -ENOSYS; 282738c8a9a5SSteve French cifsFileInfo_put(open_file); 282838c8a9a5SSteve French cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc); 282938c8a9a5SSteve French } else 283038c8a9a5SSteve French rc = -EINVAL; 283138c8a9a5SSteve French 283238c8a9a5SSteve French if (!rc) 283338c8a9a5SSteve French goto set_size_out; 283438c8a9a5SSteve French 283538c8a9a5SSteve French if (tcon == NULL) { 283638c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 283738c8a9a5SSteve French if (IS_ERR(tlink)) 283838c8a9a5SSteve French return PTR_ERR(tlink); 283938c8a9a5SSteve French tcon = tlink_tcon(tlink); 284038c8a9a5SSteve French server = tcon->ses->server; 284138c8a9a5SSteve French } 284238c8a9a5SSteve French 284338c8a9a5SSteve French /* 284438c8a9a5SSteve French * Set file size by pathname rather than by handle either because no 284538c8a9a5SSteve French * valid, writeable file handle for it was found or because there was 284638c8a9a5SSteve French * an error setting it by handle. 284738c8a9a5SSteve French */ 284838c8a9a5SSteve French if (server->ops->set_path_size) 284938c8a9a5SSteve French rc = server->ops->set_path_size(xid, tcon, full_path, 285038c8a9a5SSteve French attrs->ia_size, cifs_sb, false); 285138c8a9a5SSteve French else 285238c8a9a5SSteve French rc = -ENOSYS; 285338c8a9a5SSteve French cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc); 285438c8a9a5SSteve French 285538c8a9a5SSteve French if (tlink) 285638c8a9a5SSteve French cifs_put_tlink(tlink); 285738c8a9a5SSteve French 285838c8a9a5SSteve French set_size_out: 285938c8a9a5SSteve French if (rc == 0) { 286038c8a9a5SSteve French cifsInode->server_eof = attrs->ia_size; 286138c8a9a5SSteve French cifs_setsize(inode, attrs->ia_size); 286238c8a9a5SSteve French /* 286338c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), but instead 286438c8a9a5SSteve French * 512 byte (2**9) size is required for calculating num blocks. 286538c8a9a5SSteve French * Until we can query the server for actual allocation size, 286638c8a9a5SSteve French * this is best estimate we have for blocks allocated for a file 286738c8a9a5SSteve French * Number of blocks must be rounded up so size 1 is not 0 blocks 286838c8a9a5SSteve French */ 286938c8a9a5SSteve French inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9; 287038c8a9a5SSteve French 287138c8a9a5SSteve French /* 287238c8a9a5SSteve French * The man page of truncate says if the size changed, 287338c8a9a5SSteve French * then the st_ctime and st_mtime fields for the file 287438c8a9a5SSteve French * are updated. 287538c8a9a5SSteve French */ 287638c8a9a5SSteve French attrs->ia_ctime = attrs->ia_mtime = current_time(inode); 287738c8a9a5SSteve French attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME; 287838c8a9a5SSteve French 287938c8a9a5SSteve French cifs_truncate_page(inode->i_mapping, inode->i_size); 288038c8a9a5SSteve French } 288138c8a9a5SSteve French 288238c8a9a5SSteve French return rc; 288338c8a9a5SSteve French } 288438c8a9a5SSteve French 288538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 288638c8a9a5SSteve French static int 288738c8a9a5SSteve French cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 288838c8a9a5SSteve French { 288938c8a9a5SSteve French int rc; 289038c8a9a5SSteve French unsigned int xid; 289138c8a9a5SSteve French const char *full_path; 289238c8a9a5SSteve French void *page = alloc_dentry_path(); 289338c8a9a5SSteve French struct inode *inode = d_inode(direntry); 289438c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 289538c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 289638c8a9a5SSteve French struct tcon_link *tlink; 289738c8a9a5SSteve French struct cifs_tcon *pTcon; 289838c8a9a5SSteve French struct cifs_unix_set_info_args *args = NULL; 289938c8a9a5SSteve French struct cifsFileInfo *open_file; 290038c8a9a5SSteve French 290138c8a9a5SSteve French cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n", 290238c8a9a5SSteve French direntry, attrs->ia_valid); 290338c8a9a5SSteve French 290438c8a9a5SSteve French xid = get_xid(); 290538c8a9a5SSteve French 290638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 290738c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 290838c8a9a5SSteve French 290938c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 291038c8a9a5SSteve French if (rc < 0) 291138c8a9a5SSteve French goto out; 291238c8a9a5SSteve French 291338c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 291438c8a9a5SSteve French if (IS_ERR(full_path)) { 291538c8a9a5SSteve French rc = PTR_ERR(full_path); 291638c8a9a5SSteve French goto out; 291738c8a9a5SSteve French } 291838c8a9a5SSteve French 291938c8a9a5SSteve French /* 292038c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 292138c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the 292238c8a9a5SSteve French * ownership or mode then we may also need to do this. Here, we take 292338c8a9a5SSteve French * the safe way out and just do the flush on all setattr requests. If 292438c8a9a5SSteve French * the flush returns error, store it to report later and continue. 292538c8a9a5SSteve French * 292638c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 292738c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 292838c8a9a5SSteve French * the flush returns error? 292938c8a9a5SSteve French */ 293038c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 293138c8a9a5SSteve French if (is_interrupt_error(rc)) { 293238c8a9a5SSteve French rc = -ERESTARTSYS; 293338c8a9a5SSteve French goto out; 293438c8a9a5SSteve French } 293538c8a9a5SSteve French 293638c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 293738c8a9a5SSteve French rc = 0; 293838c8a9a5SSteve French 293938c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 294038c8a9a5SSteve French rc = cifs_set_file_size(inode, attrs, xid, full_path); 294138c8a9a5SSteve French if (rc != 0) 294238c8a9a5SSteve French goto out; 294338c8a9a5SSteve French } 294438c8a9a5SSteve French 294538c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 294638c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 294738c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 294838c8a9a5SSteve French 294938c8a9a5SSteve French args = kmalloc(sizeof(*args), GFP_KERNEL); 295038c8a9a5SSteve French if (args == NULL) { 295138c8a9a5SSteve French rc = -ENOMEM; 295238c8a9a5SSteve French goto out; 295338c8a9a5SSteve French } 295438c8a9a5SSteve French 295538c8a9a5SSteve French /* set up the struct */ 295638c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) 295738c8a9a5SSteve French args->mode = attrs->ia_mode; 295838c8a9a5SSteve French else 295938c8a9a5SSteve French args->mode = NO_CHANGE_64; 296038c8a9a5SSteve French 296138c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 296238c8a9a5SSteve French args->uid = attrs->ia_uid; 296338c8a9a5SSteve French else 296438c8a9a5SSteve French args->uid = INVALID_UID; /* no change */ 296538c8a9a5SSteve French 296638c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 296738c8a9a5SSteve French args->gid = attrs->ia_gid; 296838c8a9a5SSteve French else 296938c8a9a5SSteve French args->gid = INVALID_GID; /* no change */ 297038c8a9a5SSteve French 297138c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) 297238c8a9a5SSteve French args->atime = cifs_UnixTimeToNT(attrs->ia_atime); 297338c8a9a5SSteve French else 297438c8a9a5SSteve French args->atime = NO_CHANGE_64; 297538c8a9a5SSteve French 297638c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) 297738c8a9a5SSteve French args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); 297838c8a9a5SSteve French else 297938c8a9a5SSteve French args->mtime = NO_CHANGE_64; 298038c8a9a5SSteve French 298138c8a9a5SSteve French if (attrs->ia_valid & ATTR_CTIME) 298238c8a9a5SSteve French args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); 298338c8a9a5SSteve French else 298438c8a9a5SSteve French args->ctime = NO_CHANGE_64; 298538c8a9a5SSteve French 298638c8a9a5SSteve French args->device = 0; 298738c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 298838c8a9a5SSteve French if (open_file) { 298938c8a9a5SSteve French u16 nfid = open_file->fid.netfid; 299038c8a9a5SSteve French u32 npid = open_file->pid; 299138c8a9a5SSteve French pTcon = tlink_tcon(open_file->tlink); 299238c8a9a5SSteve French rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); 299338c8a9a5SSteve French cifsFileInfo_put(open_file); 299438c8a9a5SSteve French } else { 299538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 299638c8a9a5SSteve French if (IS_ERR(tlink)) { 299738c8a9a5SSteve French rc = PTR_ERR(tlink); 299838c8a9a5SSteve French goto out; 299938c8a9a5SSteve French } 300038c8a9a5SSteve French pTcon = tlink_tcon(tlink); 300138c8a9a5SSteve French rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, 300238c8a9a5SSteve French cifs_sb->local_nls, 300338c8a9a5SSteve French cifs_remap(cifs_sb)); 300438c8a9a5SSteve French cifs_put_tlink(tlink); 300538c8a9a5SSteve French } 300638c8a9a5SSteve French 300738c8a9a5SSteve French if (rc) 300838c8a9a5SSteve French goto out; 300938c8a9a5SSteve French 301038c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 301138c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 301238c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 301338c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 301438c8a9a5SSteve French } 301538c8a9a5SSteve French 301638c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 301738c8a9a5SSteve French mark_inode_dirty(inode); 301838c8a9a5SSteve French 301938c8a9a5SSteve French /* force revalidate when any of these times are set since some 302038c8a9a5SSteve French of the fs types (eg ext3, fat) do not have fine enough 302138c8a9a5SSteve French time granularity to match protocol, and we do not have a 302238c8a9a5SSteve French a way (yet) to query the server fs's time granularity (and 302338c8a9a5SSteve French whether it rounds times down). 302438c8a9a5SSteve French */ 302538c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) 302638c8a9a5SSteve French cifsInode->time = 0; 302738c8a9a5SSteve French out: 302838c8a9a5SSteve French kfree(args); 302938c8a9a5SSteve French free_dentry_path(page); 303038c8a9a5SSteve French free_xid(xid); 303138c8a9a5SSteve French return rc; 303238c8a9a5SSteve French } 303338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 303438c8a9a5SSteve French 303538c8a9a5SSteve French static int 303638c8a9a5SSteve French cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) 303738c8a9a5SSteve French { 303838c8a9a5SSteve French unsigned int xid; 303938c8a9a5SSteve French kuid_t uid = INVALID_UID; 304038c8a9a5SSteve French kgid_t gid = INVALID_GID; 304138c8a9a5SSteve French struct inode *inode = d_inode(direntry); 304238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 304338c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 304438c8a9a5SSteve French struct cifsFileInfo *wfile; 304538c8a9a5SSteve French struct cifs_tcon *tcon; 304638c8a9a5SSteve French const char *full_path; 304738c8a9a5SSteve French void *page = alloc_dentry_path(); 304838c8a9a5SSteve French int rc = -EACCES; 304938c8a9a5SSteve French __u32 dosattr = 0; 305038c8a9a5SSteve French __u64 mode = NO_CHANGE_64; 305138c8a9a5SSteve French 305238c8a9a5SSteve French xid = get_xid(); 305338c8a9a5SSteve French 305438c8a9a5SSteve French cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n", 305538c8a9a5SSteve French direntry, attrs->ia_valid); 305638c8a9a5SSteve French 305738c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 305838c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 305938c8a9a5SSteve French 306038c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 306138c8a9a5SSteve French if (rc < 0) 306238c8a9a5SSteve French goto cifs_setattr_exit; 306338c8a9a5SSteve French 306438c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 306538c8a9a5SSteve French if (IS_ERR(full_path)) { 306638c8a9a5SSteve French rc = PTR_ERR(full_path); 306738c8a9a5SSteve French goto cifs_setattr_exit; 306838c8a9a5SSteve French } 306938c8a9a5SSteve French 307038c8a9a5SSteve French /* 307138c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 307238c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data 307338c8a9a5SSteve French * returns error, store it to report later and continue. 307438c8a9a5SSteve French * 307538c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 307638c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 307738c8a9a5SSteve French * the flush returns error? Do we need to check for ATTR_MTIME_SET flag? 307838c8a9a5SSteve French */ 307938c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) { 308038c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 308138c8a9a5SSteve French if (is_interrupt_error(rc)) { 308238c8a9a5SSteve French rc = -ERESTARTSYS; 308338c8a9a5SSteve French goto cifs_setattr_exit; 308438c8a9a5SSteve French } 308538c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 308638c8a9a5SSteve French } 308738c8a9a5SSteve French 308838c8a9a5SSteve French rc = 0; 308938c8a9a5SSteve French 309038c8a9a5SSteve French if ((attrs->ia_valid & ATTR_MTIME) && 309138c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { 309238c8a9a5SSteve French rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile); 309338c8a9a5SSteve French if (!rc) { 309438c8a9a5SSteve French tcon = tlink_tcon(wfile->tlink); 309538c8a9a5SSteve French rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid); 309638c8a9a5SSteve French cifsFileInfo_put(wfile); 309738c8a9a5SSteve French if (rc) 309838c8a9a5SSteve French goto cifs_setattr_exit; 309938c8a9a5SSteve French } else if (rc != -EBADF) 310038c8a9a5SSteve French goto cifs_setattr_exit; 310138c8a9a5SSteve French else 310238c8a9a5SSteve French rc = 0; 310338c8a9a5SSteve French } 310438c8a9a5SSteve French 310538c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 310638c8a9a5SSteve French rc = cifs_set_file_size(inode, attrs, xid, full_path); 310738c8a9a5SSteve French if (rc != 0) 310838c8a9a5SSteve French goto cifs_setattr_exit; 310938c8a9a5SSteve French } 311038c8a9a5SSteve French 311138c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 311238c8a9a5SSteve French uid = attrs->ia_uid; 311338c8a9a5SSteve French 311438c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 311538c8a9a5SSteve French gid = attrs->ia_gid; 311638c8a9a5SSteve French 311738c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 311838c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 311938c8a9a5SSteve French if (uid_valid(uid) || gid_valid(gid)) { 312038c8a9a5SSteve French mode = NO_CHANGE_64; 312138c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 312238c8a9a5SSteve French uid, gid); 312338c8a9a5SSteve French if (rc) { 312438c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting id failed with error: %d\n", 312538c8a9a5SSteve French __func__, rc); 312638c8a9a5SSteve French goto cifs_setattr_exit; 312738c8a9a5SSteve French } 312838c8a9a5SSteve French } 312938c8a9a5SSteve French } else 313038c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) 313138c8a9a5SSteve French attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 313238c8a9a5SSteve French 313338c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 313438c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 313538c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 313638c8a9a5SSteve French 313738c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) { 313838c8a9a5SSteve French mode = attrs->ia_mode; 313938c8a9a5SSteve French rc = 0; 314038c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 314138c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 314238c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 314338c8a9a5SSteve French INVALID_UID, INVALID_GID); 314438c8a9a5SSteve French if (rc) { 314538c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n", 314638c8a9a5SSteve French __func__, rc); 314738c8a9a5SSteve French goto cifs_setattr_exit; 314838c8a9a5SSteve French } 314938c8a9a5SSteve French 315038c8a9a5SSteve French /* 315138c8a9a5SSteve French * In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes. 315238c8a9a5SSteve French * Pick up the actual mode bits that were set. 315338c8a9a5SSteve French */ 315438c8a9a5SSteve French if (mode != attrs->ia_mode) 315538c8a9a5SSteve French attrs->ia_mode = mode; 315638c8a9a5SSteve French } else 315738c8a9a5SSteve French if (((mode & S_IWUGO) == 0) && 315838c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 315938c8a9a5SSteve French 316038c8a9a5SSteve French dosattr = cifsInode->cifsAttrs | ATTR_READONLY; 316138c8a9a5SSteve French 316238c8a9a5SSteve French /* fix up mode if we're not using dynperm */ 316338c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) 316438c8a9a5SSteve French attrs->ia_mode = inode->i_mode & ~S_IWUGO; 316538c8a9a5SSteve French } else if ((mode & S_IWUGO) && 316638c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY)) { 316738c8a9a5SSteve French 316838c8a9a5SSteve French dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; 316938c8a9a5SSteve French /* Attributes of 0 are ignored */ 317038c8a9a5SSteve French if (dosattr == 0) 317138c8a9a5SSteve French dosattr |= ATTR_NORMAL; 317238c8a9a5SSteve French 317338c8a9a5SSteve French /* reset local inode permissions to normal */ 317438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 317538c8a9a5SSteve French attrs->ia_mode &= ~(S_IALLUGO); 317638c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) 317738c8a9a5SSteve French attrs->ia_mode |= 317838c8a9a5SSteve French cifs_sb->ctx->dir_mode; 317938c8a9a5SSteve French else 318038c8a9a5SSteve French attrs->ia_mode |= 318138c8a9a5SSteve French cifs_sb->ctx->file_mode; 318238c8a9a5SSteve French } 318338c8a9a5SSteve French } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 318438c8a9a5SSteve French /* ignore mode change - ATTR_READONLY hasn't changed */ 318538c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 318638c8a9a5SSteve French } 318738c8a9a5SSteve French } 318838c8a9a5SSteve French 318938c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || 319038c8a9a5SSteve French ((attrs->ia_valid & ATTR_MODE) && dosattr)) { 319138c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 319238c8a9a5SSteve French /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ 319338c8a9a5SSteve French 319438c8a9a5SSteve French /* Even if error on time set, no sense failing the call if 319538c8a9a5SSteve French the server would set the time to a reasonable value anyway, 319638c8a9a5SSteve French and this check ensures that we are not being called from 319738c8a9a5SSteve French sys_utimes in which case we ought to fail the call back to 319838c8a9a5SSteve French the user when the server rejects the call */ 319938c8a9a5SSteve French if ((rc) && (attrs->ia_valid & 320038c8a9a5SSteve French (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) 320138c8a9a5SSteve French rc = 0; 320238c8a9a5SSteve French } 320338c8a9a5SSteve French 320438c8a9a5SSteve French /* do not need local check to inode_check_ok since the server does 320538c8a9a5SSteve French that */ 320638c8a9a5SSteve French if (rc) 320738c8a9a5SSteve French goto cifs_setattr_exit; 320838c8a9a5SSteve French 320938c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 321038c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 321138c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 321238c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 321338c8a9a5SSteve French } 321438c8a9a5SSteve French 321538c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 321638c8a9a5SSteve French mark_inode_dirty(inode); 321738c8a9a5SSteve French 321838c8a9a5SSteve French cifs_setattr_exit: 321938c8a9a5SSteve French free_xid(xid); 322038c8a9a5SSteve French free_dentry_path(page); 322138c8a9a5SSteve French return rc; 322238c8a9a5SSteve French } 322338c8a9a5SSteve French 322438c8a9a5SSteve French int 322538c8a9a5SSteve French cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry, 322638c8a9a5SSteve French struct iattr *attrs) 322738c8a9a5SSteve French { 322838c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 322938c8a9a5SSteve French int rc, retries = 0; 323038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 323138c8a9a5SSteve French struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); 323238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 323338c8a9a5SSteve French 323438c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 323538c8a9a5SSteve French return -EIO; 323638c8a9a5SSteve French 323738c8a9a5SSteve French do { 323838c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 323938c8a9a5SSteve French if (pTcon->unix_ext) 324038c8a9a5SSteve French rc = cifs_setattr_unix(direntry, attrs); 324138c8a9a5SSteve French else 324238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 324338c8a9a5SSteve French rc = cifs_setattr_nounix(direntry, attrs); 324438c8a9a5SSteve French retries++; 324538c8a9a5SSteve French } while (is_retryable_error(rc) && retries < 2); 324638c8a9a5SSteve French 324738c8a9a5SSteve French /* BB: add cifs_setattr_legacy for really old servers */ 324838c8a9a5SSteve French return rc; 324938c8a9a5SSteve French } 3250