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