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); 8538c8a9a5SSteve French 8638c8a9a5SSteve French cifs_dbg(FYI, "%s: revalidating inode %llu\n", 8738c8a9a5SSteve French __func__, cifs_i->uniqueid); 8838c8a9a5SSteve French 8938c8a9a5SSteve French if (inode->i_state & I_NEW) { 9038c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is new\n", 9138c8a9a5SSteve French __func__, cifs_i->uniqueid); 9238c8a9a5SSteve French return; 9338c8a9a5SSteve French } 9438c8a9a5SSteve French 9538c8a9a5SSteve French /* don't bother with revalidation if we have an oplock */ 9638c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) { 9738c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is oplocked\n", 9838c8a9a5SSteve French __func__, cifs_i->uniqueid); 9938c8a9a5SSteve French return; 10038c8a9a5SSteve French } 10138c8a9a5SSteve French 10238c8a9a5SSteve French /* revalidate if mtime or size have changed */ 10338c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 10438c8a9a5SSteve French if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) && 10538c8a9a5SSteve French cifs_i->server_eof == fattr->cf_eof) { 10638c8a9a5SSteve French cifs_dbg(FYI, "%s: inode %llu is unchanged\n", 10738c8a9a5SSteve French __func__, cifs_i->uniqueid); 10838c8a9a5SSteve French return; 10938c8a9a5SSteve French } 11038c8a9a5SSteve French 11138c8a9a5SSteve French cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n", 11238c8a9a5SSteve French __func__, cifs_i->uniqueid); 11338c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags); 11438c8a9a5SSteve French /* Invalidate fscache cookie */ 11538c8a9a5SSteve French cifs_fscache_fill_coherency(&cifs_i->netfs.inode, &cd); 11638c8a9a5SSteve French fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0); 11738c8a9a5SSteve French } 11838c8a9a5SSteve French 11938c8a9a5SSteve French /* 12038c8a9a5SSteve French * copy nlink to the inode, unless it wasn't provided. Provide 12138c8a9a5SSteve French * sane values if we don't have an existing one and none was provided 12238c8a9a5SSteve French */ 12338c8a9a5SSteve French static void 12438c8a9a5SSteve French cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) 12538c8a9a5SSteve French { 12638c8a9a5SSteve French /* 12738c8a9a5SSteve French * if we're in a situation where we can't trust what we 12838c8a9a5SSteve French * got from the server (readdir, some non-unix cases) 12938c8a9a5SSteve French * fake reasonable values 13038c8a9a5SSteve French */ 13138c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) { 13238c8a9a5SSteve French /* only provide fake values on a new inode */ 13338c8a9a5SSteve French if (inode->i_state & I_NEW) { 13438c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_DIRECTORY) 13538c8a9a5SSteve French set_nlink(inode, 2); 13638c8a9a5SSteve French else 13738c8a9a5SSteve French set_nlink(inode, 1); 13838c8a9a5SSteve French } 13938c8a9a5SSteve French return; 14038c8a9a5SSteve French } 14138c8a9a5SSteve French 14238c8a9a5SSteve French /* we trust the server, so update it */ 14338c8a9a5SSteve French set_nlink(inode, fattr->cf_nlink); 14438c8a9a5SSteve French } 14538c8a9a5SSteve French 14638c8a9a5SSteve French /* populate an inode with info from a cifs_fattr struct */ 14738c8a9a5SSteve French int 14838c8a9a5SSteve French cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) 14938c8a9a5SSteve French { 15038c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 15138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 15238c8a9a5SSteve French 15338c8a9a5SSteve French if (!(inode->i_state & I_NEW) && 15438c8a9a5SSteve French unlikely(inode_wrong_type(inode, fattr->cf_mode))) { 15538c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force reval */ 15638c8a9a5SSteve French return -ESTALE; 15738c8a9a5SSteve French } 15838c8a9a5SSteve French 15938c8a9a5SSteve French cifs_revalidate_cache(inode, fattr); 16038c8a9a5SSteve French 16138c8a9a5SSteve French spin_lock(&inode->i_lock); 16238c8a9a5SSteve French fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); 16338c8a9a5SSteve French fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode); 16438c8a9a5SSteve French fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode); 16538c8a9a5SSteve French /* we do not want atime to be less than mtime, it broke some apps */ 16638c8a9a5SSteve French if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0) 16738c8a9a5SSteve French inode->i_atime = fattr->cf_mtime; 16838c8a9a5SSteve French else 16938c8a9a5SSteve French inode->i_atime = fattr->cf_atime; 17038c8a9a5SSteve French inode->i_mtime = fattr->cf_mtime; 17138c8a9a5SSteve French inode->i_ctime = fattr->cf_ctime; 17238c8a9a5SSteve French inode->i_rdev = fattr->cf_rdev; 17338c8a9a5SSteve French cifs_nlink_fattr_to_inode(inode, fattr); 17438c8a9a5SSteve French inode->i_uid = fattr->cf_uid; 17538c8a9a5SSteve French inode->i_gid = fattr->cf_gid; 17638c8a9a5SSteve French 17738c8a9a5SSteve French /* if dynperm is set, don't clobber existing mode */ 17838c8a9a5SSteve French if (inode->i_state & I_NEW || 17938c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) 18038c8a9a5SSteve French inode->i_mode = fattr->cf_mode; 18138c8a9a5SSteve French 18238c8a9a5SSteve French cifs_i->cifsAttrs = fattr->cf_cifsattrs; 18338c8a9a5SSteve French 18438c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) 18538c8a9a5SSteve French cifs_i->time = 0; 18638c8a9a5SSteve French else 18738c8a9a5SSteve French cifs_i->time = jiffies; 18838c8a9a5SSteve French 18938c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING) 19038c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19138c8a9a5SSteve French else 19238c8a9a5SSteve French clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); 19338c8a9a5SSteve French 19438c8a9a5SSteve French cifs_i->server_eof = fattr->cf_eof; 19538c8a9a5SSteve French /* 19638c8a9a5SSteve French * Can't safely change the file size here if the client is writing to 19738c8a9a5SSteve French * it due to potential races. 19838c8a9a5SSteve French */ 19938c8a9a5SSteve French if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { 20038c8a9a5SSteve French i_size_write(inode, fattr->cf_eof); 20138c8a9a5SSteve French 20238c8a9a5SSteve French /* 20338c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), 20438c8a9a5SSteve French * but instead 512 byte (2**9) size is required for 20538c8a9a5SSteve French * calculating num blocks. 20638c8a9a5SSteve French */ 20738c8a9a5SSteve French inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; 20838c8a9a5SSteve French } 20938c8a9a5SSteve French 21038c8a9a5SSteve French if (S_ISLNK(fattr->cf_mode)) { 21138c8a9a5SSteve French kfree(cifs_i->symlink_target); 21238c8a9a5SSteve French cifs_i->symlink_target = fattr->cf_symlink_target; 21338c8a9a5SSteve French fattr->cf_symlink_target = NULL; 21438c8a9a5SSteve French } 21538c8a9a5SSteve French spin_unlock(&inode->i_lock); 21638c8a9a5SSteve French 217*a18280e7SPaulo Alcantara if (fattr->cf_flags & CIFS_FATTR_JUNCTION) 21838c8a9a5SSteve French inode->i_flags |= S_AUTOMOUNT; 21938c8a9a5SSteve French if (inode->i_state & I_NEW) 22038c8a9a5SSteve French cifs_set_ops(inode); 22138c8a9a5SSteve French return 0; 22238c8a9a5SSteve French } 22338c8a9a5SSteve French 22438c8a9a5SSteve French void 22538c8a9a5SSteve French cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr) 22638c8a9a5SSteve French { 22738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 22838c8a9a5SSteve French 22938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 23038c8a9a5SSteve French return; 23138c8a9a5SSteve French 23238c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 23338c8a9a5SSteve French } 23438c8a9a5SSteve French 23538c8a9a5SSteve French /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ 23638c8a9a5SSteve French void 23738c8a9a5SSteve French cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, 23838c8a9a5SSteve French struct cifs_sb_info *cifs_sb) 23938c8a9a5SSteve French { 24038c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 24138c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); 24238c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); 24338c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 24438c8a9a5SSteve French 24538c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 24638c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); 24738c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); 24838c8a9a5SSteve French /* old POSIX extensions don't get create time */ 24938c8a9a5SSteve French 25038c8a9a5SSteve French fattr->cf_mode = le64_to_cpu(info->Permissions); 25138c8a9a5SSteve French 25238c8a9a5SSteve French /* 25338c8a9a5SSteve French * Since we set the inode type below we need to mask off 25438c8a9a5SSteve French * to avoid strange results if bits set above. 25538c8a9a5SSteve French */ 25638c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 25738c8a9a5SSteve French switch (le32_to_cpu(info->Type)) { 25838c8a9a5SSteve French case UNIX_FILE: 25938c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 26038c8a9a5SSteve French fattr->cf_dtype = DT_REG; 26138c8a9a5SSteve French break; 26238c8a9a5SSteve French case UNIX_SYMLINK: 26338c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 26438c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 26538c8a9a5SSteve French break; 26638c8a9a5SSteve French case UNIX_DIR: 26738c8a9a5SSteve French fattr->cf_mode |= S_IFDIR; 26838c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 26938c8a9a5SSteve French break; 27038c8a9a5SSteve French case UNIX_CHARDEV: 27138c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 27238c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 27338c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 27438c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 27538c8a9a5SSteve French break; 27638c8a9a5SSteve French case UNIX_BLOCKDEV: 27738c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 27838c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 27938c8a9a5SSteve French fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), 28038c8a9a5SSteve French le64_to_cpu(info->DevMinor) & MINORMASK); 28138c8a9a5SSteve French break; 28238c8a9a5SSteve French case UNIX_FIFO: 28338c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 28438c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 28538c8a9a5SSteve French break; 28638c8a9a5SSteve French case UNIX_SOCKET: 28738c8a9a5SSteve French fattr->cf_mode |= S_IFSOCK; 28838c8a9a5SSteve French fattr->cf_dtype = DT_SOCK; 28938c8a9a5SSteve French break; 29038c8a9a5SSteve French default: 29138c8a9a5SSteve French /* safest to call it a file if we do not know */ 29238c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 29338c8a9a5SSteve French fattr->cf_dtype = DT_REG; 29438c8a9a5SSteve French cifs_dbg(FYI, "unknown type %d\n", le32_to_cpu(info->Type)); 29538c8a9a5SSteve French break; 29638c8a9a5SSteve French } 29738c8a9a5SSteve French 29838c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 29938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { 30038c8a9a5SSteve French u64 id = le64_to_cpu(info->Uid); 30138c8a9a5SSteve French if (id < ((uid_t)-1)) { 30238c8a9a5SSteve French kuid_t uid = make_kuid(&init_user_ns, id); 30338c8a9a5SSteve French if (uid_valid(uid)) 30438c8a9a5SSteve French fattr->cf_uid = uid; 30538c8a9a5SSteve French } 30638c8a9a5SSteve French } 30738c8a9a5SSteve French 30838c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 30938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { 31038c8a9a5SSteve French u64 id = le64_to_cpu(info->Gid); 31138c8a9a5SSteve French if (id < ((gid_t)-1)) { 31238c8a9a5SSteve French kgid_t gid = make_kgid(&init_user_ns, id); 31338c8a9a5SSteve French if (gid_valid(gid)) 31438c8a9a5SSteve French fattr->cf_gid = gid; 31538c8a9a5SSteve French } 31638c8a9a5SSteve French } 31738c8a9a5SSteve French 31838c8a9a5SSteve French fattr->cf_nlink = le64_to_cpu(info->Nlinks); 31938c8a9a5SSteve French } 32038c8a9a5SSteve French 32138c8a9a5SSteve French /* 32238c8a9a5SSteve French * Fill a cifs_fattr struct with fake inode info. 32338c8a9a5SSteve French * 32438c8a9a5SSteve French * Needed to setup cifs_fattr data for the directory which is the 32538c8a9a5SSteve French * junction to the new submount (ie to setup the fake directory 326*a18280e7SPaulo Alcantara * which represents a DFS referral or reparse mount point). 32738c8a9a5SSteve French */ 328*a18280e7SPaulo Alcantara static void cifs_create_junction_fattr(struct cifs_fattr *fattr, 329*a18280e7SPaulo Alcantara struct super_block *sb) 33038c8a9a5SSteve French { 33138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 33238c8a9a5SSteve French 333*a18280e7SPaulo Alcantara cifs_dbg(FYI, "%s: creating fake fattr\n", __func__); 33438c8a9a5SSteve French 33538c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 33638c8a9a5SSteve French fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; 33738c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 33838c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 33938c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_mtime); 34038c8a9a5SSteve French fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; 34138c8a9a5SSteve French fattr->cf_nlink = 2; 342*a18280e7SPaulo Alcantara fattr->cf_flags = CIFS_FATTR_JUNCTION; 343*a18280e7SPaulo Alcantara } 344*a18280e7SPaulo Alcantara 345*a18280e7SPaulo Alcantara /* Update inode with final fattr data */ 346*a18280e7SPaulo Alcantara static int update_inode_info(struct super_block *sb, 347*a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 348*a18280e7SPaulo Alcantara struct inode **inode) 349*a18280e7SPaulo Alcantara { 350*a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 351*a18280e7SPaulo Alcantara int rc = 0; 352*a18280e7SPaulo Alcantara 353*a18280e7SPaulo Alcantara if (!*inode) { 354*a18280e7SPaulo Alcantara *inode = cifs_iget(sb, fattr); 355*a18280e7SPaulo Alcantara if (!*inode) 356*a18280e7SPaulo Alcantara rc = -ENOMEM; 357*a18280e7SPaulo Alcantara return rc; 358*a18280e7SPaulo Alcantara } 359*a18280e7SPaulo Alcantara /* We already have inode, update it. 360*a18280e7SPaulo Alcantara * 361*a18280e7SPaulo Alcantara * If file type or uniqueid is different, return error. 362*a18280e7SPaulo Alcantara */ 363*a18280e7SPaulo Alcantara if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 364*a18280e7SPaulo Alcantara CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) { 365*a18280e7SPaulo Alcantara CIFS_I(*inode)->time = 0; /* force reval */ 366*a18280e7SPaulo Alcantara return -ESTALE; 367*a18280e7SPaulo Alcantara } 368*a18280e7SPaulo Alcantara return cifs_fattr_to_inode(*inode, fattr); 36938c8a9a5SSteve French } 37038c8a9a5SSteve French 37138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 37238c8a9a5SSteve French static int 37338c8a9a5SSteve French cifs_get_file_info_unix(struct file *filp) 37438c8a9a5SSteve French { 37538c8a9a5SSteve French int rc; 37638c8a9a5SSteve French unsigned int xid; 37738c8a9a5SSteve French FILE_UNIX_BASIC_INFO find_data; 37838c8a9a5SSteve French struct cifs_fattr fattr = {}; 37938c8a9a5SSteve French struct inode *inode = file_inode(filp); 38038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 38138c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 38238c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 38338c8a9a5SSteve French 38438c8a9a5SSteve French xid = get_xid(); 38538c8a9a5SSteve French 38638c8a9a5SSteve French if (cfile->symlink_target) { 38738c8a9a5SSteve French fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); 38838c8a9a5SSteve French if (!fattr.cf_symlink_target) { 38938c8a9a5SSteve French rc = -ENOMEM; 39038c8a9a5SSteve French goto cifs_gfiunix_out; 39138c8a9a5SSteve French } 39238c8a9a5SSteve French } 39338c8a9a5SSteve French 39438c8a9a5SSteve French rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data); 39538c8a9a5SSteve French if (!rc) { 39638c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); 39738c8a9a5SSteve French } else if (rc == -EREMOTE) { 398*a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 39938c8a9a5SSteve French rc = 0; 40038c8a9a5SSteve French } else 40138c8a9a5SSteve French goto cifs_gfiunix_out; 40238c8a9a5SSteve French 40338c8a9a5SSteve French rc = cifs_fattr_to_inode(inode, &fattr); 40438c8a9a5SSteve French 40538c8a9a5SSteve French cifs_gfiunix_out: 40638c8a9a5SSteve French free_xid(xid); 40738c8a9a5SSteve French return rc; 40838c8a9a5SSteve French } 40938c8a9a5SSteve French 410*a18280e7SPaulo Alcantara static int cifs_get_unix_fattr(const unsigned char *full_path, 411*a18280e7SPaulo Alcantara struct super_block *sb, 412*a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 413*a18280e7SPaulo Alcantara struct inode **pinode, 414*a18280e7SPaulo Alcantara const unsigned int xid) 41538c8a9a5SSteve French { 41638c8a9a5SSteve French struct TCP_Server_Info *server; 41738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 418*a18280e7SPaulo Alcantara FILE_UNIX_BASIC_INFO find_data; 419*a18280e7SPaulo Alcantara struct cifs_tcon *tcon; 420*a18280e7SPaulo Alcantara struct tcon_link *tlink; 421*a18280e7SPaulo Alcantara int rc, tmprc; 42238c8a9a5SSteve French 42338c8a9a5SSteve French cifs_dbg(FYI, "Getting info on %s\n", full_path); 42438c8a9a5SSteve French 42538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 42638c8a9a5SSteve French if (IS_ERR(tlink)) 42738c8a9a5SSteve French return PTR_ERR(tlink); 42838c8a9a5SSteve French tcon = tlink_tcon(tlink); 42938c8a9a5SSteve French server = tcon->ses->server; 43038c8a9a5SSteve French 43138c8a9a5SSteve French /* could have done a find first instead but this returns more info */ 43238c8a9a5SSteve French rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, 43338c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 43438c8a9a5SSteve French cifs_dbg(FYI, "%s: query path info: rc = %d\n", __func__, rc); 43538c8a9a5SSteve French cifs_put_tlink(tlink); 43638c8a9a5SSteve French 43738c8a9a5SSteve French if (!rc) { 438*a18280e7SPaulo Alcantara cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb); 43938c8a9a5SSteve French } else if (rc == -EREMOTE) { 440*a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 44138c8a9a5SSteve French rc = 0; 44238c8a9a5SSteve French } else { 44338c8a9a5SSteve French return rc; 44438c8a9a5SSteve French } 44538c8a9a5SSteve French 446*a18280e7SPaulo Alcantara if (!*pinode) 447*a18280e7SPaulo Alcantara cifs_fill_uniqueid(sb, fattr); 448*a18280e7SPaulo Alcantara 44938c8a9a5SSteve French /* check for Minshall+French symlinks */ 45038c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 451*a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 45238c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 45338c8a9a5SSteve French } 45438c8a9a5SSteve French 455*a18280e7SPaulo Alcantara if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) { 45638c8a9a5SSteve French if (!server->ops->query_symlink) 45738c8a9a5SSteve French return -EOPNOTSUPP; 458*a18280e7SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 459*a18280e7SPaulo Alcantara cifs_sb, full_path, 460*a18280e7SPaulo Alcantara &fattr->cf_symlink_target, 461*a18280e7SPaulo Alcantara NULL); 46238c8a9a5SSteve French cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 46338c8a9a5SSteve French } 464*a18280e7SPaulo Alcantara return rc; 46538c8a9a5SSteve French } 46638c8a9a5SSteve French 467*a18280e7SPaulo Alcantara int cifs_get_inode_info_unix(struct inode **pinode, 468*a18280e7SPaulo Alcantara const unsigned char *full_path, 469*a18280e7SPaulo Alcantara struct super_block *sb, unsigned int xid) 470*a18280e7SPaulo Alcantara { 471*a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 472*a18280e7SPaulo Alcantara int rc; 47338c8a9a5SSteve French 474*a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid); 475*a18280e7SPaulo Alcantara if (rc) 476*a18280e7SPaulo Alcantara goto out; 47738c8a9a5SSteve French 478*a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, pinode); 479*a18280e7SPaulo Alcantara out: 48038c8a9a5SSteve French kfree(fattr.cf_symlink_target); 48138c8a9a5SSteve French return rc; 48238c8a9a5SSteve French } 48338c8a9a5SSteve French #else 484*a18280e7SPaulo Alcantara static inline int cifs_get_unix_fattr(const unsigned char *full_path, 485*a18280e7SPaulo Alcantara struct super_block *sb, 486*a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 487*a18280e7SPaulo Alcantara struct inode **pinode, 488*a18280e7SPaulo Alcantara const unsigned int xid) 489*a18280e7SPaulo Alcantara { 490*a18280e7SPaulo Alcantara return -EOPNOTSUPP; 491*a18280e7SPaulo Alcantara } 492*a18280e7SPaulo Alcantara 49338c8a9a5SSteve French int cifs_get_inode_info_unix(struct inode **pinode, 49438c8a9a5SSteve French const unsigned char *full_path, 49538c8a9a5SSteve French struct super_block *sb, unsigned int xid) 49638c8a9a5SSteve French { 49738c8a9a5SSteve French return -EOPNOTSUPP; 49838c8a9a5SSteve French } 49938c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 50038c8a9a5SSteve French 50138c8a9a5SSteve French static int 50238c8a9a5SSteve French cifs_sfu_type(struct cifs_fattr *fattr, const char *path, 50338c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 50438c8a9a5SSteve French { 50538c8a9a5SSteve French int rc; 50638c8a9a5SSteve French __u32 oplock; 50738c8a9a5SSteve French struct tcon_link *tlink; 50838c8a9a5SSteve French struct cifs_tcon *tcon; 50938c8a9a5SSteve French struct cifs_fid fid; 51038c8a9a5SSteve French struct cifs_open_parms oparms; 51138c8a9a5SSteve French struct cifs_io_parms io_parms = {0}; 51238c8a9a5SSteve French char buf[24]; 51338c8a9a5SSteve French unsigned int bytes_read; 51438c8a9a5SSteve French char *pbuf; 51538c8a9a5SSteve French int buf_type = CIFS_NO_BUFFER; 51638c8a9a5SSteve French 51738c8a9a5SSteve French pbuf = buf; 51838c8a9a5SSteve French 51938c8a9a5SSteve French fattr->cf_mode &= ~S_IFMT; 52038c8a9a5SSteve French 52138c8a9a5SSteve French if (fattr->cf_eof == 0) { 52238c8a9a5SSteve French fattr->cf_mode |= S_IFIFO; 52338c8a9a5SSteve French fattr->cf_dtype = DT_FIFO; 52438c8a9a5SSteve French return 0; 52538c8a9a5SSteve French } else if (fattr->cf_eof < 8) { 52638c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 52738c8a9a5SSteve French fattr->cf_dtype = DT_REG; 52838c8a9a5SSteve French return -EINVAL; /* EOPNOTSUPP? */ 52938c8a9a5SSteve French } 53038c8a9a5SSteve French 53138c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 53238c8a9a5SSteve French if (IS_ERR(tlink)) 53338c8a9a5SSteve French return PTR_ERR(tlink); 53438c8a9a5SSteve French tcon = tlink_tcon(tlink); 53538c8a9a5SSteve French 53638c8a9a5SSteve French oparms = (struct cifs_open_parms) { 53738c8a9a5SSteve French .tcon = tcon, 53838c8a9a5SSteve French .cifs_sb = cifs_sb, 53938c8a9a5SSteve French .desired_access = GENERIC_READ, 54038c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 54138c8a9a5SSteve French .disposition = FILE_OPEN, 54238c8a9a5SSteve French .path = path, 54338c8a9a5SSteve French .fid = &fid, 54438c8a9a5SSteve French }; 54538c8a9a5SSteve French 54638c8a9a5SSteve French if (tcon->ses->server->oplocks) 54738c8a9a5SSteve French oplock = REQ_OPLOCK; 54838c8a9a5SSteve French else 54938c8a9a5SSteve French oplock = 0; 55038c8a9a5SSteve French rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); 55138c8a9a5SSteve French if (rc) { 55238c8a9a5SSteve French cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc); 55338c8a9a5SSteve French cifs_put_tlink(tlink); 55438c8a9a5SSteve French return rc; 55538c8a9a5SSteve French } 55638c8a9a5SSteve French 55738c8a9a5SSteve French /* Read header */ 55838c8a9a5SSteve French io_parms.netfid = fid.netfid; 55938c8a9a5SSteve French io_parms.pid = current->tgid; 56038c8a9a5SSteve French io_parms.tcon = tcon; 56138c8a9a5SSteve French io_parms.offset = 0; 56238c8a9a5SSteve French io_parms.length = 24; 56338c8a9a5SSteve French 56438c8a9a5SSteve French rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms, 56538c8a9a5SSteve French &bytes_read, &pbuf, &buf_type); 56638c8a9a5SSteve French if ((rc == 0) && (bytes_read >= 8)) { 56738c8a9a5SSteve French if (memcmp("IntxBLK", pbuf, 8) == 0) { 56838c8a9a5SSteve French cifs_dbg(FYI, "Block device\n"); 56938c8a9a5SSteve French fattr->cf_mode |= S_IFBLK; 57038c8a9a5SSteve French fattr->cf_dtype = DT_BLK; 57138c8a9a5SSteve French if (bytes_read == 24) { 57238c8a9a5SSteve French /* we have enough to decode dev num */ 57338c8a9a5SSteve French __u64 mjr; /* major */ 57438c8a9a5SSteve French __u64 mnr; /* minor */ 57538c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 57638c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 57738c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 57838c8a9a5SSteve French } 57938c8a9a5SSteve French } else if (memcmp("IntxCHR", pbuf, 8) == 0) { 58038c8a9a5SSteve French cifs_dbg(FYI, "Char device\n"); 58138c8a9a5SSteve French fattr->cf_mode |= S_IFCHR; 58238c8a9a5SSteve French fattr->cf_dtype = DT_CHR; 58338c8a9a5SSteve French if (bytes_read == 24) { 58438c8a9a5SSteve French /* we have enough to decode dev num */ 58538c8a9a5SSteve French __u64 mjr; /* major */ 58638c8a9a5SSteve French __u64 mnr; /* minor */ 58738c8a9a5SSteve French mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 58838c8a9a5SSteve French mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 58938c8a9a5SSteve French fattr->cf_rdev = MKDEV(mjr, mnr); 59038c8a9a5SSteve French } 59138c8a9a5SSteve French } else if (memcmp("IntxLNK", pbuf, 7) == 0) { 59238c8a9a5SSteve French cifs_dbg(FYI, "Symlink\n"); 59338c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 59438c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 59538c8a9a5SSteve French } else { 59638c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* file? */ 59738c8a9a5SSteve French fattr->cf_dtype = DT_REG; 59838c8a9a5SSteve French rc = -EOPNOTSUPP; 59938c8a9a5SSteve French } 60038c8a9a5SSteve French } else { 60138c8a9a5SSteve French fattr->cf_mode |= S_IFREG; /* then it is a file */ 60238c8a9a5SSteve French fattr->cf_dtype = DT_REG; 60338c8a9a5SSteve French rc = -EOPNOTSUPP; /* or some unknown SFU type */ 60438c8a9a5SSteve French } 60538c8a9a5SSteve French 60638c8a9a5SSteve French tcon->ses->server->ops->close(xid, tcon, &fid); 60738c8a9a5SSteve French cifs_put_tlink(tlink); 60838c8a9a5SSteve French return rc; 60938c8a9a5SSteve French } 61038c8a9a5SSteve French 61138c8a9a5SSteve French #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ 61238c8a9a5SSteve French 61338c8a9a5SSteve French /* 61438c8a9a5SSteve French * Fetch mode bits as provided by SFU. 61538c8a9a5SSteve French * 61638c8a9a5SSteve French * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? 61738c8a9a5SSteve French */ 61838c8a9a5SSteve French static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, 61938c8a9a5SSteve French struct cifs_sb_info *cifs_sb, unsigned int xid) 62038c8a9a5SSteve French { 62138c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR 62238c8a9a5SSteve French ssize_t rc; 62338c8a9a5SSteve French char ea_value[4]; 62438c8a9a5SSteve French __u32 mode; 62538c8a9a5SSteve French struct tcon_link *tlink; 62638c8a9a5SSteve French struct cifs_tcon *tcon; 62738c8a9a5SSteve French 62838c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 62938c8a9a5SSteve French if (IS_ERR(tlink)) 63038c8a9a5SSteve French return PTR_ERR(tlink); 63138c8a9a5SSteve French tcon = tlink_tcon(tlink); 63238c8a9a5SSteve French 63338c8a9a5SSteve French if (tcon->ses->server->ops->query_all_EAs == NULL) { 63438c8a9a5SSteve French cifs_put_tlink(tlink); 63538c8a9a5SSteve French return -EOPNOTSUPP; 63638c8a9a5SSteve French } 63738c8a9a5SSteve French 63838c8a9a5SSteve French rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, 63938c8a9a5SSteve French "SETFILEBITS", ea_value, 4 /* size of buf */, 64038c8a9a5SSteve French cifs_sb); 64138c8a9a5SSteve French cifs_put_tlink(tlink); 64238c8a9a5SSteve French if (rc < 0) 64338c8a9a5SSteve French return (int)rc; 64438c8a9a5SSteve French else if (rc > 3) { 64538c8a9a5SSteve French mode = le32_to_cpu(*((__le32 *)ea_value)); 64638c8a9a5SSteve French fattr->cf_mode &= ~SFBITS_MASK; 64738c8a9a5SSteve French cifs_dbg(FYI, "special bits 0%o org mode 0%o\n", 64838c8a9a5SSteve French mode, fattr->cf_mode); 64938c8a9a5SSteve French fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; 65038c8a9a5SSteve French cifs_dbg(FYI, "special mode bits 0%o\n", mode); 65138c8a9a5SSteve French } 65238c8a9a5SSteve French 65338c8a9a5SSteve French return 0; 65438c8a9a5SSteve French #else 65538c8a9a5SSteve French return -EOPNOTSUPP; 65638c8a9a5SSteve French #endif 65738c8a9a5SSteve French } 65838c8a9a5SSteve French 65938c8a9a5SSteve French /* Fill a cifs_fattr struct with info from POSIX info struct */ 6608b4e285dSPaulo Alcantara static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 6618b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 66238c8a9a5SSteve French struct cifs_sid *owner, 66338c8a9a5SSteve French struct cifs_sid *group, 6648b4e285dSPaulo Alcantara struct super_block *sb) 66538c8a9a5SSteve French { 66638c8a9a5SSteve French struct smb311_posix_qinfo *info = &data->posix_fi; 66738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 66838c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 66938c8a9a5SSteve French 67038c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 67138c8a9a5SSteve French 67238c8a9a5SSteve French /* no fattr->flags to set */ 67338c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); 67438c8a9a5SSteve French fattr->cf_uniqueid = le64_to_cpu(info->Inode); 67538c8a9a5SSteve French 67638c8a9a5SSteve French if (info->LastAccessTime) 67738c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 67838c8a9a5SSteve French else 67938c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 68038c8a9a5SSteve French 68138c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 68238c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 68338c8a9a5SSteve French 6848b4e285dSPaulo Alcantara if (data->adjust_tz) { 68538c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 68638c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 68738c8a9a5SSteve French } 68838c8a9a5SSteve French 68938c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 69038c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 69138c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 69238c8a9a5SSteve French 69338c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->HardLinks); 69438c8a9a5SSteve French fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); 69538c8a9a5SSteve French /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ 69638c8a9a5SSteve French /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ 69738c8a9a5SSteve French 6988b4e285dSPaulo Alcantara if (data->symlink) { 69938c8a9a5SSteve French fattr->cf_mode |= S_IFLNK; 70038c8a9a5SSteve French fattr->cf_dtype = DT_LNK; 70138c8a9a5SSteve French fattr->cf_symlink_target = data->symlink_target; 70238c8a9a5SSteve French data->symlink_target = NULL; 70338c8a9a5SSteve French } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 70438c8a9a5SSteve French fattr->cf_mode |= S_IFDIR; 70538c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 70638c8a9a5SSteve French } else { /* file */ 70738c8a9a5SSteve French fattr->cf_mode |= S_IFREG; 70838c8a9a5SSteve French fattr->cf_dtype = DT_REG; 70938c8a9a5SSteve French } 71038c8a9a5SSteve French /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ 71138c8a9a5SSteve French 71238c8a9a5SSteve French sid_to_id(cifs_sb, owner, fattr, SIDOWNER); 71338c8a9a5SSteve French sid_to_id(cifs_sb, group, fattr, SIDGROUP); 71438c8a9a5SSteve French 71538c8a9a5SSteve French cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", 71638c8a9a5SSteve French fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 71738c8a9a5SSteve French } 71838c8a9a5SSteve French 7195f71ebc4SPaulo Alcantara bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 7205f71ebc4SPaulo Alcantara struct cifs_fattr *fattr, 7215f71ebc4SPaulo Alcantara u32 tag) 7225f71ebc4SPaulo Alcantara { 7235f71ebc4SPaulo Alcantara switch (tag) { 7245f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_SYMLINK: 7255f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; 7265f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_LNK; 7275f71ebc4SPaulo Alcantara break; 7285f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_FIFO: 7295f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 7305f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_FIFO; 7315f71ebc4SPaulo Alcantara break; 7325f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_AF_UNIX: 7335f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 7345f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_SOCK; 7355f71ebc4SPaulo Alcantara break; 7365f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_CHR: 7375f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 7385f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_CHR; 7395f71ebc4SPaulo Alcantara break; 7405f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_LX_BLK: 7415f71ebc4SPaulo Alcantara fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 7425f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_BLK; 7435f71ebc4SPaulo Alcantara break; 7445f71ebc4SPaulo Alcantara case 0: /* SMB1 symlink */ 7455f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_SYMLINK: 7465f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_NFS: 7475f71ebc4SPaulo Alcantara fattr->cf_mode = S_IFLNK; 7485f71ebc4SPaulo Alcantara fattr->cf_dtype = DT_LNK; 7495f71ebc4SPaulo Alcantara break; 7505f71ebc4SPaulo Alcantara default: 7515f71ebc4SPaulo Alcantara return false; 7525f71ebc4SPaulo Alcantara } 7535f71ebc4SPaulo Alcantara return true; 7545f71ebc4SPaulo Alcantara } 7555f71ebc4SPaulo Alcantara 7568b4e285dSPaulo Alcantara static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, 7578b4e285dSPaulo Alcantara struct cifs_open_info_data *data, 7588b4e285dSPaulo Alcantara struct super_block *sb) 75938c8a9a5SSteve French { 76038c8a9a5SSteve French struct smb2_file_all_info *info = &data->fi; 76138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 76238c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 76338c8a9a5SSteve French 76438c8a9a5SSteve French memset(fattr, 0, sizeof(*fattr)); 76538c8a9a5SSteve French fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); 76638c8a9a5SSteve French if (info->DeletePending) 76738c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; 76838c8a9a5SSteve French 76938c8a9a5SSteve French if (info->LastAccessTime) 77038c8a9a5SSteve French fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); 77138c8a9a5SSteve French else 77238c8a9a5SSteve French ktime_get_coarse_real_ts64(&fattr->cf_atime); 77338c8a9a5SSteve French 77438c8a9a5SSteve French fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); 77538c8a9a5SSteve French fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); 77638c8a9a5SSteve French 7778b4e285dSPaulo Alcantara if (data->adjust_tz) { 77838c8a9a5SSteve French fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; 77938c8a9a5SSteve French fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; 78038c8a9a5SSteve French } 78138c8a9a5SSteve French 78238c8a9a5SSteve French fattr->cf_eof = le64_to_cpu(info->EndOfFile); 78338c8a9a5SSteve French fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 78438c8a9a5SSteve French fattr->cf_createtime = le64_to_cpu(info->CreationTime); 78538c8a9a5SSteve French fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 7865f71ebc4SPaulo Alcantara 7875f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data) && 7885f71ebc4SPaulo Alcantara cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag)) 7895f71ebc4SPaulo Alcantara goto out_reparse; 7905f71ebc4SPaulo Alcantara 7915f71ebc4SPaulo Alcantara if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 79238c8a9a5SSteve French fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; 79338c8a9a5SSteve French fattr->cf_dtype = DT_DIR; 79438c8a9a5SSteve French /* 79538c8a9a5SSteve French * Server can return wrong NumberOfLinks value for directories 79638c8a9a5SSteve French * when Unix extensions are disabled - fake it. 79738c8a9a5SSteve French */ 79838c8a9a5SSteve French if (!tcon->unix_ext) 79938c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 80038c8a9a5SSteve French } else { 80138c8a9a5SSteve French fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; 80238c8a9a5SSteve French fattr->cf_dtype = DT_REG; 80338c8a9a5SSteve French 80438c8a9a5SSteve French /* clear write bits if ATTR_READONLY is set */ 80538c8a9a5SSteve French if (fattr->cf_cifsattrs & ATTR_READONLY) 80638c8a9a5SSteve French fattr->cf_mode &= ~(S_IWUGO); 80738c8a9a5SSteve French 80838c8a9a5SSteve French /* 80938c8a9a5SSteve French * Don't accept zero nlink from non-unix servers unless 81038c8a9a5SSteve French * delete is pending. Instead mark it as unknown. 81138c8a9a5SSteve French */ 81238c8a9a5SSteve French if ((fattr->cf_nlink < 1) && !tcon->unix_ext && 81338c8a9a5SSteve French !info->DeletePending) { 81438c8a9a5SSteve French cifs_dbg(VFS, "bogus file nlink value %u\n", 81538c8a9a5SSteve French fattr->cf_nlink); 81638c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 81738c8a9a5SSteve French } 81838c8a9a5SSteve French } 81938c8a9a5SSteve French 8205f71ebc4SPaulo Alcantara out_reparse: 82138c8a9a5SSteve French if (S_ISLNK(fattr->cf_mode)) { 82238c8a9a5SSteve French fattr->cf_symlink_target = data->symlink_target; 82338c8a9a5SSteve French data->symlink_target = NULL; 82438c8a9a5SSteve French } 82538c8a9a5SSteve French 82638c8a9a5SSteve French fattr->cf_uid = cifs_sb->ctx->linux_uid; 82738c8a9a5SSteve French fattr->cf_gid = cifs_sb->ctx->linux_gid; 82838c8a9a5SSteve French } 82938c8a9a5SSteve French 83038c8a9a5SSteve French static int 83138c8a9a5SSteve French cifs_get_file_info(struct file *filp) 83238c8a9a5SSteve French { 83338c8a9a5SSteve French int rc; 83438c8a9a5SSteve French unsigned int xid; 83538c8a9a5SSteve French struct cifs_open_info_data data = {}; 83638c8a9a5SSteve French struct cifs_fattr fattr; 83738c8a9a5SSteve French struct inode *inode = file_inode(filp); 83838c8a9a5SSteve French struct cifsFileInfo *cfile = filp->private_data; 83938c8a9a5SSteve French struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 84038c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 84138c8a9a5SSteve French 84238c8a9a5SSteve French if (!server->ops->query_file_info) 84338c8a9a5SSteve French return -ENOSYS; 84438c8a9a5SSteve French 84538c8a9a5SSteve French xid = get_xid(); 84638c8a9a5SSteve French rc = server->ops->query_file_info(xid, tcon, cfile, &data); 84738c8a9a5SSteve French switch (rc) { 84838c8a9a5SSteve French case 0: 84938c8a9a5SSteve French /* TODO: add support to query reparse tag */ 8508b4e285dSPaulo Alcantara data.adjust_tz = false; 85138c8a9a5SSteve French if (data.symlink_target) { 8528b4e285dSPaulo Alcantara data.symlink = true; 8538b4e285dSPaulo Alcantara data.reparse_tag = IO_REPARSE_TAG_SYMLINK; 85438c8a9a5SSteve French } 8558b4e285dSPaulo Alcantara cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); 85638c8a9a5SSteve French break; 85738c8a9a5SSteve French case -EREMOTE: 858*a18280e7SPaulo Alcantara cifs_create_junction_fattr(&fattr, inode->i_sb); 85938c8a9a5SSteve French rc = 0; 86038c8a9a5SSteve French break; 86138c8a9a5SSteve French case -EOPNOTSUPP: 86238c8a9a5SSteve French case -EINVAL: 86338c8a9a5SSteve French /* 86438c8a9a5SSteve French * FIXME: legacy server -- fall back to path-based call? 86538c8a9a5SSteve French * for now, just skip revalidating and mark inode for 86638c8a9a5SSteve French * immediate reval. 86738c8a9a5SSteve French */ 86838c8a9a5SSteve French rc = 0; 86938c8a9a5SSteve French CIFS_I(inode)->time = 0; 87038c8a9a5SSteve French goto cgfi_exit; 87138c8a9a5SSteve French default: 87238c8a9a5SSteve French goto cgfi_exit; 87338c8a9a5SSteve French } 87438c8a9a5SSteve French 87538c8a9a5SSteve French /* 87638c8a9a5SSteve French * don't bother with SFU junk here -- just mark inode as needing 87738c8a9a5SSteve French * revalidation. 87838c8a9a5SSteve French */ 87938c8a9a5SSteve French fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; 88038c8a9a5SSteve French fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; 88138c8a9a5SSteve French /* if filetype is different, return error */ 88238c8a9a5SSteve French rc = cifs_fattr_to_inode(inode, &fattr); 88338c8a9a5SSteve French cgfi_exit: 88438c8a9a5SSteve French cifs_free_open_info(&data); 88538c8a9a5SSteve French free_xid(xid); 88638c8a9a5SSteve French return rc; 88738c8a9a5SSteve French } 88838c8a9a5SSteve French 88938c8a9a5SSteve French /* Simple function to return a 64 bit hash of string. Rarely called */ 89038c8a9a5SSteve French static __u64 simple_hashstr(const char *str) 89138c8a9a5SSteve French { 89238c8a9a5SSteve French const __u64 hash_mult = 1125899906842597ULL; /* a big enough prime */ 89338c8a9a5SSteve French __u64 hash = 0; 89438c8a9a5SSteve French 89538c8a9a5SSteve French while (*str) 89638c8a9a5SSteve French hash = (hash + (__u64) *str++) * hash_mult; 89738c8a9a5SSteve French 89838c8a9a5SSteve French return hash; 89938c8a9a5SSteve French } 90038c8a9a5SSteve French 90138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 90238c8a9a5SSteve French /** 90338c8a9a5SSteve French * cifs_backup_query_path_info - SMB1 fallback code to get ino 90438c8a9a5SSteve French * 90538c8a9a5SSteve French * Fallback code to get file metadata when we don't have access to 90638c8a9a5SSteve French * full_path (EACCES) and have backup creds. 90738c8a9a5SSteve French * 90838c8a9a5SSteve French * @xid: transaction id used to identify original request in logs 90938c8a9a5SSteve French * @tcon: information about the server share we have mounted 91038c8a9a5SSteve French * @sb: the superblock stores info such as disk space available 91138c8a9a5SSteve French * @full_path: name of the file we are getting the metadata for 91238c8a9a5SSteve French * @resp_buf: will be set to cifs resp buf and needs to be freed with 91338c8a9a5SSteve French * cifs_buf_release() when done with @data 91438c8a9a5SSteve French * @data: will be set to search info result buffer 91538c8a9a5SSteve French */ 91638c8a9a5SSteve French static int 91738c8a9a5SSteve French cifs_backup_query_path_info(int xid, 91838c8a9a5SSteve French struct cifs_tcon *tcon, 91938c8a9a5SSteve French struct super_block *sb, 92038c8a9a5SSteve French const char *full_path, 92138c8a9a5SSteve French void **resp_buf, 92238c8a9a5SSteve French FILE_ALL_INFO **data) 92338c8a9a5SSteve French { 92438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 92538c8a9a5SSteve French struct cifs_search_info info = {0}; 92638c8a9a5SSteve French u16 flags; 92738c8a9a5SSteve French int rc; 92838c8a9a5SSteve French 92938c8a9a5SSteve French *resp_buf = NULL; 93038c8a9a5SSteve French info.endOfSearch = false; 93138c8a9a5SSteve French if (tcon->unix_ext) 93238c8a9a5SSteve French info.info_level = SMB_FIND_FILE_UNIX; 93338c8a9a5SSteve French else if ((tcon->ses->capabilities & 93438c8a9a5SSteve French tcon->ses->server->vals->cap_nt_find) == 0) 93538c8a9a5SSteve French info.info_level = SMB_FIND_FILE_INFO_STANDARD; 93638c8a9a5SSteve French else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) 93738c8a9a5SSteve French info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; 93838c8a9a5SSteve French else /* no srvino useful for fallback to some netapp */ 93938c8a9a5SSteve French info.info_level = SMB_FIND_FILE_DIRECTORY_INFO; 94038c8a9a5SSteve French 94138c8a9a5SSteve French flags = CIFS_SEARCH_CLOSE_ALWAYS | 94238c8a9a5SSteve French CIFS_SEARCH_CLOSE_AT_END | 94338c8a9a5SSteve French CIFS_SEARCH_BACKUP_SEARCH; 94438c8a9a5SSteve French 94538c8a9a5SSteve French rc = CIFSFindFirst(xid, tcon, full_path, 94638c8a9a5SSteve French cifs_sb, NULL, flags, &info, false); 94738c8a9a5SSteve French if (rc) 94838c8a9a5SSteve French return rc; 94938c8a9a5SSteve French 95038c8a9a5SSteve French *resp_buf = (void *)info.ntwrk_buf_start; 95138c8a9a5SSteve French *data = (FILE_ALL_INFO *)info.srch_entries_start; 95238c8a9a5SSteve French return 0; 95338c8a9a5SSteve French } 95438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 95538c8a9a5SSteve French 95638c8a9a5SSteve French static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_block *sb, 95738c8a9a5SSteve French struct inode **inode, const char *full_path, 95838c8a9a5SSteve French struct cifs_open_info_data *data, struct cifs_fattr *fattr) 95938c8a9a5SSteve French { 96038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 96138c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 96238c8a9a5SSteve French int rc; 96338c8a9a5SSteve French 96438c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { 96538c8a9a5SSteve French if (*inode) 96638c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 96738c8a9a5SSteve French else 96838c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 96938c8a9a5SSteve French return; 97038c8a9a5SSteve French } 97138c8a9a5SSteve French 97238c8a9a5SSteve French /* 97338c8a9a5SSteve French * If we have an inode pass a NULL tcon to ensure we don't 97438c8a9a5SSteve French * make a round trip to the server. This only works for SMB2+. 97538c8a9a5SSteve French */ 97638c8a9a5SSteve French rc = server->ops->get_srv_inum(xid, *inode ? NULL : tcon, cifs_sb, full_path, 97738c8a9a5SSteve French &fattr->cf_uniqueid, data); 97838c8a9a5SSteve French if (rc) { 97938c8a9a5SSteve French /* 98038c8a9a5SSteve French * If that fails reuse existing ino or generate one 98138c8a9a5SSteve French * and disable server ones 98238c8a9a5SSteve French */ 98338c8a9a5SSteve French if (*inode) 98438c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 98538c8a9a5SSteve French else { 98638c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 98738c8a9a5SSteve French cifs_autodisable_serverino(cifs_sb); 98838c8a9a5SSteve French } 98938c8a9a5SSteve French return; 99038c8a9a5SSteve French } 99138c8a9a5SSteve French 99238c8a9a5SSteve French /* If no errors, check for zero root inode (invalid) */ 99338c8a9a5SSteve French if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) { 99438c8a9a5SSteve French cifs_dbg(FYI, "Invalid (0) inodenum\n"); 99538c8a9a5SSteve French if (*inode) { 99638c8a9a5SSteve French /* reuse */ 99738c8a9a5SSteve French fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid; 99838c8a9a5SSteve French } else { 99938c8a9a5SSteve French /* make an ino by hashing the UNC */ 100038c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO; 100138c8a9a5SSteve French fattr->cf_uniqueid = simple_hashstr(tcon->tree_name); 100238c8a9a5SSteve French } 100338c8a9a5SSteve French } 100438c8a9a5SSteve French } 100538c8a9a5SSteve French 100638c8a9a5SSteve French static inline bool is_inode_cache_good(struct inode *ino) 100738c8a9a5SSteve French { 100838c8a9a5SSteve French return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0; 100938c8a9a5SSteve French } 101038c8a9a5SSteve French 1011*a18280e7SPaulo Alcantara static int reparse_info_to_fattr(struct cifs_open_info_data *data, 10125f71ebc4SPaulo Alcantara struct super_block *sb, 10135f71ebc4SPaulo Alcantara const unsigned int xid, 10145f71ebc4SPaulo Alcantara struct cifs_tcon *tcon, 10155f71ebc4SPaulo Alcantara const char *full_path, 10165f71ebc4SPaulo Alcantara struct cifs_fattr *fattr) 10175f71ebc4SPaulo Alcantara { 10185f71ebc4SPaulo Alcantara struct TCP_Server_Info *server = tcon->ses->server; 10195f71ebc4SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 10209a49e221SPaulo Alcantara struct kvec rsp_iov, *iov = NULL; 10219a49e221SPaulo Alcantara int rsp_buftype = CIFS_NO_BUFFER; 10225f71ebc4SPaulo Alcantara u32 tag = data->reparse_tag; 10235f71ebc4SPaulo Alcantara int rc = 0; 10245f71ebc4SPaulo Alcantara 10259a49e221SPaulo Alcantara if (!tag && server->ops->query_reparse_point) { 10269a49e221SPaulo Alcantara rc = server->ops->query_reparse_point(xid, tcon, cifs_sb, 10279a49e221SPaulo Alcantara full_path, &tag, 10289a49e221SPaulo Alcantara &rsp_iov, &rsp_buftype); 10299a49e221SPaulo Alcantara if (!rc) 10309a49e221SPaulo Alcantara iov = &rsp_iov; 10315f71ebc4SPaulo Alcantara } 10325f71ebc4SPaulo Alcantara switch ((data->reparse_tag = tag)) { 10335f71ebc4SPaulo Alcantara case 0: /* SMB1 symlink */ 10349a49e221SPaulo Alcantara iov = NULL; 10355f71ebc4SPaulo Alcantara fallthrough; 10365f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_NFS: 10375f71ebc4SPaulo Alcantara case IO_REPARSE_TAG_SYMLINK: 10385f71ebc4SPaulo Alcantara if (!data->symlink_target && server->ops->query_symlink) { 10395f71ebc4SPaulo Alcantara rc = server->ops->query_symlink(xid, tcon, 10405f71ebc4SPaulo Alcantara cifs_sb, full_path, 10415f71ebc4SPaulo Alcantara &data->symlink_target, 10429a49e221SPaulo Alcantara iov); 10435f71ebc4SPaulo Alcantara } 10445f71ebc4SPaulo Alcantara break; 1045*a18280e7SPaulo Alcantara case IO_REPARSE_TAG_MOUNT_POINT: 1046*a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 1047*a18280e7SPaulo Alcantara goto out; 10485f71ebc4SPaulo Alcantara } 1049*a18280e7SPaulo Alcantara 1050*a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 1051*a18280e7SPaulo Alcantara out: 10529a49e221SPaulo Alcantara free_rsp_buf(rsp_buftype, rsp_iov.iov_base); 10535f71ebc4SPaulo Alcantara return rc; 10545f71ebc4SPaulo Alcantara } 10555f71ebc4SPaulo Alcantara 1056*a18280e7SPaulo Alcantara static int cifs_get_fattr(struct cifs_open_info_data *data, 1057*a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1058*a18280e7SPaulo Alcantara const struct cifs_fid *fid, 1059*a18280e7SPaulo Alcantara struct cifs_fattr *fattr, 1060*a18280e7SPaulo Alcantara struct inode **inode, 1061*a18280e7SPaulo Alcantara const char *full_path) 106238c8a9a5SSteve French { 1063*a18280e7SPaulo Alcantara struct cifs_open_info_data tmp_data = {}; 106438c8a9a5SSteve French struct cifs_tcon *tcon; 106538c8a9a5SSteve French struct TCP_Server_Info *server; 106638c8a9a5SSteve French struct tcon_link *tlink; 106738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 106838c8a9a5SSteve French void *smb1_backup_rsp_buf = NULL; 106938c8a9a5SSteve French int rc = 0; 107038c8a9a5SSteve French int tmprc = 0; 107138c8a9a5SSteve French 107238c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 107338c8a9a5SSteve French if (IS_ERR(tlink)) 107438c8a9a5SSteve French return PTR_ERR(tlink); 107538c8a9a5SSteve French tcon = tlink_tcon(tlink); 107638c8a9a5SSteve French server = tcon->ses->server; 107738c8a9a5SSteve French 107838c8a9a5SSteve French /* 107938c8a9a5SSteve French * 1. Fetch file metadata if not provided (data) 108038c8a9a5SSteve French */ 108138c8a9a5SSteve French 108238c8a9a5SSteve French if (!data) { 10838b4e285dSPaulo Alcantara rc = server->ops->query_path_info(xid, tcon, cifs_sb, 10848b4e285dSPaulo Alcantara full_path, &tmp_data); 108538c8a9a5SSteve French data = &tmp_data; 108638c8a9a5SSteve French } 108738c8a9a5SSteve French 108838c8a9a5SSteve French /* 108938c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 109038c8a9a5SSteve French */ 109138c8a9a5SSteve French 109238c8a9a5SSteve French switch (rc) { 109338c8a9a5SSteve French case 0: 109438c8a9a5SSteve French /* 109538c8a9a5SSteve French * If the file is a reparse point, it is more complicated 109638c8a9a5SSteve French * since we have to check if its reparse tag matches a known 109738c8a9a5SSteve French * special file type e.g. symlink or fifo or char etc. 109838c8a9a5SSteve French */ 10995f71ebc4SPaulo Alcantara if (cifs_open_data_reparse(data)) { 1100*a18280e7SPaulo Alcantara rc = reparse_info_to_fattr(data, sb, xid, tcon, 1101*a18280e7SPaulo Alcantara full_path, fattr); 1102*a18280e7SPaulo Alcantara } else { 1103*a18280e7SPaulo Alcantara cifs_open_info_to_fattr(fattr, data, sb); 110438c8a9a5SSteve French } 110538c8a9a5SSteve French break; 110638c8a9a5SSteve French case -EREMOTE: 110738c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1108*a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 110938c8a9a5SSteve French rc = 0; 111038c8a9a5SSteve French break; 111138c8a9a5SSteve French case -EACCES: 111238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 111338c8a9a5SSteve French /* 111438c8a9a5SSteve French * perm errors, try again with backup flags if possible 111538c8a9a5SSteve French * 111638c8a9a5SSteve French * For SMB2 and later the backup intent flag 111738c8a9a5SSteve French * is already sent if needed on open and there 111838c8a9a5SSteve French * is no path based FindFirst operation to use 111938c8a9a5SSteve French * to retry with 112038c8a9a5SSteve French */ 112138c8a9a5SSteve French if (backup_cred(cifs_sb) && is_smb1_server(server)) { 112238c8a9a5SSteve French /* for easier reading */ 112338c8a9a5SSteve French FILE_ALL_INFO *fi; 112438c8a9a5SSteve French FILE_DIRECTORY_INFO *fdi; 112538c8a9a5SSteve French SEARCH_ID_FULL_DIR_INFO *si; 112638c8a9a5SSteve French 112738c8a9a5SSteve French rc = cifs_backup_query_path_info(xid, tcon, sb, 112838c8a9a5SSteve French full_path, 112938c8a9a5SSteve French &smb1_backup_rsp_buf, 113038c8a9a5SSteve French &fi); 113138c8a9a5SSteve French if (rc) 113238c8a9a5SSteve French goto out; 113338c8a9a5SSteve French 113438c8a9a5SSteve French move_cifs_info_to_smb2(&data->fi, fi); 113538c8a9a5SSteve French fdi = (FILE_DIRECTORY_INFO *)fi; 113638c8a9a5SSteve French si = (SEARCH_ID_FULL_DIR_INFO *)fi; 113738c8a9a5SSteve French 1138*a18280e7SPaulo Alcantara cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); 1139*a18280e7SPaulo Alcantara fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); 114038c8a9a5SSteve French /* uniqueid set, skip get inum step */ 114138c8a9a5SSteve French goto handle_mnt_opt; 114238c8a9a5SSteve French } else { 114338c8a9a5SSteve French /* nothing we can do, bail out */ 114438c8a9a5SSteve French goto out; 114538c8a9a5SSteve French } 114638c8a9a5SSteve French #else 114738c8a9a5SSteve French goto out; 114838c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 114938c8a9a5SSteve French break; 115038c8a9a5SSteve French default: 115138c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 115238c8a9a5SSteve French goto out; 115338c8a9a5SSteve French } 115438c8a9a5SSteve French 115538c8a9a5SSteve French /* 1156*a18280e7SPaulo Alcantara * 3. Get or update inode number (fattr->cf_uniqueid) 115738c8a9a5SSteve French */ 115838c8a9a5SSteve French 1159*a18280e7SPaulo Alcantara cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr); 116038c8a9a5SSteve French 116138c8a9a5SSteve French /* 116238c8a9a5SSteve French * 4. Tweak fattr based on mount options 116338c8a9a5SSteve French */ 116438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 116538c8a9a5SSteve French handle_mnt_opt: 116638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 116738c8a9a5SSteve French /* query for SFU type info if supported and needed */ 1168*a18280e7SPaulo Alcantara if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && 1169*a18280e7SPaulo Alcantara (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { 1170*a18280e7SPaulo Alcantara tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid); 117138c8a9a5SSteve French if (tmprc) 117238c8a9a5SSteve French cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc); 117338c8a9a5SSteve French } 117438c8a9a5SSteve French 117538c8a9a5SSteve French /* fill in 0777 bits from ACL */ 117638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) { 1177*a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1178*a18280e7SPaulo Alcantara true, full_path, fid); 117938c8a9a5SSteve French if (rc == -EREMOTE) 118038c8a9a5SSteve French rc = 0; 118138c8a9a5SSteve French if (rc) { 118238c8a9a5SSteve French cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n", 118338c8a9a5SSteve French __func__, rc); 118438c8a9a5SSteve French goto out; 118538c8a9a5SSteve French } 118638c8a9a5SSteve French } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 1187*a18280e7SPaulo Alcantara rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode, 1188*a18280e7SPaulo Alcantara false, full_path, fid); 118938c8a9a5SSteve French if (rc == -EREMOTE) 119038c8a9a5SSteve French rc = 0; 119138c8a9a5SSteve French if (rc) { 119238c8a9a5SSteve French cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n", 119338c8a9a5SSteve French __func__, rc); 119438c8a9a5SSteve French goto out; 119538c8a9a5SSteve French } 119638c8a9a5SSteve French } 119738c8a9a5SSteve French 119838c8a9a5SSteve French /* fill in remaining high mode bits e.g. SUID, VTX */ 119938c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) 1200*a18280e7SPaulo Alcantara cifs_sfu_mode(fattr, full_path, cifs_sb, xid); 120138c8a9a5SSteve French 120238c8a9a5SSteve French /* check for Minshall+French symlinks */ 120338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1204*a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 120538c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 120638c8a9a5SSteve French } 120738c8a9a5SSteve French 120838c8a9a5SSteve French out: 120938c8a9a5SSteve French cifs_buf_release(smb1_backup_rsp_buf); 121038c8a9a5SSteve French cifs_put_tlink(tlink); 121138c8a9a5SSteve French cifs_free_open_info(&tmp_data); 1212*a18280e7SPaulo Alcantara return rc; 1213*a18280e7SPaulo Alcantara } 1214*a18280e7SPaulo Alcantara 1215*a18280e7SPaulo Alcantara int cifs_get_inode_info(struct inode **inode, 1216*a18280e7SPaulo Alcantara const char *full_path, 1217*a18280e7SPaulo Alcantara struct cifs_open_info_data *data, 1218*a18280e7SPaulo Alcantara struct super_block *sb, int xid, 1219*a18280e7SPaulo Alcantara const struct cifs_fid *fid) 1220*a18280e7SPaulo Alcantara { 1221*a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1222*a18280e7SPaulo Alcantara int rc; 1223*a18280e7SPaulo Alcantara 1224*a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1225*a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1226*a18280e7SPaulo Alcantara return 0; 1227*a18280e7SPaulo Alcantara } 1228*a18280e7SPaulo Alcantara 1229*a18280e7SPaulo Alcantara rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path); 1230*a18280e7SPaulo Alcantara if (rc) 1231*a18280e7SPaulo Alcantara goto out; 1232*a18280e7SPaulo Alcantara 1233*a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 1234*a18280e7SPaulo Alcantara out: 123538c8a9a5SSteve French kfree(fattr.cf_symlink_target); 123638c8a9a5SSteve French return rc; 123738c8a9a5SSteve French } 123838c8a9a5SSteve French 1239*a18280e7SPaulo Alcantara static int smb311_posix_get_fattr(struct cifs_fattr *fattr, 124038c8a9a5SSteve French const char *full_path, 1241*a18280e7SPaulo Alcantara struct super_block *sb, 1242*a18280e7SPaulo Alcantara const unsigned int xid) 124338c8a9a5SSteve French { 1244*a18280e7SPaulo Alcantara struct cifs_open_info_data data = {}; 1245*a18280e7SPaulo Alcantara struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 124638c8a9a5SSteve French struct cifs_tcon *tcon; 124738c8a9a5SSteve French struct tcon_link *tlink; 124838c8a9a5SSteve French struct cifs_sid owner, group; 1249*a18280e7SPaulo Alcantara int tmprc; 1250*a18280e7SPaulo Alcantara int rc; 125138c8a9a5SSteve French 125238c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 125338c8a9a5SSteve French if (IS_ERR(tlink)) 125438c8a9a5SSteve French return PTR_ERR(tlink); 125538c8a9a5SSteve French tcon = tlink_tcon(tlink); 125638c8a9a5SSteve French 125738c8a9a5SSteve French /* 125838c8a9a5SSteve French * 1. Fetch file metadata 125938c8a9a5SSteve French */ 126038c8a9a5SSteve French 12618b4e285dSPaulo Alcantara rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, 12628b4e285dSPaulo Alcantara full_path, &data, 12638b4e285dSPaulo Alcantara &owner, &group); 126438c8a9a5SSteve French 126538c8a9a5SSteve French /* 126638c8a9a5SSteve French * 2. Convert it to internal cifs metadata (fattr) 126738c8a9a5SSteve French */ 126838c8a9a5SSteve French 126938c8a9a5SSteve French switch (rc) { 127038c8a9a5SSteve French case 0: 1271*a18280e7SPaulo Alcantara smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb); 127238c8a9a5SSteve French break; 127338c8a9a5SSteve French case -EREMOTE: 127438c8a9a5SSteve French /* DFS link, no metadata available on this server */ 1275*a18280e7SPaulo Alcantara cifs_create_junction_fattr(fattr, sb); 127638c8a9a5SSteve French rc = 0; 127738c8a9a5SSteve French break; 127838c8a9a5SSteve French case -EACCES: 127938c8a9a5SSteve French /* 128038c8a9a5SSteve French * For SMB2 and later the backup intent flag 128138c8a9a5SSteve French * is already sent if needed on open and there 128238c8a9a5SSteve French * is no path based FindFirst operation to use 128338c8a9a5SSteve French * to retry with so nothing we can do, bail out 128438c8a9a5SSteve French */ 128538c8a9a5SSteve French goto out; 128638c8a9a5SSteve French default: 128738c8a9a5SSteve French cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); 128838c8a9a5SSteve French goto out; 128938c8a9a5SSteve French } 129038c8a9a5SSteve French 129138c8a9a5SSteve French /* 129238c8a9a5SSteve French * 3. Tweak fattr based on mount options 129338c8a9a5SSteve French */ 129438c8a9a5SSteve French /* check for Minshall+French symlinks */ 129538c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 1296*a18280e7SPaulo Alcantara tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path); 129738c8a9a5SSteve French cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); 129838c8a9a5SSteve French } 129938c8a9a5SSteve French 130038c8a9a5SSteve French out: 130138c8a9a5SSteve French cifs_put_tlink(tlink); 130238c8a9a5SSteve French cifs_free_open_info(&data); 130338c8a9a5SSteve French return rc; 130438c8a9a5SSteve French } 130538c8a9a5SSteve French 1306*a18280e7SPaulo Alcantara int smb311_posix_get_inode_info(struct inode **inode, const char *full_path, 1307*a18280e7SPaulo Alcantara struct super_block *sb, const unsigned int xid) 1308*a18280e7SPaulo Alcantara { 1309*a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 1310*a18280e7SPaulo Alcantara int rc; 1311*a18280e7SPaulo Alcantara 1312*a18280e7SPaulo Alcantara if (is_inode_cache_good(*inode)) { 1313*a18280e7SPaulo Alcantara cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); 1314*a18280e7SPaulo Alcantara return 0; 1315*a18280e7SPaulo Alcantara } 1316*a18280e7SPaulo Alcantara 1317*a18280e7SPaulo Alcantara rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid); 1318*a18280e7SPaulo Alcantara if (rc) 1319*a18280e7SPaulo Alcantara goto out; 1320*a18280e7SPaulo Alcantara 1321*a18280e7SPaulo Alcantara rc = update_inode_info(sb, &fattr, inode); 1322*a18280e7SPaulo Alcantara out: 1323*a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 1324*a18280e7SPaulo Alcantara return rc; 1325*a18280e7SPaulo Alcantara } 132638c8a9a5SSteve French 132738c8a9a5SSteve French static const struct inode_operations cifs_ipc_inode_ops = { 132838c8a9a5SSteve French .lookup = cifs_lookup, 132938c8a9a5SSteve French }; 133038c8a9a5SSteve French 133138c8a9a5SSteve French static int 133238c8a9a5SSteve French cifs_find_inode(struct inode *inode, void *opaque) 133338c8a9a5SSteve French { 133438c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 133538c8a9a5SSteve French 133638c8a9a5SSteve French /* don't match inode with different uniqueid */ 133738c8a9a5SSteve French if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) 133838c8a9a5SSteve French return 0; 133938c8a9a5SSteve French 134038c8a9a5SSteve French /* use createtime like an i_generation field */ 134138c8a9a5SSteve French if (CIFS_I(inode)->createtime != fattr->cf_createtime) 134238c8a9a5SSteve French return 0; 134338c8a9a5SSteve French 134438c8a9a5SSteve French /* don't match inode of different type */ 134538c8a9a5SSteve French if (inode_wrong_type(inode, fattr->cf_mode)) 134638c8a9a5SSteve French return 0; 134738c8a9a5SSteve French 134838c8a9a5SSteve French /* if it's not a directory or has no dentries, then flag it */ 134938c8a9a5SSteve French if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) 135038c8a9a5SSteve French fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; 135138c8a9a5SSteve French 135238c8a9a5SSteve French return 1; 135338c8a9a5SSteve French } 135438c8a9a5SSteve French 135538c8a9a5SSteve French static int 135638c8a9a5SSteve French cifs_init_inode(struct inode *inode, void *opaque) 135738c8a9a5SSteve French { 135838c8a9a5SSteve French struct cifs_fattr *fattr = opaque; 135938c8a9a5SSteve French 136038c8a9a5SSteve French CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; 136138c8a9a5SSteve French CIFS_I(inode)->createtime = fattr->cf_createtime; 136238c8a9a5SSteve French return 0; 136338c8a9a5SSteve French } 136438c8a9a5SSteve French 136538c8a9a5SSteve French /* 136638c8a9a5SSteve French * walk dentry list for an inode and report whether it has aliases that 136738c8a9a5SSteve French * are hashed. We use this to determine if a directory inode can actually 136838c8a9a5SSteve French * be used. 136938c8a9a5SSteve French */ 137038c8a9a5SSteve French static bool 137138c8a9a5SSteve French inode_has_hashed_dentries(struct inode *inode) 137238c8a9a5SSteve French { 137338c8a9a5SSteve French struct dentry *dentry; 137438c8a9a5SSteve French 137538c8a9a5SSteve French spin_lock(&inode->i_lock); 137638c8a9a5SSteve French hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { 137738c8a9a5SSteve French if (!d_unhashed(dentry) || IS_ROOT(dentry)) { 137838c8a9a5SSteve French spin_unlock(&inode->i_lock); 137938c8a9a5SSteve French return true; 138038c8a9a5SSteve French } 138138c8a9a5SSteve French } 138238c8a9a5SSteve French spin_unlock(&inode->i_lock); 138338c8a9a5SSteve French return false; 138438c8a9a5SSteve French } 138538c8a9a5SSteve French 138638c8a9a5SSteve French /* Given fattrs, get a corresponding inode */ 138738c8a9a5SSteve French struct inode * 138838c8a9a5SSteve French cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) 138938c8a9a5SSteve French { 139038c8a9a5SSteve French unsigned long hash; 139138c8a9a5SSteve French struct inode *inode; 139238c8a9a5SSteve French 139338c8a9a5SSteve French retry_iget5_locked: 139438c8a9a5SSteve French cifs_dbg(FYI, "looking for uniqueid=%llu\n", fattr->cf_uniqueid); 139538c8a9a5SSteve French 139638c8a9a5SSteve French /* hash down to 32-bits on 32-bit arch */ 139738c8a9a5SSteve French hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); 139838c8a9a5SSteve French 139938c8a9a5SSteve French inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); 140038c8a9a5SSteve French if (inode) { 140138c8a9a5SSteve French /* was there a potentially problematic inode collision? */ 140238c8a9a5SSteve French if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { 140338c8a9a5SSteve French fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; 140438c8a9a5SSteve French 140538c8a9a5SSteve French if (inode_has_hashed_dentries(inode)) { 140638c8a9a5SSteve French cifs_autodisable_serverino(CIFS_SB(sb)); 140738c8a9a5SSteve French iput(inode); 140838c8a9a5SSteve French fattr->cf_uniqueid = iunique(sb, ROOT_I); 140938c8a9a5SSteve French goto retry_iget5_locked; 141038c8a9a5SSteve French } 141138c8a9a5SSteve French } 141238c8a9a5SSteve French 141338c8a9a5SSteve French /* can't fail - see cifs_find_inode() */ 141438c8a9a5SSteve French cifs_fattr_to_inode(inode, fattr); 141538c8a9a5SSteve French if (sb->s_flags & SB_NOATIME) 141638c8a9a5SSteve French inode->i_flags |= S_NOATIME | S_NOCMTIME; 141738c8a9a5SSteve French if (inode->i_state & I_NEW) { 141838c8a9a5SSteve French inode->i_ino = hash; 141938c8a9a5SSteve French cifs_fscache_get_inode_cookie(inode); 142038c8a9a5SSteve French unlock_new_inode(inode); 142138c8a9a5SSteve French } 142238c8a9a5SSteve French } 142338c8a9a5SSteve French 142438c8a9a5SSteve French return inode; 142538c8a9a5SSteve French } 142638c8a9a5SSteve French 142738c8a9a5SSteve French /* gets root inode */ 142838c8a9a5SSteve French struct inode *cifs_root_iget(struct super_block *sb) 142938c8a9a5SSteve French { 143038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1431*a18280e7SPaulo Alcantara struct cifs_fattr fattr = {}; 143238c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1433*a18280e7SPaulo Alcantara struct inode *inode = NULL; 1434*a18280e7SPaulo Alcantara unsigned int xid; 143538c8a9a5SSteve French char *path = NULL; 143638c8a9a5SSteve French int len; 1437*a18280e7SPaulo Alcantara int rc; 143838c8a9a5SSteve French 143938c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) 144038c8a9a5SSteve French && cifs_sb->prepath) { 144138c8a9a5SSteve French len = strlen(cifs_sb->prepath); 144238c8a9a5SSteve French path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL); 144338c8a9a5SSteve French if (path == NULL) 144438c8a9a5SSteve French return ERR_PTR(-ENOMEM); 144538c8a9a5SSteve French path[0] = '/'; 144638c8a9a5SSteve French memcpy(path+1, cifs_sb->prepath, len); 144738c8a9a5SSteve French } else { 144838c8a9a5SSteve French path = kstrdup("", GFP_KERNEL); 144938c8a9a5SSteve French if (path == NULL) 145038c8a9a5SSteve French return ERR_PTR(-ENOMEM); 145138c8a9a5SSteve French } 145238c8a9a5SSteve French 145338c8a9a5SSteve French xid = get_xid(); 145438c8a9a5SSteve French if (tcon->unix_ext) { 1455*a18280e7SPaulo Alcantara rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid); 145638c8a9a5SSteve French /* some servers mistakenly claim POSIX support */ 145738c8a9a5SSteve French if (rc != -EOPNOTSUPP) 1458*a18280e7SPaulo Alcantara goto iget_root; 145938c8a9a5SSteve French cifs_dbg(VFS, "server does not support POSIX extensions\n"); 146038c8a9a5SSteve French tcon->unix_ext = false; 146138c8a9a5SSteve French } 146238c8a9a5SSteve French 146338c8a9a5SSteve French convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); 146438c8a9a5SSteve French if (tcon->posix_extensions) 1465*a18280e7SPaulo Alcantara rc = smb311_posix_get_fattr(&fattr, path, sb, xid); 146638c8a9a5SSteve French else 1467*a18280e7SPaulo Alcantara rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); 146838c8a9a5SSteve French 1469*a18280e7SPaulo Alcantara iget_root: 1470*a18280e7SPaulo Alcantara if (!rc) { 1471*a18280e7SPaulo Alcantara if (fattr.cf_flags & CIFS_FATTR_JUNCTION) { 1472*a18280e7SPaulo Alcantara fattr.cf_flags &= ~CIFS_FATTR_JUNCTION; 1473*a18280e7SPaulo Alcantara cifs_autodisable_serverino(cifs_sb); 1474*a18280e7SPaulo Alcantara } 1475*a18280e7SPaulo Alcantara inode = cifs_iget(sb, &fattr); 1476*a18280e7SPaulo Alcantara } 1477*a18280e7SPaulo Alcantara 147838c8a9a5SSteve French if (!inode) { 147938c8a9a5SSteve French inode = ERR_PTR(rc); 148038c8a9a5SSteve French goto out; 148138c8a9a5SSteve French } 148238c8a9a5SSteve French 148338c8a9a5SSteve French if (rc && tcon->pipe) { 148438c8a9a5SSteve French cifs_dbg(FYI, "ipc connection - fake read inode\n"); 148538c8a9a5SSteve French spin_lock(&inode->i_lock); 148638c8a9a5SSteve French inode->i_mode |= S_IFDIR; 148738c8a9a5SSteve French set_nlink(inode, 2); 148838c8a9a5SSteve French inode->i_op = &cifs_ipc_inode_ops; 148938c8a9a5SSteve French inode->i_fop = &simple_dir_operations; 149038c8a9a5SSteve French inode->i_uid = cifs_sb->ctx->linux_uid; 149138c8a9a5SSteve French inode->i_gid = cifs_sb->ctx->linux_gid; 149238c8a9a5SSteve French spin_unlock(&inode->i_lock); 149338c8a9a5SSteve French } else if (rc) { 149438c8a9a5SSteve French iget_failed(inode); 149538c8a9a5SSteve French inode = ERR_PTR(rc); 149638c8a9a5SSteve French } 149738c8a9a5SSteve French 149838c8a9a5SSteve French out: 149938c8a9a5SSteve French kfree(path); 150038c8a9a5SSteve French free_xid(xid); 1501*a18280e7SPaulo Alcantara kfree(fattr.cf_symlink_target); 150238c8a9a5SSteve French return inode; 150338c8a9a5SSteve French } 150438c8a9a5SSteve French 150538c8a9a5SSteve French int 150638c8a9a5SSteve French cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, 150738c8a9a5SSteve French const char *full_path, __u32 dosattr) 150838c8a9a5SSteve French { 150938c8a9a5SSteve French bool set_time = false; 151038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 151138c8a9a5SSteve French struct TCP_Server_Info *server; 151238c8a9a5SSteve French FILE_BASIC_INFO info_buf; 151338c8a9a5SSteve French 151438c8a9a5SSteve French if (attrs == NULL) 151538c8a9a5SSteve French return -EINVAL; 151638c8a9a5SSteve French 151738c8a9a5SSteve French server = cifs_sb_master_tcon(cifs_sb)->ses->server; 151838c8a9a5SSteve French if (!server->ops->set_file_info) 151938c8a9a5SSteve French return -ENOSYS; 152038c8a9a5SSteve French 152138c8a9a5SSteve French info_buf.Pad = 0; 152238c8a9a5SSteve French 152338c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) { 152438c8a9a5SSteve French set_time = true; 152538c8a9a5SSteve French info_buf.LastAccessTime = 152638c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); 152738c8a9a5SSteve French } else 152838c8a9a5SSteve French info_buf.LastAccessTime = 0; 152938c8a9a5SSteve French 153038c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) { 153138c8a9a5SSteve French set_time = true; 153238c8a9a5SSteve French info_buf.LastWriteTime = 153338c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); 153438c8a9a5SSteve French } else 153538c8a9a5SSteve French info_buf.LastWriteTime = 0; 153638c8a9a5SSteve French 153738c8a9a5SSteve French /* 153838c8a9a5SSteve French * Samba throws this field away, but windows may actually use it. 153938c8a9a5SSteve French * Do not set ctime unless other time stamps are changed explicitly 154038c8a9a5SSteve French * (i.e. by utimes()) since we would then have a mix of client and 154138c8a9a5SSteve French * server times. 154238c8a9a5SSteve French */ 154338c8a9a5SSteve French if (set_time && (attrs->ia_valid & ATTR_CTIME)) { 154438c8a9a5SSteve French cifs_dbg(FYI, "CIFS - CTIME changed\n"); 154538c8a9a5SSteve French info_buf.ChangeTime = 154638c8a9a5SSteve French cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); 154738c8a9a5SSteve French } else 154838c8a9a5SSteve French info_buf.ChangeTime = 0; 154938c8a9a5SSteve French 155038c8a9a5SSteve French info_buf.CreationTime = 0; /* don't change */ 155138c8a9a5SSteve French info_buf.Attributes = cpu_to_le32(dosattr); 155238c8a9a5SSteve French 155338c8a9a5SSteve French return server->ops->set_file_info(inode, full_path, &info_buf, xid); 155438c8a9a5SSteve French } 155538c8a9a5SSteve French 155638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 155738c8a9a5SSteve French /* 155838c8a9a5SSteve French * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit 155938c8a9a5SSteve French * and rename it to a random name that hopefully won't conflict with 156038c8a9a5SSteve French * anything else. 156138c8a9a5SSteve French */ 156238c8a9a5SSteve French int 156338c8a9a5SSteve French cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, 156438c8a9a5SSteve French const unsigned int xid) 156538c8a9a5SSteve French { 156638c8a9a5SSteve French int oplock = 0; 156738c8a9a5SSteve French int rc; 156838c8a9a5SSteve French struct cifs_fid fid; 156938c8a9a5SSteve French struct cifs_open_parms oparms; 157038c8a9a5SSteve French struct inode *inode = d_inode(dentry); 157138c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 157238c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 157338c8a9a5SSteve French struct tcon_link *tlink; 157438c8a9a5SSteve French struct cifs_tcon *tcon; 157538c8a9a5SSteve French __u32 dosattr, origattr; 157638c8a9a5SSteve French FILE_BASIC_INFO *info_buf = NULL; 157738c8a9a5SSteve French 157838c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 157938c8a9a5SSteve French if (IS_ERR(tlink)) 158038c8a9a5SSteve French return PTR_ERR(tlink); 158138c8a9a5SSteve French tcon = tlink_tcon(tlink); 158238c8a9a5SSteve French 158338c8a9a5SSteve French /* 158438c8a9a5SSteve French * We cannot rename the file if the server doesn't support 158538c8a9a5SSteve French * CAP_INFOLEVEL_PASSTHRU 158638c8a9a5SSteve French */ 158738c8a9a5SSteve French if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) { 158838c8a9a5SSteve French rc = -EBUSY; 158938c8a9a5SSteve French goto out; 159038c8a9a5SSteve French } 159138c8a9a5SSteve French 159238c8a9a5SSteve French oparms = (struct cifs_open_parms) { 159338c8a9a5SSteve French .tcon = tcon, 159438c8a9a5SSteve French .cifs_sb = cifs_sb, 159538c8a9a5SSteve French .desired_access = DELETE | FILE_WRITE_ATTRIBUTES, 159638c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 159738c8a9a5SSteve French .disposition = FILE_OPEN, 159838c8a9a5SSteve French .path = full_path, 159938c8a9a5SSteve French .fid = &fid, 160038c8a9a5SSteve French }; 160138c8a9a5SSteve French 160238c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 160338c8a9a5SSteve French if (rc != 0) 160438c8a9a5SSteve French goto out; 160538c8a9a5SSteve French 160638c8a9a5SSteve French origattr = cifsInode->cifsAttrs; 160738c8a9a5SSteve French if (origattr == 0) 160838c8a9a5SSteve French origattr |= ATTR_NORMAL; 160938c8a9a5SSteve French 161038c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 161138c8a9a5SSteve French if (dosattr == 0) 161238c8a9a5SSteve French dosattr |= ATTR_NORMAL; 161338c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 161438c8a9a5SSteve French 161538c8a9a5SSteve French /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */ 161638c8a9a5SSteve French if (dosattr != origattr) { 161738c8a9a5SSteve French info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); 161838c8a9a5SSteve French if (info_buf == NULL) { 161938c8a9a5SSteve French rc = -ENOMEM; 162038c8a9a5SSteve French goto out_close; 162138c8a9a5SSteve French } 162238c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(dosattr); 162338c8a9a5SSteve French rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 162438c8a9a5SSteve French current->tgid); 162538c8a9a5SSteve French /* although we would like to mark the file hidden 162638c8a9a5SSteve French if that fails we will still try to rename it */ 162738c8a9a5SSteve French if (!rc) 162838c8a9a5SSteve French cifsInode->cifsAttrs = dosattr; 162938c8a9a5SSteve French else 163038c8a9a5SSteve French dosattr = origattr; /* since not able to change them */ 163138c8a9a5SSteve French } 163238c8a9a5SSteve French 163338c8a9a5SSteve French /* rename the file */ 163438c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, 163538c8a9a5SSteve French cifs_sb->local_nls, 163638c8a9a5SSteve French cifs_remap(cifs_sb)); 163738c8a9a5SSteve French if (rc != 0) { 163838c8a9a5SSteve French rc = -EBUSY; 163938c8a9a5SSteve French goto undo_setattr; 164038c8a9a5SSteve French } 164138c8a9a5SSteve French 164238c8a9a5SSteve French /* try to set DELETE_ON_CLOSE */ 164338c8a9a5SSteve French if (!test_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags)) { 164438c8a9a5SSteve French rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid, 164538c8a9a5SSteve French current->tgid); 164638c8a9a5SSteve French /* 164738c8a9a5SSteve French * some samba versions return -ENOENT when we try to set the 164838c8a9a5SSteve French * file disposition here. Likely a samba bug, but work around 164938c8a9a5SSteve French * it for now. This means that some cifsXXX files may hang 165038c8a9a5SSteve French * around after they shouldn't. 165138c8a9a5SSteve French * 165238c8a9a5SSteve French * BB: remove this hack after more servers have the fix 165338c8a9a5SSteve French */ 165438c8a9a5SSteve French if (rc == -ENOENT) 165538c8a9a5SSteve French rc = 0; 165638c8a9a5SSteve French else if (rc != 0) { 165738c8a9a5SSteve French rc = -EBUSY; 165838c8a9a5SSteve French goto undo_rename; 165938c8a9a5SSteve French } 166038c8a9a5SSteve French set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags); 166138c8a9a5SSteve French } 166238c8a9a5SSteve French 166338c8a9a5SSteve French out_close: 166438c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 166538c8a9a5SSteve French out: 166638c8a9a5SSteve French kfree(info_buf); 166738c8a9a5SSteve French cifs_put_tlink(tlink); 166838c8a9a5SSteve French return rc; 166938c8a9a5SSteve French 167038c8a9a5SSteve French /* 167138c8a9a5SSteve French * reset everything back to the original state. Don't bother 167238c8a9a5SSteve French * dealing with errors here since we can't do anything about 167338c8a9a5SSteve French * them anyway. 167438c8a9a5SSteve French */ 167538c8a9a5SSteve French undo_rename: 167638c8a9a5SSteve French CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, 167738c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 167838c8a9a5SSteve French undo_setattr: 167938c8a9a5SSteve French if (dosattr != origattr) { 168038c8a9a5SSteve French info_buf->Attributes = cpu_to_le32(origattr); 168138c8a9a5SSteve French if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, 168238c8a9a5SSteve French current->tgid)) 168338c8a9a5SSteve French cifsInode->cifsAttrs = origattr; 168438c8a9a5SSteve French } 168538c8a9a5SSteve French 168638c8a9a5SSteve French goto out_close; 168738c8a9a5SSteve French } 168838c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 168938c8a9a5SSteve French 169038c8a9a5SSteve French /* copied from fs/nfs/dir.c with small changes */ 169138c8a9a5SSteve French static void 169238c8a9a5SSteve French cifs_drop_nlink(struct inode *inode) 169338c8a9a5SSteve French { 169438c8a9a5SSteve French spin_lock(&inode->i_lock); 169538c8a9a5SSteve French if (inode->i_nlink > 0) 169638c8a9a5SSteve French drop_nlink(inode); 169738c8a9a5SSteve French spin_unlock(&inode->i_lock); 169838c8a9a5SSteve French } 169938c8a9a5SSteve French 170038c8a9a5SSteve French /* 170138c8a9a5SSteve French * If d_inode(dentry) is null (usually meaning the cached dentry 170238c8a9a5SSteve French * is a negative dentry) then we would attempt a standard SMB delete, but 170338c8a9a5SSteve French * if that fails we can not attempt the fall back mechanisms on EACCES 170438c8a9a5SSteve French * but will return the EACCES to the caller. Note that the VFS does not call 170538c8a9a5SSteve French * unlink on negative dentries currently. 170638c8a9a5SSteve French */ 170738c8a9a5SSteve French int cifs_unlink(struct inode *dir, struct dentry *dentry) 170838c8a9a5SSteve French { 170938c8a9a5SSteve French int rc = 0; 171038c8a9a5SSteve French unsigned int xid; 171138c8a9a5SSteve French const char *full_path; 171238c8a9a5SSteve French void *page; 171338c8a9a5SSteve French struct inode *inode = d_inode(dentry); 171438c8a9a5SSteve French struct cifsInodeInfo *cifs_inode; 171538c8a9a5SSteve French struct super_block *sb = dir->i_sb; 171638c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 171738c8a9a5SSteve French struct tcon_link *tlink; 171838c8a9a5SSteve French struct cifs_tcon *tcon; 171938c8a9a5SSteve French struct TCP_Server_Info *server; 172038c8a9a5SSteve French struct iattr *attrs = NULL; 172138c8a9a5SSteve French __u32 dosattr = 0, origattr = 0; 172238c8a9a5SSteve French 172338c8a9a5SSteve French cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); 172438c8a9a5SSteve French 172538c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 172638c8a9a5SSteve French return -EIO; 172738c8a9a5SSteve French 172838c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 172938c8a9a5SSteve French if (IS_ERR(tlink)) 173038c8a9a5SSteve French return PTR_ERR(tlink); 173138c8a9a5SSteve French tcon = tlink_tcon(tlink); 173238c8a9a5SSteve French server = tcon->ses->server; 173338c8a9a5SSteve French 173438c8a9a5SSteve French xid = get_xid(); 173538c8a9a5SSteve French page = alloc_dentry_path(); 173638c8a9a5SSteve French 173738c8a9a5SSteve French if (tcon->nodelete) { 173838c8a9a5SSteve French rc = -EACCES; 173938c8a9a5SSteve French goto unlink_out; 174038c8a9a5SSteve French } 174138c8a9a5SSteve French 174238c8a9a5SSteve French /* Unlink can be called from rename so we can not take the 174338c8a9a5SSteve French * sb->s_vfs_rename_mutex here */ 174438c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 174538c8a9a5SSteve French if (IS_ERR(full_path)) { 174638c8a9a5SSteve French rc = PTR_ERR(full_path); 174738c8a9a5SSteve French goto unlink_out; 174838c8a9a5SSteve French } 174938c8a9a5SSteve French 175038c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, full_path); 175138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 175238c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 175338c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 175438c8a9a5SSteve French rc = CIFSPOSIXDelFile(xid, tcon, full_path, 175538c8a9a5SSteve French SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 175638c8a9a5SSteve French cifs_remap(cifs_sb)); 175738c8a9a5SSteve French cifs_dbg(FYI, "posix del rc %d\n", rc); 175838c8a9a5SSteve French if ((rc == 0) || (rc == -ENOENT)) 175938c8a9a5SSteve French goto psx_del_no_retry; 176038c8a9a5SSteve French } 176138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 176238c8a9a5SSteve French 176338c8a9a5SSteve French retry_std_delete: 176438c8a9a5SSteve French if (!server->ops->unlink) { 176538c8a9a5SSteve French rc = -ENOSYS; 176638c8a9a5SSteve French goto psx_del_no_retry; 176738c8a9a5SSteve French } 176838c8a9a5SSteve French 176938c8a9a5SSteve French rc = server->ops->unlink(xid, tcon, full_path, cifs_sb); 177038c8a9a5SSteve French 177138c8a9a5SSteve French psx_del_no_retry: 177238c8a9a5SSteve French if (!rc) { 177338c8a9a5SSteve French if (inode) 177438c8a9a5SSteve French cifs_drop_nlink(inode); 177538c8a9a5SSteve French } else if (rc == -ENOENT) { 177638c8a9a5SSteve French d_drop(dentry); 177738c8a9a5SSteve French } else if (rc == -EBUSY) { 177838c8a9a5SSteve French if (server->ops->rename_pending_delete) { 177938c8a9a5SSteve French rc = server->ops->rename_pending_delete(full_path, 178038c8a9a5SSteve French dentry, xid); 178138c8a9a5SSteve French if (rc == 0) 178238c8a9a5SSteve French cifs_drop_nlink(inode); 178338c8a9a5SSteve French } 178438c8a9a5SSteve French } else if ((rc == -EACCES) && (dosattr == 0) && inode) { 178538c8a9a5SSteve French attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 178638c8a9a5SSteve French if (attrs == NULL) { 178738c8a9a5SSteve French rc = -ENOMEM; 178838c8a9a5SSteve French goto out_reval; 178938c8a9a5SSteve French } 179038c8a9a5SSteve French 179138c8a9a5SSteve French /* try to reset dos attributes */ 179238c8a9a5SSteve French cifs_inode = CIFS_I(inode); 179338c8a9a5SSteve French origattr = cifs_inode->cifsAttrs; 179438c8a9a5SSteve French if (origattr == 0) 179538c8a9a5SSteve French origattr |= ATTR_NORMAL; 179638c8a9a5SSteve French dosattr = origattr & ~ATTR_READONLY; 179738c8a9a5SSteve French if (dosattr == 0) 179838c8a9a5SSteve French dosattr |= ATTR_NORMAL; 179938c8a9a5SSteve French dosattr |= ATTR_HIDDEN; 180038c8a9a5SSteve French 180138c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 180238c8a9a5SSteve French if (rc != 0) 180338c8a9a5SSteve French goto out_reval; 180438c8a9a5SSteve French 180538c8a9a5SSteve French goto retry_std_delete; 180638c8a9a5SSteve French } 180738c8a9a5SSteve French 180838c8a9a5SSteve French /* undo the setattr if we errored out and it's needed */ 180938c8a9a5SSteve French if (rc != 0 && dosattr != 0) 181038c8a9a5SSteve French cifs_set_file_info(inode, attrs, xid, full_path, origattr); 181138c8a9a5SSteve French 181238c8a9a5SSteve French out_reval: 181338c8a9a5SSteve French if (inode) { 181438c8a9a5SSteve French cifs_inode = CIFS_I(inode); 181538c8a9a5SSteve French cifs_inode->time = 0; /* will force revalidate to get info 181638c8a9a5SSteve French when needed */ 181738c8a9a5SSteve French inode->i_ctime = current_time(inode); 181838c8a9a5SSteve French } 181938c8a9a5SSteve French dir->i_ctime = dir->i_mtime = current_time(dir); 182038c8a9a5SSteve French cifs_inode = CIFS_I(dir); 182138c8a9a5SSteve French CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ 182238c8a9a5SSteve French unlink_out: 182338c8a9a5SSteve French free_dentry_path(page); 182438c8a9a5SSteve French kfree(attrs); 182538c8a9a5SSteve French free_xid(xid); 182638c8a9a5SSteve French cifs_put_tlink(tlink); 182738c8a9a5SSteve French return rc; 182838c8a9a5SSteve French } 182938c8a9a5SSteve French 183038c8a9a5SSteve French static int 183138c8a9a5SSteve French cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, 183238c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 183338c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 183438c8a9a5SSteve French { 183538c8a9a5SSteve French int rc = 0; 183638c8a9a5SSteve French struct inode *inode = NULL; 183738c8a9a5SSteve French 183838c8a9a5SSteve French if (tcon->posix_extensions) 183938c8a9a5SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid); 184038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 184138c8a9a5SSteve French else if (tcon->unix_ext) 184238c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, 184338c8a9a5SSteve French xid); 184438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 184538c8a9a5SSteve French else 184638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb, 184738c8a9a5SSteve French xid, NULL); 184838c8a9a5SSteve French 184938c8a9a5SSteve French if (rc) 185038c8a9a5SSteve French return rc; 185138c8a9a5SSteve French 185238c8a9a5SSteve French if (!S_ISDIR(inode->i_mode)) { 185338c8a9a5SSteve French /* 185438c8a9a5SSteve French * mkdir succeeded, but another client has managed to remove the 185538c8a9a5SSteve French * sucker and replace it with non-directory. Return success, 185638c8a9a5SSteve French * but don't leave the child in dcache. 185738c8a9a5SSteve French */ 185838c8a9a5SSteve French iput(inode); 185938c8a9a5SSteve French d_drop(dentry); 186038c8a9a5SSteve French return 0; 186138c8a9a5SSteve French } 186238c8a9a5SSteve French /* 186338c8a9a5SSteve French * setting nlink not necessary except in cases where we failed to get it 186438c8a9a5SSteve French * from the server or was set bogus. Also, since this is a brand new 186538c8a9a5SSteve French * inode, no need to grab the i_lock before setting the i_nlink. 186638c8a9a5SSteve French */ 186738c8a9a5SSteve French if (inode->i_nlink < 2) 186838c8a9a5SSteve French set_nlink(inode, 2); 186938c8a9a5SSteve French mode &= ~current_umask(); 187038c8a9a5SSteve French /* must turn on setgid bit if parent dir has it */ 187138c8a9a5SSteve French if (parent->i_mode & S_ISGID) 187238c8a9a5SSteve French mode |= S_ISGID; 187338c8a9a5SSteve French 187438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 187538c8a9a5SSteve French if (tcon->unix_ext) { 187638c8a9a5SSteve French struct cifs_unix_set_info_args args = { 187738c8a9a5SSteve French .mode = mode, 187838c8a9a5SSteve French .ctime = NO_CHANGE_64, 187938c8a9a5SSteve French .atime = NO_CHANGE_64, 188038c8a9a5SSteve French .mtime = NO_CHANGE_64, 188138c8a9a5SSteve French .device = 0, 188238c8a9a5SSteve French }; 188338c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 188438c8a9a5SSteve French args.uid = current_fsuid(); 188538c8a9a5SSteve French if (parent->i_mode & S_ISGID) 188638c8a9a5SSteve French args.gid = parent->i_gid; 188738c8a9a5SSteve French else 188838c8a9a5SSteve French args.gid = current_fsgid(); 188938c8a9a5SSteve French } else { 189038c8a9a5SSteve French args.uid = INVALID_UID; /* no change */ 189138c8a9a5SSteve French args.gid = INVALID_GID; /* no change */ 189238c8a9a5SSteve French } 189338c8a9a5SSteve French CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, 189438c8a9a5SSteve French cifs_sb->local_nls, 189538c8a9a5SSteve French cifs_remap(cifs_sb)); 189638c8a9a5SSteve French } else { 189738c8a9a5SSteve French #else 189838c8a9a5SSteve French { 189938c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 190038c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 190138c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 190238c8a9a5SSteve French (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo) 190338c8a9a5SSteve French server->ops->mkdir_setinfo(inode, full_path, cifs_sb, 190438c8a9a5SSteve French tcon, xid); 190538c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) 190638c8a9a5SSteve French inode->i_mode = (mode | S_IFDIR); 190738c8a9a5SSteve French 190838c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 190938c8a9a5SSteve French inode->i_uid = current_fsuid(); 191038c8a9a5SSteve French if (inode->i_mode & S_ISGID) 191138c8a9a5SSteve French inode->i_gid = parent->i_gid; 191238c8a9a5SSteve French else 191338c8a9a5SSteve French inode->i_gid = current_fsgid(); 191438c8a9a5SSteve French } 191538c8a9a5SSteve French } 191638c8a9a5SSteve French d_instantiate(dentry, inode); 191738c8a9a5SSteve French return 0; 191838c8a9a5SSteve French } 191938c8a9a5SSteve French 192038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 192138c8a9a5SSteve French static int 192238c8a9a5SSteve French cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode, 192338c8a9a5SSteve French const char *full_path, struct cifs_sb_info *cifs_sb, 192438c8a9a5SSteve French struct cifs_tcon *tcon, const unsigned int xid) 192538c8a9a5SSteve French { 192638c8a9a5SSteve French int rc = 0; 192738c8a9a5SSteve French u32 oplock = 0; 192838c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info = NULL; 192938c8a9a5SSteve French struct inode *newinode = NULL; 193038c8a9a5SSteve French struct cifs_fattr fattr; 193138c8a9a5SSteve French 193238c8a9a5SSteve French info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 193338c8a9a5SSteve French if (info == NULL) { 193438c8a9a5SSteve French rc = -ENOMEM; 193538c8a9a5SSteve French goto posix_mkdir_out; 193638c8a9a5SSteve French } 193738c8a9a5SSteve French 193838c8a9a5SSteve French mode &= ~current_umask(); 193938c8a9a5SSteve French rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, 194038c8a9a5SSteve French NULL /* netfid */, info, &oplock, full_path, 194138c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 194238c8a9a5SSteve French if (rc == -EOPNOTSUPP) 194338c8a9a5SSteve French goto posix_mkdir_out; 194438c8a9a5SSteve French else if (rc) { 194538c8a9a5SSteve French cifs_dbg(FYI, "posix mkdir returned 0x%x\n", rc); 194638c8a9a5SSteve French d_drop(dentry); 194738c8a9a5SSteve French goto posix_mkdir_out; 194838c8a9a5SSteve French } 194938c8a9a5SSteve French 195038c8a9a5SSteve French if (info->Type == cpu_to_le32(-1)) 195138c8a9a5SSteve French /* no return info, go query for it */ 195238c8a9a5SSteve French goto posix_mkdir_get_info; 195338c8a9a5SSteve French /* 195438c8a9a5SSteve French * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if 195538c8a9a5SSteve French * need to set uid/gid. 195638c8a9a5SSteve French */ 195738c8a9a5SSteve French 195838c8a9a5SSteve French cifs_unix_basic_to_fattr(&fattr, info, cifs_sb); 195938c8a9a5SSteve French cifs_fill_uniqueid(inode->i_sb, &fattr); 196038c8a9a5SSteve French newinode = cifs_iget(inode->i_sb, &fattr); 196138c8a9a5SSteve French if (!newinode) 196238c8a9a5SSteve French goto posix_mkdir_get_info; 196338c8a9a5SSteve French 196438c8a9a5SSteve French d_instantiate(dentry, newinode); 196538c8a9a5SSteve French 196638c8a9a5SSteve French #ifdef CONFIG_CIFS_DEBUG2 196738c8a9a5SSteve French cifs_dbg(FYI, "instantiated dentry %p %pd to inode %p\n", 196838c8a9a5SSteve French dentry, dentry, newinode); 196938c8a9a5SSteve French 197038c8a9a5SSteve French if (newinode->i_nlink != 2) 197138c8a9a5SSteve French cifs_dbg(FYI, "unexpected number of links %d\n", 197238c8a9a5SSteve French newinode->i_nlink); 197338c8a9a5SSteve French #endif 197438c8a9a5SSteve French 197538c8a9a5SSteve French posix_mkdir_out: 197638c8a9a5SSteve French kfree(info); 197738c8a9a5SSteve French return rc; 197838c8a9a5SSteve French posix_mkdir_get_info: 197938c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon, 198038c8a9a5SSteve French xid); 198138c8a9a5SSteve French goto posix_mkdir_out; 198238c8a9a5SSteve French } 198338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 198438c8a9a5SSteve French 198538c8a9a5SSteve French int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode, 198638c8a9a5SSteve French struct dentry *direntry, umode_t mode) 198738c8a9a5SSteve French { 198838c8a9a5SSteve French int rc = 0; 198938c8a9a5SSteve French unsigned int xid; 199038c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 199138c8a9a5SSteve French struct tcon_link *tlink; 199238c8a9a5SSteve French struct cifs_tcon *tcon; 199338c8a9a5SSteve French struct TCP_Server_Info *server; 199438c8a9a5SSteve French const char *full_path; 199538c8a9a5SSteve French void *page; 199638c8a9a5SSteve French 199738c8a9a5SSteve French cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n", 199838c8a9a5SSteve French mode, inode); 199938c8a9a5SSteve French 200038c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 200138c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 200238c8a9a5SSteve French return -EIO; 200338c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 200438c8a9a5SSteve French if (IS_ERR(tlink)) 200538c8a9a5SSteve French return PTR_ERR(tlink); 200638c8a9a5SSteve French tcon = tlink_tcon(tlink); 200738c8a9a5SSteve French 200838c8a9a5SSteve French xid = get_xid(); 200938c8a9a5SSteve French 201038c8a9a5SSteve French page = alloc_dentry_path(); 201138c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 201238c8a9a5SSteve French if (IS_ERR(full_path)) { 201338c8a9a5SSteve French rc = PTR_ERR(full_path); 201438c8a9a5SSteve French goto mkdir_out; 201538c8a9a5SSteve French } 201638c8a9a5SSteve French 201738c8a9a5SSteve French server = tcon->ses->server; 201838c8a9a5SSteve French 201938c8a9a5SSteve French if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { 202038c8a9a5SSteve French rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, 202138c8a9a5SSteve French cifs_sb); 202238c8a9a5SSteve French d_drop(direntry); /* for time being always refresh inode info */ 202338c8a9a5SSteve French goto mkdir_out; 202438c8a9a5SSteve French } 202538c8a9a5SSteve French 202638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 202738c8a9a5SSteve French if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 202838c8a9a5SSteve French le64_to_cpu(tcon->fsUnixInfo.Capability))) { 202938c8a9a5SSteve French rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, 203038c8a9a5SSteve French tcon, xid); 203138c8a9a5SSteve French if (rc != -EOPNOTSUPP) 203238c8a9a5SSteve French goto mkdir_out; 203338c8a9a5SSteve French } 203438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 203538c8a9a5SSteve French 203638c8a9a5SSteve French if (!server->ops->mkdir) { 203738c8a9a5SSteve French rc = -ENOSYS; 203838c8a9a5SSteve French goto mkdir_out; 203938c8a9a5SSteve French } 204038c8a9a5SSteve French 204138c8a9a5SSteve French /* BB add setting the equivalent of mode via CreateX w/ACLs */ 204238c8a9a5SSteve French rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb); 204338c8a9a5SSteve French if (rc) { 204438c8a9a5SSteve French cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc); 204538c8a9a5SSteve French d_drop(direntry); 204638c8a9a5SSteve French goto mkdir_out; 204738c8a9a5SSteve French } 204838c8a9a5SSteve French 204938c8a9a5SSteve French /* TODO: skip this for smb2/smb3 */ 205038c8a9a5SSteve French rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon, 205138c8a9a5SSteve French xid); 205238c8a9a5SSteve French mkdir_out: 205338c8a9a5SSteve French /* 205438c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 205538c8a9a5SSteve French * attributes are invalid now. 205638c8a9a5SSteve French */ 205738c8a9a5SSteve French CIFS_I(inode)->time = 0; 205838c8a9a5SSteve French free_dentry_path(page); 205938c8a9a5SSteve French free_xid(xid); 206038c8a9a5SSteve French cifs_put_tlink(tlink); 206138c8a9a5SSteve French return rc; 206238c8a9a5SSteve French } 206338c8a9a5SSteve French 206438c8a9a5SSteve French int cifs_rmdir(struct inode *inode, struct dentry *direntry) 206538c8a9a5SSteve French { 206638c8a9a5SSteve French int rc = 0; 206738c8a9a5SSteve French unsigned int xid; 206838c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 206938c8a9a5SSteve French struct tcon_link *tlink; 207038c8a9a5SSteve French struct cifs_tcon *tcon; 207138c8a9a5SSteve French struct TCP_Server_Info *server; 207238c8a9a5SSteve French const char *full_path; 207338c8a9a5SSteve French void *page = alloc_dentry_path(); 207438c8a9a5SSteve French struct cifsInodeInfo *cifsInode; 207538c8a9a5SSteve French 207638c8a9a5SSteve French cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode); 207738c8a9a5SSteve French 207838c8a9a5SSteve French xid = get_xid(); 207938c8a9a5SSteve French 208038c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 208138c8a9a5SSteve French if (IS_ERR(full_path)) { 208238c8a9a5SSteve French rc = PTR_ERR(full_path); 208338c8a9a5SSteve French goto rmdir_exit; 208438c8a9a5SSteve French } 208538c8a9a5SSteve French 208638c8a9a5SSteve French cifs_sb = CIFS_SB(inode->i_sb); 208738c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) { 208838c8a9a5SSteve French rc = -EIO; 208938c8a9a5SSteve French goto rmdir_exit; 209038c8a9a5SSteve French } 209138c8a9a5SSteve French 209238c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 209338c8a9a5SSteve French if (IS_ERR(tlink)) { 209438c8a9a5SSteve French rc = PTR_ERR(tlink); 209538c8a9a5SSteve French goto rmdir_exit; 209638c8a9a5SSteve French } 209738c8a9a5SSteve French tcon = tlink_tcon(tlink); 209838c8a9a5SSteve French server = tcon->ses->server; 209938c8a9a5SSteve French 210038c8a9a5SSteve French if (!server->ops->rmdir) { 210138c8a9a5SSteve French rc = -ENOSYS; 210238c8a9a5SSteve French cifs_put_tlink(tlink); 210338c8a9a5SSteve French goto rmdir_exit; 210438c8a9a5SSteve French } 210538c8a9a5SSteve French 210638c8a9a5SSteve French if (tcon->nodelete) { 210738c8a9a5SSteve French rc = -EACCES; 210838c8a9a5SSteve French cifs_put_tlink(tlink); 210938c8a9a5SSteve French goto rmdir_exit; 211038c8a9a5SSteve French } 211138c8a9a5SSteve French 211238c8a9a5SSteve French rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); 211338c8a9a5SSteve French cifs_put_tlink(tlink); 211438c8a9a5SSteve French 211538c8a9a5SSteve French if (!rc) { 211638c8a9a5SSteve French spin_lock(&d_inode(direntry)->i_lock); 211738c8a9a5SSteve French i_size_write(d_inode(direntry), 0); 211838c8a9a5SSteve French clear_nlink(d_inode(direntry)); 211938c8a9a5SSteve French spin_unlock(&d_inode(direntry)->i_lock); 212038c8a9a5SSteve French } 212138c8a9a5SSteve French 212238c8a9a5SSteve French cifsInode = CIFS_I(d_inode(direntry)); 212338c8a9a5SSteve French /* force revalidate to go get info when needed */ 212438c8a9a5SSteve French cifsInode->time = 0; 212538c8a9a5SSteve French 212638c8a9a5SSteve French cifsInode = CIFS_I(inode); 212738c8a9a5SSteve French /* 212838c8a9a5SSteve French * Force revalidate to get parent dir info when needed since cached 212938c8a9a5SSteve French * attributes are invalid now. 213038c8a9a5SSteve French */ 213138c8a9a5SSteve French cifsInode->time = 0; 213238c8a9a5SSteve French 213338c8a9a5SSteve French d_inode(direntry)->i_ctime = inode->i_ctime = inode->i_mtime = 213438c8a9a5SSteve French current_time(inode); 213538c8a9a5SSteve French 213638c8a9a5SSteve French rmdir_exit: 213738c8a9a5SSteve French free_dentry_path(page); 213838c8a9a5SSteve French free_xid(xid); 213938c8a9a5SSteve French return rc; 214038c8a9a5SSteve French } 214138c8a9a5SSteve French 214238c8a9a5SSteve French static int 214338c8a9a5SSteve French cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, 214438c8a9a5SSteve French const char *from_path, struct dentry *to_dentry, 214538c8a9a5SSteve French const char *to_path) 214638c8a9a5SSteve French { 214738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); 214838c8a9a5SSteve French struct tcon_link *tlink; 214938c8a9a5SSteve French struct cifs_tcon *tcon; 215038c8a9a5SSteve French struct TCP_Server_Info *server; 215138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 215238c8a9a5SSteve French struct cifs_fid fid; 215338c8a9a5SSteve French struct cifs_open_parms oparms; 215438c8a9a5SSteve French int oplock; 215538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 215638c8a9a5SSteve French int rc; 215738c8a9a5SSteve French 215838c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 215938c8a9a5SSteve French if (IS_ERR(tlink)) 216038c8a9a5SSteve French return PTR_ERR(tlink); 216138c8a9a5SSteve French tcon = tlink_tcon(tlink); 216238c8a9a5SSteve French server = tcon->ses->server; 216338c8a9a5SSteve French 216438c8a9a5SSteve French if (!server->ops->rename) 216538c8a9a5SSteve French return -ENOSYS; 216638c8a9a5SSteve French 216738c8a9a5SSteve French /* try path-based rename first */ 216838c8a9a5SSteve French rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb); 216938c8a9a5SSteve French 217038c8a9a5SSteve French /* 217138c8a9a5SSteve French * Don't bother with rename by filehandle unless file is busy and 217238c8a9a5SSteve French * source. Note that cross directory moves do not work with 217338c8a9a5SSteve French * rename by filehandle to various Windows servers. 217438c8a9a5SSteve French */ 217538c8a9a5SSteve French if (rc == 0 || rc != -EBUSY) 217638c8a9a5SSteve French goto do_rename_exit; 217738c8a9a5SSteve French 217838c8a9a5SSteve French /* Don't fall back to using SMB on SMB 2+ mount */ 217938c8a9a5SSteve French if (server->vals->protocol_id != 0) 218038c8a9a5SSteve French goto do_rename_exit; 218138c8a9a5SSteve French 218238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 218338c8a9a5SSteve French /* open-file renames don't work across directories */ 218438c8a9a5SSteve French if (to_dentry->d_parent != from_dentry->d_parent) 218538c8a9a5SSteve French goto do_rename_exit; 218638c8a9a5SSteve French 218738c8a9a5SSteve French oparms = (struct cifs_open_parms) { 218838c8a9a5SSteve French .tcon = tcon, 218938c8a9a5SSteve French .cifs_sb = cifs_sb, 219038c8a9a5SSteve French /* open the file to be renamed -- we need DELETE perms */ 219138c8a9a5SSteve French .desired_access = DELETE, 219238c8a9a5SSteve French .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), 219338c8a9a5SSteve French .disposition = FILE_OPEN, 219438c8a9a5SSteve French .path = from_path, 219538c8a9a5SSteve French .fid = &fid, 219638c8a9a5SSteve French }; 219738c8a9a5SSteve French 219838c8a9a5SSteve French rc = CIFS_open(xid, &oparms, &oplock, NULL); 219938c8a9a5SSteve French if (rc == 0) { 220038c8a9a5SSteve French rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, 220138c8a9a5SSteve French (const char *) to_dentry->d_name.name, 220238c8a9a5SSteve French cifs_sb->local_nls, cifs_remap(cifs_sb)); 220338c8a9a5SSteve French CIFSSMBClose(xid, tcon, fid.netfid); 220438c8a9a5SSteve French } 220538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 220638c8a9a5SSteve French do_rename_exit: 220738c8a9a5SSteve French if (rc == 0) 220838c8a9a5SSteve French d_move(from_dentry, to_dentry); 220938c8a9a5SSteve French cifs_put_tlink(tlink); 221038c8a9a5SSteve French return rc; 221138c8a9a5SSteve French } 221238c8a9a5SSteve French 221338c8a9a5SSteve French int 221438c8a9a5SSteve French cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, 221538c8a9a5SSteve French struct dentry *source_dentry, struct inode *target_dir, 221638c8a9a5SSteve French struct dentry *target_dentry, unsigned int flags) 221738c8a9a5SSteve French { 221838c8a9a5SSteve French const char *from_name, *to_name; 221938c8a9a5SSteve French void *page1, *page2; 222038c8a9a5SSteve French struct cifs_sb_info *cifs_sb; 222138c8a9a5SSteve French struct tcon_link *tlink; 222238c8a9a5SSteve French struct cifs_tcon *tcon; 222338c8a9a5SSteve French unsigned int xid; 222438c8a9a5SSteve French int rc, tmprc; 222538c8a9a5SSteve French int retry_count = 0; 222638c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_source = NULL; 222738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 222838c8a9a5SSteve French FILE_UNIX_BASIC_INFO *info_buf_target; 222938c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 223038c8a9a5SSteve French 223138c8a9a5SSteve French if (flags & ~RENAME_NOREPLACE) 223238c8a9a5SSteve French return -EINVAL; 223338c8a9a5SSteve French 223438c8a9a5SSteve French cifs_sb = CIFS_SB(source_dir->i_sb); 223538c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 223638c8a9a5SSteve French return -EIO; 223738c8a9a5SSteve French 223838c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 223938c8a9a5SSteve French if (IS_ERR(tlink)) 224038c8a9a5SSteve French return PTR_ERR(tlink); 224138c8a9a5SSteve French tcon = tlink_tcon(tlink); 224238c8a9a5SSteve French 224338c8a9a5SSteve French page1 = alloc_dentry_path(); 224438c8a9a5SSteve French page2 = alloc_dentry_path(); 224538c8a9a5SSteve French xid = get_xid(); 224638c8a9a5SSteve French 224738c8a9a5SSteve French from_name = build_path_from_dentry(source_dentry, page1); 224838c8a9a5SSteve French if (IS_ERR(from_name)) { 224938c8a9a5SSteve French rc = PTR_ERR(from_name); 225038c8a9a5SSteve French goto cifs_rename_exit; 225138c8a9a5SSteve French } 225238c8a9a5SSteve French 225338c8a9a5SSteve French to_name = build_path_from_dentry(target_dentry, page2); 225438c8a9a5SSteve French if (IS_ERR(to_name)) { 225538c8a9a5SSteve French rc = PTR_ERR(to_name); 225638c8a9a5SSteve French goto cifs_rename_exit; 225738c8a9a5SSteve French } 225838c8a9a5SSteve French 225938c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, from_name); 226038c8a9a5SSteve French if (d_inode(target_dentry) != NULL) 226138c8a9a5SSteve French cifs_close_deferred_file_under_dentry(tcon, to_name); 226238c8a9a5SSteve French 226338c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 226438c8a9a5SSteve French to_name); 226538c8a9a5SSteve French 226638c8a9a5SSteve French if (rc == -EACCES) { 226738c8a9a5SSteve French while (retry_count < 3) { 226838c8a9a5SSteve French cifs_close_all_deferred_files(tcon); 226938c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, 227038c8a9a5SSteve French to_name); 227138c8a9a5SSteve French if (rc != -EACCES) 227238c8a9a5SSteve French break; 227338c8a9a5SSteve French retry_count++; 227438c8a9a5SSteve French } 227538c8a9a5SSteve French } 227638c8a9a5SSteve French 227738c8a9a5SSteve French /* 227838c8a9a5SSteve French * No-replace is the natural behavior for CIFS, so skip unlink hacks. 227938c8a9a5SSteve French */ 228038c8a9a5SSteve French if (flags & RENAME_NOREPLACE) 228138c8a9a5SSteve French goto cifs_rename_exit; 228238c8a9a5SSteve French 228338c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 228438c8a9a5SSteve French if (rc == -EEXIST && tcon->unix_ext) { 228538c8a9a5SSteve French /* 228638c8a9a5SSteve French * Are src and dst hardlinks of same inode? We can only tell 228738c8a9a5SSteve French * with unix extensions enabled. 228838c8a9a5SSteve French */ 228938c8a9a5SSteve French info_buf_source = 229038c8a9a5SSteve French kmalloc_array(2, sizeof(FILE_UNIX_BASIC_INFO), 229138c8a9a5SSteve French GFP_KERNEL); 229238c8a9a5SSteve French if (info_buf_source == NULL) { 229338c8a9a5SSteve French rc = -ENOMEM; 229438c8a9a5SSteve French goto cifs_rename_exit; 229538c8a9a5SSteve French } 229638c8a9a5SSteve French 229738c8a9a5SSteve French info_buf_target = info_buf_source + 1; 229838c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name, 229938c8a9a5SSteve French info_buf_source, 230038c8a9a5SSteve French cifs_sb->local_nls, 230138c8a9a5SSteve French cifs_remap(cifs_sb)); 230238c8a9a5SSteve French if (tmprc != 0) 230338c8a9a5SSteve French goto unlink_target; 230438c8a9a5SSteve French 230538c8a9a5SSteve French tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name, 230638c8a9a5SSteve French info_buf_target, 230738c8a9a5SSteve French cifs_sb->local_nls, 230838c8a9a5SSteve French cifs_remap(cifs_sb)); 230938c8a9a5SSteve French 231038c8a9a5SSteve French if (tmprc == 0 && (info_buf_source->UniqueId == 231138c8a9a5SSteve French info_buf_target->UniqueId)) { 231238c8a9a5SSteve French /* same file, POSIX says that this is a noop */ 231338c8a9a5SSteve French rc = 0; 231438c8a9a5SSteve French goto cifs_rename_exit; 231538c8a9a5SSteve French } 231638c8a9a5SSteve French } 231738c8a9a5SSteve French /* 231838c8a9a5SSteve French * else ... BB we could add the same check for Windows by 231938c8a9a5SSteve French * checking the UniqueId via FILE_INTERNAL_INFO 232038c8a9a5SSteve French */ 232138c8a9a5SSteve French 232238c8a9a5SSteve French unlink_target: 232338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 232438c8a9a5SSteve French 232538c8a9a5SSteve French /* Try unlinking the target dentry if it's not negative */ 232638c8a9a5SSteve French if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) { 232738c8a9a5SSteve French if (d_is_dir(target_dentry)) 232838c8a9a5SSteve French tmprc = cifs_rmdir(target_dir, target_dentry); 232938c8a9a5SSteve French else 233038c8a9a5SSteve French tmprc = cifs_unlink(target_dir, target_dentry); 233138c8a9a5SSteve French if (tmprc) 233238c8a9a5SSteve French goto cifs_rename_exit; 233338c8a9a5SSteve French rc = cifs_do_rename(xid, source_dentry, from_name, 233438c8a9a5SSteve French target_dentry, to_name); 233538c8a9a5SSteve French } 233638c8a9a5SSteve French 233738c8a9a5SSteve French /* force revalidate to go get info when needed */ 233838c8a9a5SSteve French CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; 233938c8a9a5SSteve French 234038c8a9a5SSteve French source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime = 234138c8a9a5SSteve French target_dir->i_mtime = current_time(source_dir); 234238c8a9a5SSteve French 234338c8a9a5SSteve French cifs_rename_exit: 234438c8a9a5SSteve French kfree(info_buf_source); 234538c8a9a5SSteve French free_dentry_path(page2); 234638c8a9a5SSteve French free_dentry_path(page1); 234738c8a9a5SSteve French free_xid(xid); 234838c8a9a5SSteve French cifs_put_tlink(tlink); 234938c8a9a5SSteve French return rc; 235038c8a9a5SSteve French } 235138c8a9a5SSteve French 235238c8a9a5SSteve French static bool 235338c8a9a5SSteve French cifs_dentry_needs_reval(struct dentry *dentry) 235438c8a9a5SSteve French { 235538c8a9a5SSteve French struct inode *inode = d_inode(dentry); 235638c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 235738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 235838c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 235938c8a9a5SSteve French struct cached_fid *cfid = NULL; 236038c8a9a5SSteve French 236138c8a9a5SSteve French if (cifs_i->time == 0) 236238c8a9a5SSteve French return true; 236338c8a9a5SSteve French 236438c8a9a5SSteve French if (CIFS_CACHE_READ(cifs_i)) 236538c8a9a5SSteve French return false; 236638c8a9a5SSteve French 236738c8a9a5SSteve French if (!lookupCacheEnabled) 236838c8a9a5SSteve French return true; 236938c8a9a5SSteve French 237038c8a9a5SSteve French if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) { 237138c8a9a5SSteve French spin_lock(&cfid->fid_lock); 237238c8a9a5SSteve French if (cfid->time && cifs_i->time > cfid->time) { 237338c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 237438c8a9a5SSteve French close_cached_dir(cfid); 237538c8a9a5SSteve French return false; 237638c8a9a5SSteve French } 237738c8a9a5SSteve French spin_unlock(&cfid->fid_lock); 237838c8a9a5SSteve French close_cached_dir(cfid); 237938c8a9a5SSteve French } 238038c8a9a5SSteve French /* 238138c8a9a5SSteve French * depending on inode type, check if attribute caching disabled for 238238c8a9a5SSteve French * files or directories 238338c8a9a5SSteve French */ 238438c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) { 238538c8a9a5SSteve French if (!cifs_sb->ctx->acdirmax) 238638c8a9a5SSteve French return true; 238738c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 238838c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acdirmax)) 238938c8a9a5SSteve French return true; 239038c8a9a5SSteve French } else { /* file */ 239138c8a9a5SSteve French if (!cifs_sb->ctx->acregmax) 239238c8a9a5SSteve French return true; 239338c8a9a5SSteve French if (!time_in_range(jiffies, cifs_i->time, 239438c8a9a5SSteve French cifs_i->time + cifs_sb->ctx->acregmax)) 239538c8a9a5SSteve French return true; 239638c8a9a5SSteve French } 239738c8a9a5SSteve French 239838c8a9a5SSteve French /* hardlinked files w/ noserverino get "special" treatment */ 239938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 240038c8a9a5SSteve French S_ISREG(inode->i_mode) && inode->i_nlink != 1) 240138c8a9a5SSteve French return true; 240238c8a9a5SSteve French 240338c8a9a5SSteve French return false; 240438c8a9a5SSteve French } 240538c8a9a5SSteve French 240638c8a9a5SSteve French /* 240738c8a9a5SSteve French * Zap the cache. Called when invalid_mapping flag is set. 240838c8a9a5SSteve French */ 240938c8a9a5SSteve French int 241038c8a9a5SSteve French cifs_invalidate_mapping(struct inode *inode) 241138c8a9a5SSteve French { 241238c8a9a5SSteve French int rc = 0; 241338c8a9a5SSteve French 241438c8a9a5SSteve French if (inode->i_mapping && inode->i_mapping->nrpages != 0) { 241538c8a9a5SSteve French rc = invalidate_inode_pages2(inode->i_mapping); 241638c8a9a5SSteve French if (rc) 2417acf35d79SSteve French cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n", 2418acf35d79SSteve French __func__, inode, rc); 241938c8a9a5SSteve French } 242038c8a9a5SSteve French 242138c8a9a5SSteve French return rc; 242238c8a9a5SSteve French } 242338c8a9a5SSteve French 242438c8a9a5SSteve French /** 242538c8a9a5SSteve French * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks 242638c8a9a5SSteve French * 242738c8a9a5SSteve French * @key: currently unused 242838c8a9a5SSteve French * @mode: the task state to sleep in 242938c8a9a5SSteve French */ 243038c8a9a5SSteve French static int 243138c8a9a5SSteve French cifs_wait_bit_killable(struct wait_bit_key *key, int mode) 243238c8a9a5SSteve French { 243338c8a9a5SSteve French schedule(); 243438c8a9a5SSteve French if (signal_pending_state(mode, current)) 243538c8a9a5SSteve French return -ERESTARTSYS; 243638c8a9a5SSteve French return 0; 243738c8a9a5SSteve French } 243838c8a9a5SSteve French 243938c8a9a5SSteve French int 244038c8a9a5SSteve French cifs_revalidate_mapping(struct inode *inode) 244138c8a9a5SSteve French { 244238c8a9a5SSteve French int rc; 244338c8a9a5SSteve French unsigned long *flags = &CIFS_I(inode)->flags; 244438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 244538c8a9a5SSteve French 244638c8a9a5SSteve French /* swapfiles are not supposed to be shared */ 244738c8a9a5SSteve French if (IS_SWAPFILE(inode)) 244838c8a9a5SSteve French return 0; 244938c8a9a5SSteve French 245038c8a9a5SSteve French rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable, 245138c8a9a5SSteve French TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 245238c8a9a5SSteve French if (rc) 245338c8a9a5SSteve French return rc; 245438c8a9a5SSteve French 245538c8a9a5SSteve French if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) { 245638c8a9a5SSteve French /* for cache=singleclient, do not invalidate */ 245738c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) 245838c8a9a5SSteve French goto skip_invalidate; 245938c8a9a5SSteve French 246038c8a9a5SSteve French rc = cifs_invalidate_mapping(inode); 246138c8a9a5SSteve French if (rc) 246238c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, flags); 246338c8a9a5SSteve French } 246438c8a9a5SSteve French 246538c8a9a5SSteve French skip_invalidate: 246638c8a9a5SSteve French clear_bit_unlock(CIFS_INO_LOCK, flags); 246738c8a9a5SSteve French smp_mb__after_atomic(); 246838c8a9a5SSteve French wake_up_bit(flags, CIFS_INO_LOCK); 246938c8a9a5SSteve French 247038c8a9a5SSteve French return rc; 247138c8a9a5SSteve French } 247238c8a9a5SSteve French 247338c8a9a5SSteve French int 247438c8a9a5SSteve French cifs_zap_mapping(struct inode *inode) 247538c8a9a5SSteve French { 247638c8a9a5SSteve French set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags); 247738c8a9a5SSteve French return cifs_revalidate_mapping(inode); 247838c8a9a5SSteve French } 247938c8a9a5SSteve French 248038c8a9a5SSteve French int cifs_revalidate_file_attr(struct file *filp) 248138c8a9a5SSteve French { 248238c8a9a5SSteve French int rc = 0; 248338c8a9a5SSteve French struct dentry *dentry = file_dentry(filp); 248438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 248538c8a9a5SSteve French struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; 248638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 248738c8a9a5SSteve French 248838c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 248938c8a9a5SSteve French return rc; 249038c8a9a5SSteve French 249138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 249238c8a9a5SSteve French if (tlink_tcon(cfile->tlink)->unix_ext) 249338c8a9a5SSteve French rc = cifs_get_file_info_unix(filp); 249438c8a9a5SSteve French else 249538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 249638c8a9a5SSteve French rc = cifs_get_file_info(filp); 249738c8a9a5SSteve French 249838c8a9a5SSteve French return rc; 249938c8a9a5SSteve French } 250038c8a9a5SSteve French 250138c8a9a5SSteve French int cifs_revalidate_dentry_attr(struct dentry *dentry) 250238c8a9a5SSteve French { 250338c8a9a5SSteve French unsigned int xid; 250438c8a9a5SSteve French int rc = 0; 250538c8a9a5SSteve French struct inode *inode = d_inode(dentry); 250638c8a9a5SSteve French struct super_block *sb = dentry->d_sb; 250738c8a9a5SSteve French const char *full_path; 250838c8a9a5SSteve French void *page; 250938c8a9a5SSteve French int count = 0; 251038c8a9a5SSteve French 251138c8a9a5SSteve French if (inode == NULL) 251238c8a9a5SSteve French return -ENOENT; 251338c8a9a5SSteve French 251438c8a9a5SSteve French if (!cifs_dentry_needs_reval(dentry)) 251538c8a9a5SSteve French return rc; 251638c8a9a5SSteve French 251738c8a9a5SSteve French xid = get_xid(); 251838c8a9a5SSteve French 251938c8a9a5SSteve French page = alloc_dentry_path(); 252038c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 252138c8a9a5SSteve French if (IS_ERR(full_path)) { 252238c8a9a5SSteve French rc = PTR_ERR(full_path); 252338c8a9a5SSteve French goto out; 252438c8a9a5SSteve French } 252538c8a9a5SSteve French 252638c8a9a5SSteve French cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n", 252738c8a9a5SSteve French full_path, inode, inode->i_count.counter, 252838c8a9a5SSteve French dentry, cifs_get_time(dentry), jiffies); 252938c8a9a5SSteve French 253038c8a9a5SSteve French again: 253138c8a9a5SSteve French if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) 253238c8a9a5SSteve French rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); 253338c8a9a5SSteve French else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) 253438c8a9a5SSteve French rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); 253538c8a9a5SSteve French else 253638c8a9a5SSteve French rc = cifs_get_inode_info(&inode, full_path, NULL, sb, 253738c8a9a5SSteve French xid, NULL); 253838c8a9a5SSteve French if (rc == -EAGAIN && count++ < 10) 253938c8a9a5SSteve French goto again; 254038c8a9a5SSteve French out: 254138c8a9a5SSteve French free_dentry_path(page); 254238c8a9a5SSteve French free_xid(xid); 254338c8a9a5SSteve French 254438c8a9a5SSteve French return rc; 254538c8a9a5SSteve French } 254638c8a9a5SSteve French 254738c8a9a5SSteve French int cifs_revalidate_file(struct file *filp) 254838c8a9a5SSteve French { 254938c8a9a5SSteve French int rc; 255038c8a9a5SSteve French struct inode *inode = file_inode(filp); 255138c8a9a5SSteve French 255238c8a9a5SSteve French rc = cifs_revalidate_file_attr(filp); 255338c8a9a5SSteve French if (rc) 255438c8a9a5SSteve French return rc; 255538c8a9a5SSteve French 255638c8a9a5SSteve French return cifs_revalidate_mapping(inode); 255738c8a9a5SSteve French } 255838c8a9a5SSteve French 255938c8a9a5SSteve French /* revalidate a dentry's inode attributes */ 256038c8a9a5SSteve French int cifs_revalidate_dentry(struct dentry *dentry) 256138c8a9a5SSteve French { 256238c8a9a5SSteve French int rc; 256338c8a9a5SSteve French struct inode *inode = d_inode(dentry); 256438c8a9a5SSteve French 256538c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 256638c8a9a5SSteve French if (rc) 256738c8a9a5SSteve French return rc; 256838c8a9a5SSteve French 256938c8a9a5SSteve French return cifs_revalidate_mapping(inode); 257038c8a9a5SSteve French } 257138c8a9a5SSteve French 257238c8a9a5SSteve French int cifs_getattr(struct mnt_idmap *idmap, const struct path *path, 257338c8a9a5SSteve French struct kstat *stat, u32 request_mask, unsigned int flags) 257438c8a9a5SSteve French { 257538c8a9a5SSteve French struct dentry *dentry = path->dentry; 257638c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); 257738c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 257838c8a9a5SSteve French struct inode *inode = d_inode(dentry); 257938c8a9a5SSteve French int rc; 258038c8a9a5SSteve French 258138c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) 258238c8a9a5SSteve French return -EIO; 258338c8a9a5SSteve French 258438c8a9a5SSteve French /* 258538c8a9a5SSteve French * We need to be sure that all dirty pages are written and the server 258638c8a9a5SSteve French * has actual ctime, mtime and file length. 258738c8a9a5SSteve French */ 258838c8a9a5SSteve French if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) && 258938c8a9a5SSteve French !CIFS_CACHE_READ(CIFS_I(inode)) && 259038c8a9a5SSteve French inode->i_mapping && inode->i_mapping->nrpages != 0) { 259138c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 259238c8a9a5SSteve French if (rc) { 259338c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 259438c8a9a5SSteve French return rc; 259538c8a9a5SSteve French } 259638c8a9a5SSteve French } 259738c8a9a5SSteve French 259838c8a9a5SSteve French if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC) 259938c8a9a5SSteve French CIFS_I(inode)->time = 0; /* force revalidate */ 260038c8a9a5SSteve French 260138c8a9a5SSteve French /* 260238c8a9a5SSteve French * If the caller doesn't require syncing, only sync if 260338c8a9a5SSteve French * necessary (e.g. due to earlier truncate or setattr 260438c8a9a5SSteve French * invalidating the cached metadata) 260538c8a9a5SSteve French */ 260638c8a9a5SSteve French if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) || 260738c8a9a5SSteve French (CIFS_I(inode)->time == 0)) { 260838c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 260938c8a9a5SSteve French if (rc) 261038c8a9a5SSteve French return rc; 261138c8a9a5SSteve French } 261238c8a9a5SSteve French 261338c8a9a5SSteve French generic_fillattr(&nop_mnt_idmap, inode, stat); 261438c8a9a5SSteve French stat->blksize = cifs_sb->ctx->bsize; 261538c8a9a5SSteve French stat->ino = CIFS_I(inode)->uniqueid; 261638c8a9a5SSteve French 261738c8a9a5SSteve French /* old CIFS Unix Extensions doesn't return create time */ 261838c8a9a5SSteve French if (CIFS_I(inode)->createtime) { 261938c8a9a5SSteve French stat->result_mask |= STATX_BTIME; 262038c8a9a5SSteve French stat->btime = 262138c8a9a5SSteve French cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); 262238c8a9a5SSteve French } 262338c8a9a5SSteve French 262438c8a9a5SSteve French stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED); 262538c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) 262638c8a9a5SSteve French stat->attributes |= STATX_ATTR_COMPRESSED; 262738c8a9a5SSteve French if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED) 262838c8a9a5SSteve French stat->attributes |= STATX_ATTR_ENCRYPTED; 262938c8a9a5SSteve French 263038c8a9a5SSteve French /* 263138c8a9a5SSteve French * If on a multiuser mount without unix extensions or cifsacl being 263238c8a9a5SSteve French * enabled, and the admin hasn't overridden them, set the ownership 263338c8a9a5SSteve French * to the fsuid/fsgid of the current process. 263438c8a9a5SSteve French */ 263538c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && 263638c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 263738c8a9a5SSteve French !tcon->unix_ext) { 263838c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) 263938c8a9a5SSteve French stat->uid = current_fsuid(); 264038c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) 264138c8a9a5SSteve French stat->gid = current_fsgid(); 264238c8a9a5SSteve French } 264338c8a9a5SSteve French return 0; 264438c8a9a5SSteve French } 264538c8a9a5SSteve French 264638c8a9a5SSteve French int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, 264738c8a9a5SSteve French u64 len) 264838c8a9a5SSteve French { 264938c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 265038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->netfs.inode.i_sb); 265138c8a9a5SSteve French struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 265238c8a9a5SSteve French struct TCP_Server_Info *server = tcon->ses->server; 265338c8a9a5SSteve French struct cifsFileInfo *cfile; 265438c8a9a5SSteve French int rc; 265538c8a9a5SSteve French 265638c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 265738c8a9a5SSteve French return -EIO; 265838c8a9a5SSteve French 265938c8a9a5SSteve French /* 266038c8a9a5SSteve French * We need to be sure that all dirty pages are written as they 266138c8a9a5SSteve French * might fill holes on the server. 266238c8a9a5SSteve French */ 266338c8a9a5SSteve French if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && 266438c8a9a5SSteve French inode->i_mapping->nrpages != 0) { 266538c8a9a5SSteve French rc = filemap_fdatawait(inode->i_mapping); 266638c8a9a5SSteve French if (rc) { 266738c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 266838c8a9a5SSteve French return rc; 266938c8a9a5SSteve French } 267038c8a9a5SSteve French } 267138c8a9a5SSteve French 267238c8a9a5SSteve French cfile = find_readable_file(cifs_i, false); 267338c8a9a5SSteve French if (cfile == NULL) 267438c8a9a5SSteve French return -EINVAL; 267538c8a9a5SSteve French 267638c8a9a5SSteve French if (server->ops->fiemap) { 267738c8a9a5SSteve French rc = server->ops->fiemap(tcon, cfile, fei, start, len); 267838c8a9a5SSteve French cifsFileInfo_put(cfile); 267938c8a9a5SSteve French return rc; 268038c8a9a5SSteve French } 268138c8a9a5SSteve French 268238c8a9a5SSteve French cifsFileInfo_put(cfile); 268338c8a9a5SSteve French return -ENOTSUPP; 268438c8a9a5SSteve French } 268538c8a9a5SSteve French 268638c8a9a5SSteve French int cifs_truncate_page(struct address_space *mapping, loff_t from) 268738c8a9a5SSteve French { 268838c8a9a5SSteve French pgoff_t index = from >> PAGE_SHIFT; 268938c8a9a5SSteve French unsigned offset = from & (PAGE_SIZE - 1); 269038c8a9a5SSteve French struct page *page; 269138c8a9a5SSteve French int rc = 0; 269238c8a9a5SSteve French 269338c8a9a5SSteve French page = grab_cache_page(mapping, index); 269438c8a9a5SSteve French if (!page) 269538c8a9a5SSteve French return -ENOMEM; 269638c8a9a5SSteve French 269738c8a9a5SSteve French zero_user_segment(page, offset, PAGE_SIZE); 269838c8a9a5SSteve French unlock_page(page); 269938c8a9a5SSteve French put_page(page); 270038c8a9a5SSteve French return rc; 270138c8a9a5SSteve French } 270238c8a9a5SSteve French 270338c8a9a5SSteve French void cifs_setsize(struct inode *inode, loff_t offset) 270438c8a9a5SSteve French { 270538c8a9a5SSteve French struct cifsInodeInfo *cifs_i = CIFS_I(inode); 270638c8a9a5SSteve French 270738c8a9a5SSteve French spin_lock(&inode->i_lock); 270838c8a9a5SSteve French i_size_write(inode, offset); 270938c8a9a5SSteve French spin_unlock(&inode->i_lock); 271038c8a9a5SSteve French 271138c8a9a5SSteve French /* Cached inode must be refreshed on truncate */ 271238c8a9a5SSteve French cifs_i->time = 0; 271338c8a9a5SSteve French truncate_pagecache(inode, offset); 271438c8a9a5SSteve French } 271538c8a9a5SSteve French 271638c8a9a5SSteve French static int 271738c8a9a5SSteve French cifs_set_file_size(struct inode *inode, struct iattr *attrs, 271838c8a9a5SSteve French unsigned int xid, const char *full_path) 271938c8a9a5SSteve French { 272038c8a9a5SSteve French int rc; 272138c8a9a5SSteve French struct cifsFileInfo *open_file; 272238c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 272338c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 272438c8a9a5SSteve French struct tcon_link *tlink = NULL; 272538c8a9a5SSteve French struct cifs_tcon *tcon = NULL; 272638c8a9a5SSteve French struct TCP_Server_Info *server; 272738c8a9a5SSteve French 272838c8a9a5SSteve French /* 272938c8a9a5SSteve French * To avoid spurious oplock breaks from server, in the case of 273038c8a9a5SSteve French * inodes that we already have open, avoid doing path based 273138c8a9a5SSteve French * setting of file size if we can do it by handle. 273238c8a9a5SSteve French * This keeps our caching token (oplock) and avoids timeouts 273338c8a9a5SSteve French * when the local oplock break takes longer to flush 273438c8a9a5SSteve French * writebehind data than the SMB timeout for the SetPathInfo 273538c8a9a5SSteve French * request would allow 273638c8a9a5SSteve French */ 273738c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 273838c8a9a5SSteve French if (open_file) { 273938c8a9a5SSteve French tcon = tlink_tcon(open_file->tlink); 274038c8a9a5SSteve French server = tcon->ses->server; 274138c8a9a5SSteve French if (server->ops->set_file_size) 274238c8a9a5SSteve French rc = server->ops->set_file_size(xid, tcon, open_file, 274338c8a9a5SSteve French attrs->ia_size, false); 274438c8a9a5SSteve French else 274538c8a9a5SSteve French rc = -ENOSYS; 274638c8a9a5SSteve French cifsFileInfo_put(open_file); 274738c8a9a5SSteve French cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc); 274838c8a9a5SSteve French } else 274938c8a9a5SSteve French rc = -EINVAL; 275038c8a9a5SSteve French 275138c8a9a5SSteve French if (!rc) 275238c8a9a5SSteve French goto set_size_out; 275338c8a9a5SSteve French 275438c8a9a5SSteve French if (tcon == NULL) { 275538c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 275638c8a9a5SSteve French if (IS_ERR(tlink)) 275738c8a9a5SSteve French return PTR_ERR(tlink); 275838c8a9a5SSteve French tcon = tlink_tcon(tlink); 275938c8a9a5SSteve French server = tcon->ses->server; 276038c8a9a5SSteve French } 276138c8a9a5SSteve French 276238c8a9a5SSteve French /* 276338c8a9a5SSteve French * Set file size by pathname rather than by handle either because no 276438c8a9a5SSteve French * valid, writeable file handle for it was found or because there was 276538c8a9a5SSteve French * an error setting it by handle. 276638c8a9a5SSteve French */ 276738c8a9a5SSteve French if (server->ops->set_path_size) 276838c8a9a5SSteve French rc = server->ops->set_path_size(xid, tcon, full_path, 276938c8a9a5SSteve French attrs->ia_size, cifs_sb, false); 277038c8a9a5SSteve French else 277138c8a9a5SSteve French rc = -ENOSYS; 277238c8a9a5SSteve French cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc); 277338c8a9a5SSteve French 277438c8a9a5SSteve French if (tlink) 277538c8a9a5SSteve French cifs_put_tlink(tlink); 277638c8a9a5SSteve French 277738c8a9a5SSteve French set_size_out: 277838c8a9a5SSteve French if (rc == 0) { 277938c8a9a5SSteve French cifsInode->server_eof = attrs->ia_size; 278038c8a9a5SSteve French cifs_setsize(inode, attrs->ia_size); 278138c8a9a5SSteve French /* 278238c8a9a5SSteve French * i_blocks is not related to (i_size / i_blksize), but instead 278338c8a9a5SSteve French * 512 byte (2**9) size is required for calculating num blocks. 278438c8a9a5SSteve French * Until we can query the server for actual allocation size, 278538c8a9a5SSteve French * this is best estimate we have for blocks allocated for a file 278638c8a9a5SSteve French * Number of blocks must be rounded up so size 1 is not 0 blocks 278738c8a9a5SSteve French */ 278838c8a9a5SSteve French inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9; 278938c8a9a5SSteve French 279038c8a9a5SSteve French /* 279138c8a9a5SSteve French * The man page of truncate says if the size changed, 279238c8a9a5SSteve French * then the st_ctime and st_mtime fields for the file 279338c8a9a5SSteve French * are updated. 279438c8a9a5SSteve French */ 279538c8a9a5SSteve French attrs->ia_ctime = attrs->ia_mtime = current_time(inode); 279638c8a9a5SSteve French attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME; 279738c8a9a5SSteve French 279838c8a9a5SSteve French cifs_truncate_page(inode->i_mapping, inode->i_size); 279938c8a9a5SSteve French } 280038c8a9a5SSteve French 280138c8a9a5SSteve French return rc; 280238c8a9a5SSteve French } 280338c8a9a5SSteve French 280438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 280538c8a9a5SSteve French static int 280638c8a9a5SSteve French cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 280738c8a9a5SSteve French { 280838c8a9a5SSteve French int rc; 280938c8a9a5SSteve French unsigned int xid; 281038c8a9a5SSteve French const char *full_path; 281138c8a9a5SSteve French void *page = alloc_dentry_path(); 281238c8a9a5SSteve French struct inode *inode = d_inode(direntry); 281338c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 281438c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 281538c8a9a5SSteve French struct tcon_link *tlink; 281638c8a9a5SSteve French struct cifs_tcon *pTcon; 281738c8a9a5SSteve French struct cifs_unix_set_info_args *args = NULL; 281838c8a9a5SSteve French struct cifsFileInfo *open_file; 281938c8a9a5SSteve French 282038c8a9a5SSteve French cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n", 282138c8a9a5SSteve French direntry, attrs->ia_valid); 282238c8a9a5SSteve French 282338c8a9a5SSteve French xid = get_xid(); 282438c8a9a5SSteve French 282538c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 282638c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 282738c8a9a5SSteve French 282838c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 282938c8a9a5SSteve French if (rc < 0) 283038c8a9a5SSteve French goto out; 283138c8a9a5SSteve French 283238c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 283338c8a9a5SSteve French if (IS_ERR(full_path)) { 283438c8a9a5SSteve French rc = PTR_ERR(full_path); 283538c8a9a5SSteve French goto out; 283638c8a9a5SSteve French } 283738c8a9a5SSteve French 283838c8a9a5SSteve French /* 283938c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 284038c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the 284138c8a9a5SSteve French * ownership or mode then we may also need to do this. Here, we take 284238c8a9a5SSteve French * the safe way out and just do the flush on all setattr requests. If 284338c8a9a5SSteve French * the flush returns error, store it to report later and continue. 284438c8a9a5SSteve French * 284538c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 284638c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 284738c8a9a5SSteve French * the flush returns error? 284838c8a9a5SSteve French */ 284938c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 285038c8a9a5SSteve French if (is_interrupt_error(rc)) { 285138c8a9a5SSteve French rc = -ERESTARTSYS; 285238c8a9a5SSteve French goto out; 285338c8a9a5SSteve French } 285438c8a9a5SSteve French 285538c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 285638c8a9a5SSteve French rc = 0; 285738c8a9a5SSteve French 285838c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 285938c8a9a5SSteve French rc = cifs_set_file_size(inode, attrs, xid, full_path); 286038c8a9a5SSteve French if (rc != 0) 286138c8a9a5SSteve French goto out; 286238c8a9a5SSteve French } 286338c8a9a5SSteve French 286438c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 286538c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 286638c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 286738c8a9a5SSteve French 286838c8a9a5SSteve French args = kmalloc(sizeof(*args), GFP_KERNEL); 286938c8a9a5SSteve French if (args == NULL) { 287038c8a9a5SSteve French rc = -ENOMEM; 287138c8a9a5SSteve French goto out; 287238c8a9a5SSteve French } 287338c8a9a5SSteve French 287438c8a9a5SSteve French /* set up the struct */ 287538c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) 287638c8a9a5SSteve French args->mode = attrs->ia_mode; 287738c8a9a5SSteve French else 287838c8a9a5SSteve French args->mode = NO_CHANGE_64; 287938c8a9a5SSteve French 288038c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 288138c8a9a5SSteve French args->uid = attrs->ia_uid; 288238c8a9a5SSteve French else 288338c8a9a5SSteve French args->uid = INVALID_UID; /* no change */ 288438c8a9a5SSteve French 288538c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 288638c8a9a5SSteve French args->gid = attrs->ia_gid; 288738c8a9a5SSteve French else 288838c8a9a5SSteve French args->gid = INVALID_GID; /* no change */ 288938c8a9a5SSteve French 289038c8a9a5SSteve French if (attrs->ia_valid & ATTR_ATIME) 289138c8a9a5SSteve French args->atime = cifs_UnixTimeToNT(attrs->ia_atime); 289238c8a9a5SSteve French else 289338c8a9a5SSteve French args->atime = NO_CHANGE_64; 289438c8a9a5SSteve French 289538c8a9a5SSteve French if (attrs->ia_valid & ATTR_MTIME) 289638c8a9a5SSteve French args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); 289738c8a9a5SSteve French else 289838c8a9a5SSteve French args->mtime = NO_CHANGE_64; 289938c8a9a5SSteve French 290038c8a9a5SSteve French if (attrs->ia_valid & ATTR_CTIME) 290138c8a9a5SSteve French args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); 290238c8a9a5SSteve French else 290338c8a9a5SSteve French args->ctime = NO_CHANGE_64; 290438c8a9a5SSteve French 290538c8a9a5SSteve French args->device = 0; 290638c8a9a5SSteve French open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY); 290738c8a9a5SSteve French if (open_file) { 290838c8a9a5SSteve French u16 nfid = open_file->fid.netfid; 290938c8a9a5SSteve French u32 npid = open_file->pid; 291038c8a9a5SSteve French pTcon = tlink_tcon(open_file->tlink); 291138c8a9a5SSteve French rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); 291238c8a9a5SSteve French cifsFileInfo_put(open_file); 291338c8a9a5SSteve French } else { 291438c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 291538c8a9a5SSteve French if (IS_ERR(tlink)) { 291638c8a9a5SSteve French rc = PTR_ERR(tlink); 291738c8a9a5SSteve French goto out; 291838c8a9a5SSteve French } 291938c8a9a5SSteve French pTcon = tlink_tcon(tlink); 292038c8a9a5SSteve French rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, 292138c8a9a5SSteve French cifs_sb->local_nls, 292238c8a9a5SSteve French cifs_remap(cifs_sb)); 292338c8a9a5SSteve French cifs_put_tlink(tlink); 292438c8a9a5SSteve French } 292538c8a9a5SSteve French 292638c8a9a5SSteve French if (rc) 292738c8a9a5SSteve French goto out; 292838c8a9a5SSteve French 292938c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 293038c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 293138c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 293238c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 293338c8a9a5SSteve French } 293438c8a9a5SSteve French 293538c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 293638c8a9a5SSteve French mark_inode_dirty(inode); 293738c8a9a5SSteve French 293838c8a9a5SSteve French /* force revalidate when any of these times are set since some 293938c8a9a5SSteve French of the fs types (eg ext3, fat) do not have fine enough 294038c8a9a5SSteve French time granularity to match protocol, and we do not have a 294138c8a9a5SSteve French a way (yet) to query the server fs's time granularity (and 294238c8a9a5SSteve French whether it rounds times down). 294338c8a9a5SSteve French */ 294438c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) 294538c8a9a5SSteve French cifsInode->time = 0; 294638c8a9a5SSteve French out: 294738c8a9a5SSteve French kfree(args); 294838c8a9a5SSteve French free_dentry_path(page); 294938c8a9a5SSteve French free_xid(xid); 295038c8a9a5SSteve French return rc; 295138c8a9a5SSteve French } 295238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 295338c8a9a5SSteve French 295438c8a9a5SSteve French static int 295538c8a9a5SSteve French cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) 295638c8a9a5SSteve French { 295738c8a9a5SSteve French unsigned int xid; 295838c8a9a5SSteve French kuid_t uid = INVALID_UID; 295938c8a9a5SSteve French kgid_t gid = INVALID_GID; 296038c8a9a5SSteve French struct inode *inode = d_inode(direntry); 296138c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 296238c8a9a5SSteve French struct cifsInodeInfo *cifsInode = CIFS_I(inode); 296338c8a9a5SSteve French struct cifsFileInfo *wfile; 296438c8a9a5SSteve French struct cifs_tcon *tcon; 296538c8a9a5SSteve French const char *full_path; 296638c8a9a5SSteve French void *page = alloc_dentry_path(); 296738c8a9a5SSteve French int rc = -EACCES; 296838c8a9a5SSteve French __u32 dosattr = 0; 296938c8a9a5SSteve French __u64 mode = NO_CHANGE_64; 297038c8a9a5SSteve French 297138c8a9a5SSteve French xid = get_xid(); 297238c8a9a5SSteve French 297338c8a9a5SSteve French cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n", 297438c8a9a5SSteve French direntry, attrs->ia_valid); 297538c8a9a5SSteve French 297638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) 297738c8a9a5SSteve French attrs->ia_valid |= ATTR_FORCE; 297838c8a9a5SSteve French 297938c8a9a5SSteve French rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs); 298038c8a9a5SSteve French if (rc < 0) 298138c8a9a5SSteve French goto cifs_setattr_exit; 298238c8a9a5SSteve French 298338c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 298438c8a9a5SSteve French if (IS_ERR(full_path)) { 298538c8a9a5SSteve French rc = PTR_ERR(full_path); 298638c8a9a5SSteve French goto cifs_setattr_exit; 298738c8a9a5SSteve French } 298838c8a9a5SSteve French 298938c8a9a5SSteve French /* 299038c8a9a5SSteve French * Attempt to flush data before changing attributes. We need to do 299138c8a9a5SSteve French * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data 299238c8a9a5SSteve French * returns error, store it to report later and continue. 299338c8a9a5SSteve French * 299438c8a9a5SSteve French * BB: This should be smarter. Why bother flushing pages that 299538c8a9a5SSteve French * will be truncated anyway? Also, should we error out here if 299638c8a9a5SSteve French * the flush returns error? Do we need to check for ATTR_MTIME_SET flag? 299738c8a9a5SSteve French */ 299838c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) { 299938c8a9a5SSteve French rc = filemap_write_and_wait(inode->i_mapping); 300038c8a9a5SSteve French if (is_interrupt_error(rc)) { 300138c8a9a5SSteve French rc = -ERESTARTSYS; 300238c8a9a5SSteve French goto cifs_setattr_exit; 300338c8a9a5SSteve French } 300438c8a9a5SSteve French mapping_set_error(inode->i_mapping, rc); 300538c8a9a5SSteve French } 300638c8a9a5SSteve French 300738c8a9a5SSteve French rc = 0; 300838c8a9a5SSteve French 300938c8a9a5SSteve French if ((attrs->ia_valid & ATTR_MTIME) && 301038c8a9a5SSteve French !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { 301138c8a9a5SSteve French rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile); 301238c8a9a5SSteve French if (!rc) { 301338c8a9a5SSteve French tcon = tlink_tcon(wfile->tlink); 301438c8a9a5SSteve French rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid); 301538c8a9a5SSteve French cifsFileInfo_put(wfile); 301638c8a9a5SSteve French if (rc) 301738c8a9a5SSteve French goto cifs_setattr_exit; 301838c8a9a5SSteve French } else if (rc != -EBADF) 301938c8a9a5SSteve French goto cifs_setattr_exit; 302038c8a9a5SSteve French else 302138c8a9a5SSteve French rc = 0; 302238c8a9a5SSteve French } 302338c8a9a5SSteve French 302438c8a9a5SSteve French if (attrs->ia_valid & ATTR_SIZE) { 302538c8a9a5SSteve French rc = cifs_set_file_size(inode, attrs, xid, full_path); 302638c8a9a5SSteve French if (rc != 0) 302738c8a9a5SSteve French goto cifs_setattr_exit; 302838c8a9a5SSteve French } 302938c8a9a5SSteve French 303038c8a9a5SSteve French if (attrs->ia_valid & ATTR_UID) 303138c8a9a5SSteve French uid = attrs->ia_uid; 303238c8a9a5SSteve French 303338c8a9a5SSteve French if (attrs->ia_valid & ATTR_GID) 303438c8a9a5SSteve French gid = attrs->ia_gid; 303538c8a9a5SSteve French 303638c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 303738c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 303838c8a9a5SSteve French if (uid_valid(uid) || gid_valid(gid)) { 303938c8a9a5SSteve French mode = NO_CHANGE_64; 304038c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 304138c8a9a5SSteve French uid, gid); 304238c8a9a5SSteve French if (rc) { 304338c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting id failed with error: %d\n", 304438c8a9a5SSteve French __func__, rc); 304538c8a9a5SSteve French goto cifs_setattr_exit; 304638c8a9a5SSteve French } 304738c8a9a5SSteve French } 304838c8a9a5SSteve French } else 304938c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) 305038c8a9a5SSteve French attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 305138c8a9a5SSteve French 305238c8a9a5SSteve French /* skip mode change if it's just for clearing setuid/setgid */ 305338c8a9a5SSteve French if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 305438c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 305538c8a9a5SSteve French 305638c8a9a5SSteve French if (attrs->ia_valid & ATTR_MODE) { 305738c8a9a5SSteve French mode = attrs->ia_mode; 305838c8a9a5SSteve French rc = 0; 305938c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 306038c8a9a5SSteve French (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 306138c8a9a5SSteve French rc = id_mode_to_cifs_acl(inode, full_path, &mode, 306238c8a9a5SSteve French INVALID_UID, INVALID_GID); 306338c8a9a5SSteve French if (rc) { 306438c8a9a5SSteve French cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n", 306538c8a9a5SSteve French __func__, rc); 306638c8a9a5SSteve French goto cifs_setattr_exit; 306738c8a9a5SSteve French } 306838c8a9a5SSteve French 306938c8a9a5SSteve French /* 307038c8a9a5SSteve French * In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes. 307138c8a9a5SSteve French * Pick up the actual mode bits that were set. 307238c8a9a5SSteve French */ 307338c8a9a5SSteve French if (mode != attrs->ia_mode) 307438c8a9a5SSteve French attrs->ia_mode = mode; 307538c8a9a5SSteve French } else 307638c8a9a5SSteve French if (((mode & S_IWUGO) == 0) && 307738c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 307838c8a9a5SSteve French 307938c8a9a5SSteve French dosattr = cifsInode->cifsAttrs | ATTR_READONLY; 308038c8a9a5SSteve French 308138c8a9a5SSteve French /* fix up mode if we're not using dynperm */ 308238c8a9a5SSteve French if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) 308338c8a9a5SSteve French attrs->ia_mode = inode->i_mode & ~S_IWUGO; 308438c8a9a5SSteve French } else if ((mode & S_IWUGO) && 308538c8a9a5SSteve French (cifsInode->cifsAttrs & ATTR_READONLY)) { 308638c8a9a5SSteve French 308738c8a9a5SSteve French dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; 308838c8a9a5SSteve French /* Attributes of 0 are ignored */ 308938c8a9a5SSteve French if (dosattr == 0) 309038c8a9a5SSteve French dosattr |= ATTR_NORMAL; 309138c8a9a5SSteve French 309238c8a9a5SSteve French /* reset local inode permissions to normal */ 309338c8a9a5SSteve French if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 309438c8a9a5SSteve French attrs->ia_mode &= ~(S_IALLUGO); 309538c8a9a5SSteve French if (S_ISDIR(inode->i_mode)) 309638c8a9a5SSteve French attrs->ia_mode |= 309738c8a9a5SSteve French cifs_sb->ctx->dir_mode; 309838c8a9a5SSteve French else 309938c8a9a5SSteve French attrs->ia_mode |= 310038c8a9a5SSteve French cifs_sb->ctx->file_mode; 310138c8a9a5SSteve French } 310238c8a9a5SSteve French } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 310338c8a9a5SSteve French /* ignore mode change - ATTR_READONLY hasn't changed */ 310438c8a9a5SSteve French attrs->ia_valid &= ~ATTR_MODE; 310538c8a9a5SSteve French } 310638c8a9a5SSteve French } 310738c8a9a5SSteve French 310838c8a9a5SSteve French if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || 310938c8a9a5SSteve French ((attrs->ia_valid & ATTR_MODE) && dosattr)) { 311038c8a9a5SSteve French rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); 311138c8a9a5SSteve French /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ 311238c8a9a5SSteve French 311338c8a9a5SSteve French /* Even if error on time set, no sense failing the call if 311438c8a9a5SSteve French the server would set the time to a reasonable value anyway, 311538c8a9a5SSteve French and this check ensures that we are not being called from 311638c8a9a5SSteve French sys_utimes in which case we ought to fail the call back to 311738c8a9a5SSteve French the user when the server rejects the call */ 311838c8a9a5SSteve French if ((rc) && (attrs->ia_valid & 311938c8a9a5SSteve French (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) 312038c8a9a5SSteve French rc = 0; 312138c8a9a5SSteve French } 312238c8a9a5SSteve French 312338c8a9a5SSteve French /* do not need local check to inode_check_ok since the server does 312438c8a9a5SSteve French that */ 312538c8a9a5SSteve French if (rc) 312638c8a9a5SSteve French goto cifs_setattr_exit; 312738c8a9a5SSteve French 312838c8a9a5SSteve French if ((attrs->ia_valid & ATTR_SIZE) && 312938c8a9a5SSteve French attrs->ia_size != i_size_read(inode)) { 313038c8a9a5SSteve French truncate_setsize(inode, attrs->ia_size); 313138c8a9a5SSteve French fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); 313238c8a9a5SSteve French } 313338c8a9a5SSteve French 313438c8a9a5SSteve French setattr_copy(&nop_mnt_idmap, inode, attrs); 313538c8a9a5SSteve French mark_inode_dirty(inode); 313638c8a9a5SSteve French 313738c8a9a5SSteve French cifs_setattr_exit: 313838c8a9a5SSteve French free_xid(xid); 313938c8a9a5SSteve French free_dentry_path(page); 314038c8a9a5SSteve French return rc; 314138c8a9a5SSteve French } 314238c8a9a5SSteve French 314338c8a9a5SSteve French int 314438c8a9a5SSteve French cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry, 314538c8a9a5SSteve French struct iattr *attrs) 314638c8a9a5SSteve French { 314738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 314838c8a9a5SSteve French int rc, retries = 0; 314938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 315038c8a9a5SSteve French struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); 315138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 315238c8a9a5SSteve French 315338c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 315438c8a9a5SSteve French return -EIO; 315538c8a9a5SSteve French 315638c8a9a5SSteve French do { 315738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 315838c8a9a5SSteve French if (pTcon->unix_ext) 315938c8a9a5SSteve French rc = cifs_setattr_unix(direntry, attrs); 316038c8a9a5SSteve French else 316138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 316238c8a9a5SSteve French rc = cifs_setattr_nounix(direntry, attrs); 316338c8a9a5SSteve French retries++; 316438c8a9a5SSteve French } while (is_retryable_error(rc) && retries < 2); 316538c8a9a5SSteve French 316638c8a9a5SSteve French /* BB: add cifs_setattr_legacy for really old servers */ 316738c8a9a5SSteve French return rc; 316838c8a9a5SSteve French } 3169