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