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