xref: /openbmc/linux/fs/smb/client/inode.c (revision 01bce099)
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"
29db0f1c07SPaulo Alcantara #include "reparse.h"
3038c8a9a5SSteve French 
cifs_set_ops(struct inode * inode)3138c8a9a5SSteve French static void cifs_set_ops(struct inode *inode)
3238c8a9a5SSteve French {
3338c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
3438c8a9a5SSteve French 
3538c8a9a5SSteve French 	switch (inode->i_mode & S_IFMT) {
3638c8a9a5SSteve French 	case S_IFREG:
3738c8a9a5SSteve French 		inode->i_op = &cifs_file_inode_ops;
3838c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
3938c8a9a5SSteve French 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
4038c8a9a5SSteve French 				inode->i_fop = &cifs_file_direct_nobrl_ops;
4138c8a9a5SSteve French 			else
4238c8a9a5SSteve French 				inode->i_fop = &cifs_file_direct_ops;
4338c8a9a5SSteve French 		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
4438c8a9a5SSteve French 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
4538c8a9a5SSteve French 				inode->i_fop = &cifs_file_strict_nobrl_ops;
4638c8a9a5SSteve French 			else
4738c8a9a5SSteve French 				inode->i_fop = &cifs_file_strict_ops;
4838c8a9a5SSteve French 		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
4938c8a9a5SSteve French 			inode->i_fop = &cifs_file_nobrl_ops;
5038c8a9a5SSteve French 		else { /* not direct, send byte range locks */
5138c8a9a5SSteve French 			inode->i_fop = &cifs_file_ops;
5238c8a9a5SSteve French 		}
5338c8a9a5SSteve French 
5438c8a9a5SSteve French 		/* check if server can support readahead */
5538c8a9a5SSteve French 		if (cifs_sb_master_tcon(cifs_sb)->ses->server->max_read <
5638c8a9a5SSteve French 				PAGE_SIZE + MAX_CIFS_HDR_SIZE)
5738c8a9a5SSteve French 			inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
5838c8a9a5SSteve French 		else
5938c8a9a5SSteve French 			inode->i_data.a_ops = &cifs_addr_ops;
6038c8a9a5SSteve French 		break;
6138c8a9a5SSteve French 	case S_IFDIR:
6238c8a9a5SSteve French 		if (IS_AUTOMOUNT(inode)) {
630a049935SPaulo Alcantara 			inode->i_op = &cifs_namespace_inode_operations;
6438c8a9a5SSteve French 		} else {
6538c8a9a5SSteve French 			inode->i_op = &cifs_dir_inode_ops;
6638c8a9a5SSteve French 			inode->i_fop = &cifs_dir_ops;
6738c8a9a5SSteve French 		}
6838c8a9a5SSteve French 		break;
6938c8a9a5SSteve French 	case S_IFLNK:
7038c8a9a5SSteve French 		inode->i_op = &cifs_symlink_inode_ops;
7138c8a9a5SSteve French 		break;
7238c8a9a5SSteve French 	default:
7338c8a9a5SSteve French 		init_special_inode(inode, inode->i_mode, inode->i_rdev);
7438c8a9a5SSteve French 		break;
7538c8a9a5SSteve French 	}
7638c8a9a5SSteve French }
7738c8a9a5SSteve French 
7838c8a9a5SSteve French /* check inode attributes against fattr. If they don't match, tag the
7938c8a9a5SSteve French  * inode for cache invalidation
8038c8a9a5SSteve French  */
8138c8a9a5SSteve French static void
cifs_revalidate_cache(struct inode * inode,struct cifs_fattr * fattr)8238c8a9a5SSteve French cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
8338c8a9a5SSteve French {
8438c8a9a5SSteve French 	struct cifs_fscache_inode_coherency_data cd;
8538c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
8623171df5SJeff Layton 	struct timespec64 mtime;
8738c8a9a5SSteve French 
8838c8a9a5SSteve French 	cifs_dbg(FYI, "%s: revalidating inode %llu\n",
8938c8a9a5SSteve French 		 __func__, cifs_i->uniqueid);
9038c8a9a5SSteve French 
9138c8a9a5SSteve French 	if (inode->i_state & I_NEW) {
9238c8a9a5SSteve French 		cifs_dbg(FYI, "%s: inode %llu is new\n",
9338c8a9a5SSteve French 			 __func__, cifs_i->uniqueid);
9438c8a9a5SSteve French 		return;
9538c8a9a5SSteve French 	}
9638c8a9a5SSteve French 
9738c8a9a5SSteve French 	/* don't bother with revalidation if we have an oplock */
9838c8a9a5SSteve French 	if (CIFS_CACHE_READ(cifs_i)) {
9938c8a9a5SSteve French 		cifs_dbg(FYI, "%s: inode %llu is oplocked\n",
10038c8a9a5SSteve French 			 __func__, cifs_i->uniqueid);
10138c8a9a5SSteve French 		return;
10238c8a9a5SSteve French 	}
10338c8a9a5SSteve French 
10438c8a9a5SSteve French 	 /* revalidate if mtime or size have changed */
10538c8a9a5SSteve French 	fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
10623171df5SJeff Layton 	mtime = inode_get_mtime(inode);
10723171df5SJeff Layton 	if (timespec64_equal(&mtime, &fattr->cf_mtime) &&
10838c8a9a5SSteve French 	    cifs_i->server_eof == fattr->cf_eof) {
10938c8a9a5SSteve French 		cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
11038c8a9a5SSteve French 			 __func__, cifs_i->uniqueid);
11138c8a9a5SSteve French 		return;
11238c8a9a5SSteve French 	}
11338c8a9a5SSteve French 
11438c8a9a5SSteve French 	cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n",
11538c8a9a5SSteve French 		 __func__, cifs_i->uniqueid);
11638c8a9a5SSteve French 	set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
11738c8a9a5SSteve French 	/* Invalidate fscache cookie */
11838c8a9a5SSteve French 	cifs_fscache_fill_coherency(&cifs_i->netfs.inode, &cd);
11938c8a9a5SSteve French 	fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
12038c8a9a5SSteve French }
12138c8a9a5SSteve French 
12238c8a9a5SSteve French /*
12338c8a9a5SSteve French  * copy nlink to the inode, unless it wasn't provided.  Provide
12438c8a9a5SSteve French  * sane values if we don't have an existing one and none was provided
12538c8a9a5SSteve French  */
12638c8a9a5SSteve French static void
cifs_nlink_fattr_to_inode(struct inode * inode,struct cifs_fattr * fattr)12738c8a9a5SSteve French cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
12838c8a9a5SSteve French {
12938c8a9a5SSteve French 	/*
13038c8a9a5SSteve French 	 * if we're in a situation where we can't trust what we
13138c8a9a5SSteve French 	 * got from the server (readdir, some non-unix cases)
13238c8a9a5SSteve French 	 * fake reasonable values
13338c8a9a5SSteve French 	 */
13438c8a9a5SSteve French 	if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) {
13538c8a9a5SSteve French 		/* only provide fake values on a new inode */
13638c8a9a5SSteve French 		if (inode->i_state & I_NEW) {
13738c8a9a5SSteve French 			if (fattr->cf_cifsattrs & ATTR_DIRECTORY)
13838c8a9a5SSteve French 				set_nlink(inode, 2);
13938c8a9a5SSteve French 			else
14038c8a9a5SSteve French 				set_nlink(inode, 1);
14138c8a9a5SSteve French 		}
14238c8a9a5SSteve French 		return;
14338c8a9a5SSteve French 	}
14438c8a9a5SSteve French 
14538c8a9a5SSteve French 	/* we trust the server, so update it */
14638c8a9a5SSteve French 	set_nlink(inode, fattr->cf_nlink);
14738c8a9a5SSteve French }
14838c8a9a5SSteve French 
14938c8a9a5SSteve French /* populate an inode with info from a cifs_fattr struct */
15038c8a9a5SSteve French int
cifs_fattr_to_inode(struct inode * inode,struct cifs_fattr * fattr,bool from_readdir)1519179aa27SBharath SM cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
1529179aa27SBharath SM 		    bool from_readdir)
15338c8a9a5SSteve French {
15438c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
15538c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
15638c8a9a5SSteve French 
15738c8a9a5SSteve French 	if (!(inode->i_state & I_NEW) &&
15838c8a9a5SSteve French 	    unlikely(inode_wrong_type(inode, fattr->cf_mode))) {
15938c8a9a5SSteve French 		CIFS_I(inode)->time = 0; /* force reval */
16038c8a9a5SSteve French 		return -ESTALE;
16138c8a9a5SSteve French 	}
16238c8a9a5SSteve French 
16338c8a9a5SSteve French 	cifs_revalidate_cache(inode, fattr);
16438c8a9a5SSteve French 
16538c8a9a5SSteve French 	spin_lock(&inode->i_lock);
16638c8a9a5SSteve French 	fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
16738c8a9a5SSteve French 	fattr->cf_atime = timestamp_truncate(fattr->cf_atime, inode);
16838c8a9a5SSteve French 	fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode);
16938c8a9a5SSteve French 	/* we do not want atime to be less than mtime, it broke some apps */
17038c8a9a5SSteve French 	if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0)
17123171df5SJeff Layton 		inode_set_atime_to_ts(inode, fattr->cf_mtime);
17238c8a9a5SSteve French 	else
17323171df5SJeff Layton 		inode_set_atime_to_ts(inode, fattr->cf_atime);
17423171df5SJeff Layton 	inode_set_mtime_to_ts(inode, fattr->cf_mtime);
17594487653SJeff Layton 	inode_set_ctime_to_ts(inode, fattr->cf_ctime);
17638c8a9a5SSteve French 	inode->i_rdev = fattr->cf_rdev;
17738c8a9a5SSteve French 	cifs_nlink_fattr_to_inode(inode, fattr);
17838c8a9a5SSteve French 	inode->i_uid = fattr->cf_uid;
17938c8a9a5SSteve French 	inode->i_gid = fattr->cf_gid;
18038c8a9a5SSteve French 
18138c8a9a5SSteve French 	/* if dynperm is set, don't clobber existing mode */
18238c8a9a5SSteve French 	if (inode->i_state & I_NEW ||
18338c8a9a5SSteve French 	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
18438c8a9a5SSteve French 		inode->i_mode = fattr->cf_mode;
18538c8a9a5SSteve French 
18638c8a9a5SSteve French 	cifs_i->cifsAttrs = fattr->cf_cifsattrs;
187b9e741acSPaulo Alcantara 	cifs_i->reparse_tag = fattr->cf_cifstag;
18838c8a9a5SSteve French 
18938c8a9a5SSteve French 	if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
19038c8a9a5SSteve French 		cifs_i->time = 0;
19138c8a9a5SSteve French 	else
19238c8a9a5SSteve French 		cifs_i->time = jiffies;
19338c8a9a5SSteve French 
19438c8a9a5SSteve French 	if (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING)
19538c8a9a5SSteve French 		set_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);
19638c8a9a5SSteve French 	else
19738c8a9a5SSteve French 		clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);
19838c8a9a5SSteve French 
19938c8a9a5SSteve French 	cifs_i->server_eof = fattr->cf_eof;
20038c8a9a5SSteve French 	/*
20138c8a9a5SSteve French 	 * Can't safely change the file size here if the client is writing to
20238c8a9a5SSteve French 	 * it due to potential races.
20338c8a9a5SSteve French 	 */
2049179aa27SBharath SM 	if (is_size_safe_to_change(cifs_i, fattr->cf_eof, from_readdir)) {
20538c8a9a5SSteve French 		i_size_write(inode, fattr->cf_eof);
20638c8a9a5SSteve French 
20738c8a9a5SSteve French 		/*
20838c8a9a5SSteve French 		 * i_blocks is not related to (i_size / i_blksize),
20938c8a9a5SSteve French 		 * but instead 512 byte (2**9) size is required for
21038c8a9a5SSteve French 		 * calculating num blocks.
21138c8a9a5SSteve French 		 */
21238c8a9a5SSteve French 		inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
21338c8a9a5SSteve French 	}
21438c8a9a5SSteve French 
215b9e741acSPaulo Alcantara 	if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) {
21638c8a9a5SSteve French 		kfree(cifs_i->symlink_target);
21738c8a9a5SSteve French 		cifs_i->symlink_target = fattr->cf_symlink_target;
21838c8a9a5SSteve French 		fattr->cf_symlink_target = NULL;
21938c8a9a5SSteve French 	}
22038c8a9a5SSteve French 	spin_unlock(&inode->i_lock);
22138c8a9a5SSteve French 
222a18280e7SPaulo Alcantara 	if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
22338c8a9a5SSteve French 		inode->i_flags |= S_AUTOMOUNT;
22438c8a9a5SSteve French 	if (inode->i_state & I_NEW)
22538c8a9a5SSteve French 		cifs_set_ops(inode);
22638c8a9a5SSteve French 	return 0;
22738c8a9a5SSteve French }
22838c8a9a5SSteve French 
22938c8a9a5SSteve French void
cifs_fill_uniqueid(struct super_block * sb,struct cifs_fattr * fattr)23038c8a9a5SSteve French cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
23138c8a9a5SSteve French {
23238c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
23338c8a9a5SSteve French 
23438c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
23538c8a9a5SSteve French 		return;
23638c8a9a5SSteve French 
23738c8a9a5SSteve French 	fattr->cf_uniqueid = iunique(sb, ROOT_I);
23838c8a9a5SSteve French }
23938c8a9a5SSteve French 
24038c8a9a5SSteve French /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
24138c8a9a5SSteve French void
cifs_unix_basic_to_fattr(struct cifs_fattr * fattr,FILE_UNIX_BASIC_INFO * info,struct cifs_sb_info * cifs_sb)24238c8a9a5SSteve French cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
24338c8a9a5SSteve French 			 struct cifs_sb_info *cifs_sb)
24438c8a9a5SSteve French {
24538c8a9a5SSteve French 	memset(fattr, 0, sizeof(*fattr));
24638c8a9a5SSteve French 	fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
24738c8a9a5SSteve French 	fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
24838c8a9a5SSteve French 	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
24938c8a9a5SSteve French 
25038c8a9a5SSteve French 	fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
25138c8a9a5SSteve French 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
25238c8a9a5SSteve French 	fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
25338c8a9a5SSteve French 	/* old POSIX extensions don't get create time */
25438c8a9a5SSteve French 
25538c8a9a5SSteve French 	fattr->cf_mode = le64_to_cpu(info->Permissions);
25638c8a9a5SSteve French 
25738c8a9a5SSteve French 	/*
25838c8a9a5SSteve French 	 * Since we set the inode type below we need to mask off
25938c8a9a5SSteve French 	 * to avoid strange results if bits set above.
26038c8a9a5SSteve French 	 */
26138c8a9a5SSteve French 	fattr->cf_mode &= ~S_IFMT;
26238c8a9a5SSteve French 	switch (le32_to_cpu(info->Type)) {
26338c8a9a5SSteve French 	case UNIX_FILE:
26438c8a9a5SSteve French 		fattr->cf_mode |= S_IFREG;
26538c8a9a5SSteve French 		fattr->cf_dtype = DT_REG;
26638c8a9a5SSteve French 		break;
26738c8a9a5SSteve French 	case UNIX_SYMLINK:
26838c8a9a5SSteve French 		fattr->cf_mode |= S_IFLNK;
26938c8a9a5SSteve French 		fattr->cf_dtype = DT_LNK;
27038c8a9a5SSteve French 		break;
27138c8a9a5SSteve French 	case UNIX_DIR:
27238c8a9a5SSteve French 		fattr->cf_mode |= S_IFDIR;
27338c8a9a5SSteve French 		fattr->cf_dtype = DT_DIR;
27438c8a9a5SSteve French 		break;
27538c8a9a5SSteve French 	case UNIX_CHARDEV:
27638c8a9a5SSteve French 		fattr->cf_mode |= S_IFCHR;
27738c8a9a5SSteve French 		fattr->cf_dtype = DT_CHR;
27838c8a9a5SSteve French 		fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
27938c8a9a5SSteve French 				       le64_to_cpu(info->DevMinor) & MINORMASK);
28038c8a9a5SSteve French 		break;
28138c8a9a5SSteve French 	case UNIX_BLOCKDEV:
28238c8a9a5SSteve French 		fattr->cf_mode |= S_IFBLK;
28338c8a9a5SSteve French 		fattr->cf_dtype = DT_BLK;
28438c8a9a5SSteve French 		fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
28538c8a9a5SSteve French 				       le64_to_cpu(info->DevMinor) & MINORMASK);
28638c8a9a5SSteve French 		break;
28738c8a9a5SSteve French 	case UNIX_FIFO:
28838c8a9a5SSteve French 		fattr->cf_mode |= S_IFIFO;
28938c8a9a5SSteve French 		fattr->cf_dtype = DT_FIFO;
29038c8a9a5SSteve French 		break;
29138c8a9a5SSteve French 	case UNIX_SOCKET:
29238c8a9a5SSteve French 		fattr->cf_mode |= S_IFSOCK;
29338c8a9a5SSteve French 		fattr->cf_dtype = DT_SOCK;
29438c8a9a5SSteve French 		break;
29538c8a9a5SSteve French 	default:
29638c8a9a5SSteve French 		/* safest to call it a file if we do not know */
29738c8a9a5SSteve French 		fattr->cf_mode |= S_IFREG;
29838c8a9a5SSteve French 		fattr->cf_dtype = DT_REG;
29938c8a9a5SSteve French 		cifs_dbg(FYI, "unknown type %d\n", le32_to_cpu(info->Type));
30038c8a9a5SSteve French 		break;
30138c8a9a5SSteve French 	}
30238c8a9a5SSteve French 
30338c8a9a5SSteve French 	fattr->cf_uid = cifs_sb->ctx->linux_uid;
30438c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) {
30538c8a9a5SSteve French 		u64 id = le64_to_cpu(info->Uid);
30638c8a9a5SSteve French 		if (id < ((uid_t)-1)) {
30738c8a9a5SSteve French 			kuid_t uid = make_kuid(&init_user_ns, id);
30838c8a9a5SSteve French 			if (uid_valid(uid))
30938c8a9a5SSteve French 				fattr->cf_uid = uid;
31038c8a9a5SSteve French 		}
31138c8a9a5SSteve French 	}
31238c8a9a5SSteve French 
31338c8a9a5SSteve French 	fattr->cf_gid = cifs_sb->ctx->linux_gid;
31438c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
31538c8a9a5SSteve French 		u64 id = le64_to_cpu(info->Gid);
31638c8a9a5SSteve French 		if (id < ((gid_t)-1)) {
31738c8a9a5SSteve French 			kgid_t gid = make_kgid(&init_user_ns, id);
31838c8a9a5SSteve French 			if (gid_valid(gid))
31938c8a9a5SSteve French 				fattr->cf_gid = gid;
32038c8a9a5SSteve French 		}
32138c8a9a5SSteve French 	}
32238c8a9a5SSteve French 
32338c8a9a5SSteve French 	fattr->cf_nlink = le64_to_cpu(info->Nlinks);
32438c8a9a5SSteve French }
32538c8a9a5SSteve French 
32638c8a9a5SSteve French /*
32738c8a9a5SSteve French  * Fill a cifs_fattr struct with fake inode info.
32838c8a9a5SSteve French  *
32938c8a9a5SSteve French  * Needed to setup cifs_fattr data for the directory which is the
33038c8a9a5SSteve French  * junction to the new submount (ie to setup the fake directory
331a18280e7SPaulo Alcantara  * which represents a DFS referral or reparse mount point).
33238c8a9a5SSteve French  */
cifs_create_junction_fattr(struct cifs_fattr * fattr,struct super_block * sb)333a18280e7SPaulo Alcantara static void cifs_create_junction_fattr(struct cifs_fattr *fattr,
334a18280e7SPaulo Alcantara 				       struct super_block *sb)
33538c8a9a5SSteve French {
33638c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
33738c8a9a5SSteve French 
338a18280e7SPaulo Alcantara 	cifs_dbg(FYI, "%s: creating fake fattr\n", __func__);
33938c8a9a5SSteve French 
34038c8a9a5SSteve French 	memset(fattr, 0, sizeof(*fattr));
34138c8a9a5SSteve French 	fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
34238c8a9a5SSteve French 	fattr->cf_uid = cifs_sb->ctx->linux_uid;
34338c8a9a5SSteve French 	fattr->cf_gid = cifs_sb->ctx->linux_gid;
34438c8a9a5SSteve French 	ktime_get_coarse_real_ts64(&fattr->cf_mtime);
34538c8a9a5SSteve French 	fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
34638c8a9a5SSteve French 	fattr->cf_nlink = 2;
347a18280e7SPaulo Alcantara 	fattr->cf_flags = CIFS_FATTR_JUNCTION;
348a18280e7SPaulo Alcantara }
349a18280e7SPaulo Alcantara 
350a18280e7SPaulo Alcantara /* Update inode with final fattr data */
update_inode_info(struct super_block * sb,struct cifs_fattr * fattr,struct inode ** inode)351a18280e7SPaulo Alcantara static int update_inode_info(struct super_block *sb,
352a18280e7SPaulo Alcantara 			     struct cifs_fattr *fattr,
353a18280e7SPaulo Alcantara 			     struct inode **inode)
354a18280e7SPaulo Alcantara {
355a18280e7SPaulo Alcantara 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
356a18280e7SPaulo Alcantara 	int rc = 0;
357a18280e7SPaulo Alcantara 
358a18280e7SPaulo Alcantara 	if (!*inode) {
359a18280e7SPaulo Alcantara 		*inode = cifs_iget(sb, fattr);
360a18280e7SPaulo Alcantara 		if (!*inode)
361a18280e7SPaulo Alcantara 			rc = -ENOMEM;
362a18280e7SPaulo Alcantara 		return rc;
363a18280e7SPaulo Alcantara 	}
364a18280e7SPaulo Alcantara 	/* We already have inode, update it.
365a18280e7SPaulo Alcantara 	 *
366a18280e7SPaulo Alcantara 	 * If file type or uniqueid is different, return error.
367a18280e7SPaulo Alcantara 	 */
368a18280e7SPaulo Alcantara 	if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
369a18280e7SPaulo Alcantara 		     CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
370a18280e7SPaulo Alcantara 		CIFS_I(*inode)->time = 0; /* force reval */
371a18280e7SPaulo Alcantara 		return -ESTALE;
372a18280e7SPaulo Alcantara 	}
3739179aa27SBharath SM 	return cifs_fattr_to_inode(*inode, fattr, false);
37438c8a9a5SSteve French }
37538c8a9a5SSteve French 
37638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
37738c8a9a5SSteve French static int
cifs_get_file_info_unix(struct file * filp)37838c8a9a5SSteve French cifs_get_file_info_unix(struct file *filp)
37938c8a9a5SSteve French {
38038c8a9a5SSteve French 	int rc;
38138c8a9a5SSteve French 	unsigned int xid;
38238c8a9a5SSteve French 	FILE_UNIX_BASIC_INFO find_data;
38338c8a9a5SSteve French 	struct cifs_fattr fattr = {};
38438c8a9a5SSteve French 	struct inode *inode = file_inode(filp);
38538c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
38638c8a9a5SSteve French 	struct cifsFileInfo *cfile = filp->private_data;
38738c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
38838c8a9a5SSteve French 
38938c8a9a5SSteve French 	xid = get_xid();
39038c8a9a5SSteve French 
39138c8a9a5SSteve French 	if (cfile->symlink_target) {
39238c8a9a5SSteve French 		fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
39338c8a9a5SSteve French 		if (!fattr.cf_symlink_target) {
39438c8a9a5SSteve French 			rc = -ENOMEM;
39538c8a9a5SSteve French 			goto cifs_gfiunix_out;
39638c8a9a5SSteve French 		}
39738c8a9a5SSteve French 	}
39838c8a9a5SSteve French 
39938c8a9a5SSteve French 	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
40038c8a9a5SSteve French 	if (!rc) {
40138c8a9a5SSteve French 		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
40238c8a9a5SSteve French 	} else if (rc == -EREMOTE) {
403a18280e7SPaulo Alcantara 		cifs_create_junction_fattr(&fattr, inode->i_sb);
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 
cifs_get_unix_fattr(const unsigned char * full_path,struct super_block * sb,struct cifs_fattr * fattr,struct inode ** pinode,const unsigned int xid)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 
cifs_get_inode_info_unix(struct inode ** pinode,const unsigned char * full_path,struct super_block * sb,unsigned int xid)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
cifs_get_unix_fattr(const unsigned char * full_path,struct super_block * sb,struct cifs_fattr * fattr,struct inode ** pinode,const unsigned int xid)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 
cifs_get_inode_info_unix(struct inode ** pinode,const unsigned char * full_path,struct super_block * sb,unsigned int xid)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
cifs_sfu_type(struct cifs_fattr * fattr,const char * path,struct cifs_sb_info * cifs_sb,unsigned int xid)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  */
cifs_sfu_mode(struct cifs_fattr * fattr,const unsigned char * path,struct cifs_sb_info * cifs_sb,unsigned int xid)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 */
smb311_posix_info_to_fattr(struct cifs_fattr * fattr,struct cifs_open_info_data * data,struct super_block * sb)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 	}
724a90f37e3SSteve French 	sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
725a90f37e3SSteve 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 
cifs_open_info_to_fattr(struct cifs_fattr * fattr,struct cifs_open_info_data * data,struct super_block * sb)7318b4e285dSPaulo Alcantara static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
7328b4e285dSPaulo Alcantara 				    struct cifs_open_info_data *data,
7338b4e285dSPaulo Alcantara 				    struct super_block *sb)
73438c8a9a5SSteve French {
73538c8a9a5SSteve French 	struct smb2_file_all_info *info = &data->fi;
73638c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
73738c8a9a5SSteve French 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
73838c8a9a5SSteve French 
73938c8a9a5SSteve French 	memset(fattr, 0, sizeof(*fattr));
74038c8a9a5SSteve French 	fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
74138c8a9a5SSteve French 	if (info->DeletePending)
74238c8a9a5SSteve French 		fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
74338c8a9a5SSteve French 
74438c8a9a5SSteve French 	if (info->LastAccessTime)
74538c8a9a5SSteve French 		fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
74638c8a9a5SSteve French 	else
74738c8a9a5SSteve French 		ktime_get_coarse_real_ts64(&fattr->cf_atime);
74838c8a9a5SSteve French 
74938c8a9a5SSteve French 	fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
75038c8a9a5SSteve French 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
75138c8a9a5SSteve French 
7528b4e285dSPaulo Alcantara 	if (data->adjust_tz) {
75338c8a9a5SSteve French 		fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
75438c8a9a5SSteve French 		fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
75538c8a9a5SSteve French 	}
75638c8a9a5SSteve French 
75738c8a9a5SSteve French 	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
75838c8a9a5SSteve French 	fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
75938c8a9a5SSteve French 	fattr->cf_createtime = le64_to_cpu(info->CreationTime);
76038c8a9a5SSteve French 	fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
76197db4160SPaulo Alcantara 	fattr->cf_uid = cifs_sb->ctx->linux_uid;
76297db4160SPaulo Alcantara 	fattr->cf_gid = cifs_sb->ctx->linux_gid;
7635f71ebc4SPaulo Alcantara 
764304ff3c1SPaulo Alcantara 	fattr->cf_mode = cifs_sb->ctx->file_mode;
7655f71ebc4SPaulo Alcantara 	if (cifs_open_data_reparse(data) &&
766df32e887SPaulo Alcantara 	    cifs_reparse_point_to_fattr(cifs_sb, fattr, data))
7675f71ebc4SPaulo Alcantara 		goto out_reparse;
7685f71ebc4SPaulo Alcantara 
7695f71ebc4SPaulo Alcantara 	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
77038c8a9a5SSteve French 		fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
77138c8a9a5SSteve French 		fattr->cf_dtype = DT_DIR;
77238c8a9a5SSteve French 		/*
77338c8a9a5SSteve French 		 * Server can return wrong NumberOfLinks value for directories
77438c8a9a5SSteve French 		 * when Unix extensions are disabled - fake it.
77538c8a9a5SSteve French 		 */
77638c8a9a5SSteve French 		if (!tcon->unix_ext)
77738c8a9a5SSteve French 			fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
77838c8a9a5SSteve French 	} else {
77938c8a9a5SSteve French 		fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
78038c8a9a5SSteve French 		fattr->cf_dtype = DT_REG;
78138c8a9a5SSteve French 
78238c8a9a5SSteve French 		/* clear write bits if ATTR_READONLY is set */
78338c8a9a5SSteve French 		if (fattr->cf_cifsattrs & ATTR_READONLY)
78438c8a9a5SSteve French 			fattr->cf_mode &= ~(S_IWUGO);
78538c8a9a5SSteve French 
78638c8a9a5SSteve French 		/*
78738c8a9a5SSteve French 		 * Don't accept zero nlink from non-unix servers unless
78838c8a9a5SSteve French 		 * delete is pending.  Instead mark it as unknown.
78938c8a9a5SSteve French 		 */
79038c8a9a5SSteve French 		if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
79138c8a9a5SSteve French 		    !info->DeletePending) {
79238c8a9a5SSteve French 			cifs_dbg(VFS, "bogus file nlink value %u\n",
79338c8a9a5SSteve French 				 fattr->cf_nlink);
79438c8a9a5SSteve French 			fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
79538c8a9a5SSteve French 		}
79638c8a9a5SSteve French 	}
79738c8a9a5SSteve French 
7985f71ebc4SPaulo Alcantara out_reparse:
79938c8a9a5SSteve French 	if (S_ISLNK(fattr->cf_mode)) {
8001de3dbd9SPaulo Alcantara 		if (likely(data->symlink_target))
8011de3dbd9SPaulo Alcantara 			fattr->cf_eof = strnlen(data->symlink_target, PATH_MAX);
80238c8a9a5SSteve French 		fattr->cf_symlink_target = data->symlink_target;
80338c8a9a5SSteve French 		data->symlink_target = NULL;
80438c8a9a5SSteve French 	}
80538c8a9a5SSteve French }
80638c8a9a5SSteve French 
80738c8a9a5SSteve French static int
cifs_get_file_info(struct file * filp)80838c8a9a5SSteve French cifs_get_file_info(struct file *filp)
80938c8a9a5SSteve French {
81038c8a9a5SSteve French 	int rc;
81138c8a9a5SSteve French 	unsigned int xid;
81238c8a9a5SSteve French 	struct cifs_open_info_data data = {};
81338c8a9a5SSteve French 	struct cifs_fattr fattr;
81438c8a9a5SSteve French 	struct inode *inode = file_inode(filp);
81538c8a9a5SSteve French 	struct cifsFileInfo *cfile = filp->private_data;
81638c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
81738c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
818b6e27f7fSSteve French 	struct dentry *dentry = filp->f_path.dentry;
819b6e27f7fSSteve French 	void *page = alloc_dentry_path();
820b6e27f7fSSteve French 	const unsigned char *path;
82138c8a9a5SSteve French 
8221598a015SMeetakshi Setiya 	if (!server->ops->query_file_info) {
8231598a015SMeetakshi Setiya 		free_dentry_path(page);
82438c8a9a5SSteve French 		return -ENOSYS;
8251598a015SMeetakshi Setiya 	}
82638c8a9a5SSteve French 
82738c8a9a5SSteve French 	xid = get_xid();
82838c8a9a5SSteve French 	rc = server->ops->query_file_info(xid, tcon, cfile, &data);
82938c8a9a5SSteve French 	switch (rc) {
83038c8a9a5SSteve French 	case 0:
83138c8a9a5SSteve French 		/* TODO: add support to query reparse tag */
8328b4e285dSPaulo Alcantara 		data.adjust_tz = false;
83338c8a9a5SSteve French 		if (data.symlink_target) {
8348b4e285dSPaulo Alcantara 			data.symlink = true;
835df32e887SPaulo Alcantara 			data.reparse.tag = IO_REPARSE_TAG_SYMLINK;
83638c8a9a5SSteve French 		}
837b6e27f7fSSteve French 		path = build_path_from_dentry(dentry, page);
838b6e27f7fSSteve French 		if (IS_ERR(path)) {
8391598a015SMeetakshi Setiya 			rc = PTR_ERR(path);
8401598a015SMeetakshi Setiya 			goto cgfi_exit;
841b6e27f7fSSteve French 		}
8428b4e285dSPaulo Alcantara 		cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
843b6e27f7fSSteve French 		if (fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
844b6e27f7fSSteve French 			cifs_mark_open_handles_for_deleted_file(inode, path);
84538c8a9a5SSteve French 		break;
84638c8a9a5SSteve French 	case -EREMOTE:
847a18280e7SPaulo Alcantara 		cifs_create_junction_fattr(&fattr, inode->i_sb);
84838c8a9a5SSteve French 		break;
84938c8a9a5SSteve French 	case -EOPNOTSUPP:
85038c8a9a5SSteve French 	case -EINVAL:
85138c8a9a5SSteve French 		/*
85238c8a9a5SSteve French 		 * FIXME: legacy server -- fall back to path-based call?
85338c8a9a5SSteve French 		 * for now, just skip revalidating and mark inode for
85438c8a9a5SSteve French 		 * immediate reval.
85538c8a9a5SSteve French 		 */
85638c8a9a5SSteve French 		rc = 0;
85738c8a9a5SSteve French 		CIFS_I(inode)->time = 0;
85838c8a9a5SSteve French 		goto cgfi_exit;
85938c8a9a5SSteve French 	default:
86038c8a9a5SSteve French 		goto cgfi_exit;
86138c8a9a5SSteve French 	}
86238c8a9a5SSteve French 
86338c8a9a5SSteve French 	/*
86438c8a9a5SSteve French 	 * don't bother with SFU junk here -- just mark inode as needing
86538c8a9a5SSteve French 	 * revalidation.
86638c8a9a5SSteve French 	 */
86738c8a9a5SSteve French 	fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
86838c8a9a5SSteve French 	fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
86938c8a9a5SSteve French 	/* if filetype is different, return error */
8709179aa27SBharath SM 	rc = cifs_fattr_to_inode(inode, &fattr, false);
87138c8a9a5SSteve French cgfi_exit:
87238c8a9a5SSteve French 	cifs_free_open_info(&data);
873b6e27f7fSSteve French 	free_dentry_path(page);
87438c8a9a5SSteve French 	free_xid(xid);
87538c8a9a5SSteve French 	return rc;
87638c8a9a5SSteve French }
87738c8a9a5SSteve French 
87838c8a9a5SSteve French /* Simple function to return a 64 bit hash of string.  Rarely called */
simple_hashstr(const char * str)87938c8a9a5SSteve French static __u64 simple_hashstr(const char *str)
88038c8a9a5SSteve French {
88138c8a9a5SSteve French 	const __u64 hash_mult =  1125899906842597ULL; /* a big enough prime */
88238c8a9a5SSteve French 	__u64 hash = 0;
88338c8a9a5SSteve French 
88438c8a9a5SSteve French 	while (*str)
88538c8a9a5SSteve French 		hash = (hash + (__u64) *str++) * hash_mult;
88638c8a9a5SSteve French 
88738c8a9a5SSteve French 	return hash;
88838c8a9a5SSteve French }
88938c8a9a5SSteve French 
89038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
89138c8a9a5SSteve French /**
89238c8a9a5SSteve French  * cifs_backup_query_path_info - SMB1 fallback code to get ino
89338c8a9a5SSteve French  *
89438c8a9a5SSteve French  * Fallback code to get file metadata when we don't have access to
89538c8a9a5SSteve French  * full_path (EACCES) and have backup creds.
89638c8a9a5SSteve French  *
89738c8a9a5SSteve French  * @xid:	transaction id used to identify original request in logs
89838c8a9a5SSteve French  * @tcon:	information about the server share we have mounted
89938c8a9a5SSteve French  * @sb:	the superblock stores info such as disk space available
90038c8a9a5SSteve French  * @full_path:	name of the file we are getting the metadata for
90138c8a9a5SSteve French  * @resp_buf:	will be set to cifs resp buf and needs to be freed with
90238c8a9a5SSteve French  * 		cifs_buf_release() when done with @data
90338c8a9a5SSteve French  * @data:	will be set to search info result buffer
90438c8a9a5SSteve French  */
90538c8a9a5SSteve French static int
cifs_backup_query_path_info(int xid,struct cifs_tcon * tcon,struct super_block * sb,const char * full_path,void ** resp_buf,FILE_ALL_INFO ** data)90638c8a9a5SSteve French cifs_backup_query_path_info(int xid,
90738c8a9a5SSteve French 			    struct cifs_tcon *tcon,
90838c8a9a5SSteve French 			    struct super_block *sb,
90938c8a9a5SSteve French 			    const char *full_path,
91038c8a9a5SSteve French 			    void **resp_buf,
91138c8a9a5SSteve French 			    FILE_ALL_INFO **data)
91238c8a9a5SSteve French {
91338c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
91438c8a9a5SSteve French 	struct cifs_search_info info = {0};
91538c8a9a5SSteve French 	u16 flags;
91638c8a9a5SSteve French 	int rc;
91738c8a9a5SSteve French 
91838c8a9a5SSteve French 	*resp_buf = NULL;
91938c8a9a5SSteve French 	info.endOfSearch = false;
92038c8a9a5SSteve French 	if (tcon->unix_ext)
92138c8a9a5SSteve French 		info.info_level = SMB_FIND_FILE_UNIX;
92238c8a9a5SSteve French 	else if ((tcon->ses->capabilities &
92338c8a9a5SSteve French 		  tcon->ses->server->vals->cap_nt_find) == 0)
92438c8a9a5SSteve French 		info.info_level = SMB_FIND_FILE_INFO_STANDARD;
92538c8a9a5SSteve French 	else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
92638c8a9a5SSteve French 		info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
92738c8a9a5SSteve French 	else /* no srvino useful for fallback to some netapp */
92838c8a9a5SSteve French 		info.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
92938c8a9a5SSteve French 
93038c8a9a5SSteve French 	flags = CIFS_SEARCH_CLOSE_ALWAYS |
93138c8a9a5SSteve French 		CIFS_SEARCH_CLOSE_AT_END |
93238c8a9a5SSteve French 		CIFS_SEARCH_BACKUP_SEARCH;
93338c8a9a5SSteve French 
93438c8a9a5SSteve French 	rc = CIFSFindFirst(xid, tcon, full_path,
93538c8a9a5SSteve French 			   cifs_sb, NULL, flags, &info, false);
93638c8a9a5SSteve French 	if (rc)
93738c8a9a5SSteve French 		return rc;
93838c8a9a5SSteve French 
93938c8a9a5SSteve French 	*resp_buf = (void *)info.ntwrk_buf_start;
94038c8a9a5SSteve French 	*data = (FILE_ALL_INFO *)info.srch_entries_start;
94138c8a9a5SSteve French 	return 0;
94238c8a9a5SSteve French }
94338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
94438c8a9a5SSteve French 
cifs_set_fattr_ino(int xid,struct cifs_tcon * tcon,struct super_block * sb,struct inode ** inode,const char * full_path,struct cifs_open_info_data * data,struct cifs_fattr * fattr)94538c8a9a5SSteve French static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_block *sb,
94638c8a9a5SSteve French 			       struct inode **inode, const char *full_path,
94738c8a9a5SSteve French 			       struct cifs_open_info_data *data, struct cifs_fattr *fattr)
94838c8a9a5SSteve French {
94938c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
95038c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
95138c8a9a5SSteve French 	int rc;
95238c8a9a5SSteve French 
95338c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
95438c8a9a5SSteve French 		if (*inode)
95538c8a9a5SSteve French 			fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
95638c8a9a5SSteve French 		else
95738c8a9a5SSteve French 			fattr->cf_uniqueid = iunique(sb, ROOT_I);
95838c8a9a5SSteve French 		return;
95938c8a9a5SSteve French 	}
96038c8a9a5SSteve French 
96138c8a9a5SSteve French 	/*
96238c8a9a5SSteve French 	 * If we have an inode pass a NULL tcon to ensure we don't
96338c8a9a5SSteve French 	 * make a round trip to the server. This only works for SMB2+.
96438c8a9a5SSteve French 	 */
96538c8a9a5SSteve French 	rc = server->ops->get_srv_inum(xid, *inode ? NULL : tcon, cifs_sb, full_path,
96638c8a9a5SSteve French 				       &fattr->cf_uniqueid, data);
96738c8a9a5SSteve French 	if (rc) {
96838c8a9a5SSteve French 		/*
96938c8a9a5SSteve French 		 * If that fails reuse existing ino or generate one
97038c8a9a5SSteve French 		 * and disable server ones
97138c8a9a5SSteve French 		 */
97238c8a9a5SSteve French 		if (*inode)
97338c8a9a5SSteve French 			fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
97438c8a9a5SSteve French 		else {
97538c8a9a5SSteve French 			fattr->cf_uniqueid = iunique(sb, ROOT_I);
97638c8a9a5SSteve French 			cifs_autodisable_serverino(cifs_sb);
97738c8a9a5SSteve French 		}
97838c8a9a5SSteve French 		return;
97938c8a9a5SSteve French 	}
98038c8a9a5SSteve French 
98138c8a9a5SSteve French 	/* If no errors, check for zero root inode (invalid) */
98238c8a9a5SSteve French 	if (fattr->cf_uniqueid == 0 && strlen(full_path) == 0) {
98338c8a9a5SSteve French 		cifs_dbg(FYI, "Invalid (0) inodenum\n");
98438c8a9a5SSteve French 		if (*inode) {
98538c8a9a5SSteve French 			/* reuse */
98638c8a9a5SSteve French 			fattr->cf_uniqueid = CIFS_I(*inode)->uniqueid;
98738c8a9a5SSteve French 		} else {
98838c8a9a5SSteve French 			/* make an ino by hashing the UNC */
98938c8a9a5SSteve French 			fattr->cf_flags |= CIFS_FATTR_FAKE_ROOT_INO;
99038c8a9a5SSteve French 			fattr->cf_uniqueid = simple_hashstr(tcon->tree_name);
99138c8a9a5SSteve French 		}
99238c8a9a5SSteve French 	}
99338c8a9a5SSteve French }
99438c8a9a5SSteve French 
is_inode_cache_good(struct inode * ino)99538c8a9a5SSteve French static inline bool is_inode_cache_good(struct inode *ino)
99638c8a9a5SSteve French {
99738c8a9a5SSteve French 	return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
99838c8a9a5SSteve French }
99938c8a9a5SSteve French 
reparse_info_to_fattr(struct cifs_open_info_data * data,struct super_block * sb,const unsigned int xid,struct cifs_tcon * tcon,const char * full_path,struct cifs_fattr * fattr)1000a18280e7SPaulo Alcantara static int reparse_info_to_fattr(struct cifs_open_info_data *data,
10015f71ebc4SPaulo Alcantara 				 struct super_block *sb,
10025f71ebc4SPaulo Alcantara 				 const unsigned int xid,
10035f71ebc4SPaulo Alcantara 				 struct cifs_tcon *tcon,
10045f71ebc4SPaulo Alcantara 				 const char *full_path,
1005a90f37e3SSteve French 				 struct cifs_fattr *fattr)
100638c8a9a5SSteve French {
10075f71ebc4SPaulo Alcantara 	struct TCP_Server_Info *server = tcon->ses->server;
10085f71ebc4SPaulo Alcantara 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
10099a49e221SPaulo Alcantara 	struct kvec rsp_iov, *iov = NULL;
10109a49e221SPaulo Alcantara 	int rsp_buftype = CIFS_NO_BUFFER;
1011df32e887SPaulo Alcantara 	u32 tag = data->reparse.tag;
10125f71ebc4SPaulo Alcantara 	int rc = 0;
10135f71ebc4SPaulo Alcantara 
10149a49e221SPaulo Alcantara 	if (!tag && server->ops->query_reparse_point) {
10159a49e221SPaulo Alcantara 		rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
10169a49e221SPaulo Alcantara 						      full_path, &tag,
10179a49e221SPaulo Alcantara 						      &rsp_iov, &rsp_buftype);
10189a49e221SPaulo Alcantara 		if (!rc)
10199a49e221SPaulo Alcantara 			iov = &rsp_iov;
1020a158bb66SSteve French 	} else if (data->reparse.io.buftype != CIFS_NO_BUFFER &&
1021a158bb66SSteve French 		   data->reparse.io.iov.iov_base) {
1022a158bb66SSteve French 		iov = &data->reparse.io.iov;
10235f71ebc4SPaulo Alcantara 	}
10244d07e5dfSPaulo Alcantara 
10254d07e5dfSPaulo Alcantara 	rc = -EOPNOTSUPP;
1026df32e887SPaulo Alcantara 	switch ((data->reparse.tag = tag)) {
10275f71ebc4SPaulo Alcantara 	case 0: /* SMB1 symlink */
10284d07e5dfSPaulo Alcantara 		if (server->ops->query_symlink) {
10295f71ebc4SPaulo Alcantara 			rc = server->ops->query_symlink(xid, tcon,
10305f71ebc4SPaulo Alcantara 							cifs_sb, full_path,
10314d07e5dfSPaulo Alcantara 							&data->symlink_target);
10325f71ebc4SPaulo Alcantara 		}
10335f71ebc4SPaulo Alcantara 		break;
1034a18280e7SPaulo Alcantara 	case IO_REPARSE_TAG_MOUNT_POINT:
1035a18280e7SPaulo Alcantara 		cifs_create_junction_fattr(fattr, sb);
10364d07e5dfSPaulo Alcantara 		rc = 0;
1037a18280e7SPaulo Alcantara 		goto out;
10384d07e5dfSPaulo Alcantara 	default:
103902bcf865SSteve French 		/* Check for cached reparse point data */
104002bcf865SSteve French 		if (data->symlink_target || data->reparse.buf) {
10414d07e5dfSPaulo Alcantara 			rc = 0;
1042a158bb66SSteve French 		} else if (iov && server->ops->parse_reparse_point) {
10434d07e5dfSPaulo Alcantara 			rc = server->ops->parse_reparse_point(cifs_sb,
10444d07e5dfSPaulo Alcantara 							      iov, data);
10454d07e5dfSPaulo Alcantara 		}
10464d07e5dfSPaulo Alcantara 		break;
10475f71ebc4SPaulo Alcantara 	}
1048a18280e7SPaulo Alcantara 
104902bcf865SSteve French 	if (tcon->posix_extensions)
1050a90f37e3SSteve French 		smb311_posix_info_to_fattr(fattr, data, sb);
10511598a015SMeetakshi Setiya 	else
1052a18280e7SPaulo Alcantara 		cifs_open_info_to_fattr(fattr, data, sb);
1053a18280e7SPaulo Alcantara out:
1054b9e741acSPaulo Alcantara 	fattr->cf_cifstag = data->reparse.tag;
10559a49e221SPaulo Alcantara 	free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
10565f71ebc4SPaulo Alcantara 	return rc;
10575f71ebc4SPaulo Alcantara }
10585f71ebc4SPaulo Alcantara 
cifs_get_fattr(struct cifs_open_info_data * data,struct super_block * sb,int xid,const struct cifs_fid * fid,struct cifs_fattr * fattr,struct inode ** inode,const char * full_path)1059a18280e7SPaulo Alcantara static int cifs_get_fattr(struct cifs_open_info_data *data,
1060a18280e7SPaulo Alcantara 			  struct super_block *sb, int xid,
1061a18280e7SPaulo Alcantara 			  const struct cifs_fid *fid,
1062a18280e7SPaulo Alcantara 			  struct cifs_fattr *fattr,
1063a18280e7SPaulo Alcantara 			  struct inode **inode,
1064a18280e7SPaulo Alcantara 			  const char *full_path)
106538c8a9a5SSteve French {
1066a18280e7SPaulo Alcantara 	struct cifs_open_info_data tmp_data = {};
106738c8a9a5SSteve French 	struct cifs_tcon *tcon;
106838c8a9a5SSteve French 	struct TCP_Server_Info *server;
106938c8a9a5SSteve French 	struct tcon_link *tlink;
107038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
107138c8a9a5SSteve French 	void *smb1_backup_rsp_buf = NULL;
107238c8a9a5SSteve French 	int rc = 0;
107338c8a9a5SSteve French 	int tmprc = 0;
107438c8a9a5SSteve French 
107538c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
107638c8a9a5SSteve French 	if (IS_ERR(tlink))
107738c8a9a5SSteve French 		return PTR_ERR(tlink);
107838c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
107938c8a9a5SSteve French 	server = tcon->ses->server;
108038c8a9a5SSteve French 
108138c8a9a5SSteve French 	/*
108238c8a9a5SSteve French 	 * 1. Fetch file metadata if not provided (data)
108338c8a9a5SSteve French 	 */
108438c8a9a5SSteve French 
108538c8a9a5SSteve French 	if (!data) {
10868b4e285dSPaulo Alcantara 		rc = server->ops->query_path_info(xid, tcon, cifs_sb,
10878b4e285dSPaulo Alcantara 						  full_path, &tmp_data);
108838c8a9a5SSteve French 		data = &tmp_data;
108938c8a9a5SSteve French 	}
109038c8a9a5SSteve French 
109138c8a9a5SSteve French 	/*
109238c8a9a5SSteve French 	 * 2. Convert it to internal cifs metadata (fattr)
109338c8a9a5SSteve French 	 */
109438c8a9a5SSteve French 
109538c8a9a5SSteve French 	switch (rc) {
109638c8a9a5SSteve French 	case 0:
109738c8a9a5SSteve French 		/*
109838c8a9a5SSteve French 		 * If the file is a reparse point, it is more complicated
109938c8a9a5SSteve French 		 * since we have to check if its reparse tag matches a known
110038c8a9a5SSteve French 		 * special file type e.g. symlink or fifo or char etc.
110138c8a9a5SSteve French 		 */
11025f71ebc4SPaulo Alcantara 		if (cifs_open_data_reparse(data)) {
1103a18280e7SPaulo Alcantara 			rc = reparse_info_to_fattr(data, sb, xid, tcon,
1104a90f37e3SSteve French 						   full_path, fattr);
1105a18280e7SPaulo Alcantara 		} else {
1106a18280e7SPaulo Alcantara 			cifs_open_info_to_fattr(fattr, data, sb);
110738c8a9a5SSteve French 		}
110801bce099SPaulo Alcantara 		if (!rc && *inode &&
110901bce099SPaulo Alcantara 		    (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING))
11101598a015SMeetakshi Setiya 			cifs_mark_open_handles_for_deleted_file(*inode, full_path);
111138c8a9a5SSteve French 		break;
111238c8a9a5SSteve French 	case -EREMOTE:
111338c8a9a5SSteve French 		/* DFS link, no metadata available on this server */
1114a18280e7SPaulo Alcantara 		cifs_create_junction_fattr(fattr, sb);
111538c8a9a5SSteve French 		rc = 0;
111638c8a9a5SSteve French 		break;
111738c8a9a5SSteve French 	case -EACCES:
111838c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
111938c8a9a5SSteve French 		/*
112038c8a9a5SSteve French 		 * perm errors, try again with backup flags if possible
112138c8a9a5SSteve French 		 *
112238c8a9a5SSteve French 		 * For SMB2 and later the backup intent flag
112338c8a9a5SSteve French 		 * is already sent if needed on open and there
112438c8a9a5SSteve French 		 * is no path based FindFirst operation to use
112538c8a9a5SSteve French 		 * to retry with
112638c8a9a5SSteve French 		 */
112738c8a9a5SSteve French 		if (backup_cred(cifs_sb) && is_smb1_server(server)) {
112838c8a9a5SSteve French 			/* for easier reading */
112938c8a9a5SSteve French 			FILE_ALL_INFO *fi;
113038c8a9a5SSteve French 			FILE_DIRECTORY_INFO *fdi;
113138c8a9a5SSteve French 			SEARCH_ID_FULL_DIR_INFO *si;
113238c8a9a5SSteve French 
113338c8a9a5SSteve French 			rc = cifs_backup_query_path_info(xid, tcon, sb,
113438c8a9a5SSteve French 							 full_path,
113538c8a9a5SSteve French 							 &smb1_backup_rsp_buf,
113638c8a9a5SSteve French 							 &fi);
113738c8a9a5SSteve French 			if (rc)
113838c8a9a5SSteve French 				goto out;
113938c8a9a5SSteve French 
114038c8a9a5SSteve French 			move_cifs_info_to_smb2(&data->fi, fi);
114138c8a9a5SSteve French 			fdi = (FILE_DIRECTORY_INFO *)fi;
114238c8a9a5SSteve French 			si = (SEARCH_ID_FULL_DIR_INFO *)fi;
114338c8a9a5SSteve French 
1144a18280e7SPaulo Alcantara 			cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
1145a18280e7SPaulo Alcantara 			fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
114638c8a9a5SSteve French 			/* uniqueid set, skip get inum step */
114738c8a9a5SSteve French 			goto handle_mnt_opt;
114838c8a9a5SSteve French 		} else {
114938c8a9a5SSteve French 			/* nothing we can do, bail out */
115038c8a9a5SSteve French 			goto out;
115138c8a9a5SSteve French 		}
115238c8a9a5SSteve French #else
115338c8a9a5SSteve French 		goto out;
115438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
115538c8a9a5SSteve French 		break;
115638c8a9a5SSteve French 	default:
115738c8a9a5SSteve French 		cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc);
115838c8a9a5SSteve French 		goto out;
115938c8a9a5SSteve French 	}
116038c8a9a5SSteve French 
116138c8a9a5SSteve French 	/*
1162a18280e7SPaulo Alcantara 	 * 3. Get or update inode number (fattr->cf_uniqueid)
116338c8a9a5SSteve French 	 */
116438c8a9a5SSteve French 
1165a18280e7SPaulo Alcantara 	cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr);
116638c8a9a5SSteve French 
116738c8a9a5SSteve French 	/*
116838c8a9a5SSteve French 	 * 4. Tweak fattr based on mount options
116938c8a9a5SSteve French 	 */
117038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
117138c8a9a5SSteve French handle_mnt_opt:
117238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
117338c8a9a5SSteve French 	/* query for SFU type info if supported and needed */
1174a18280e7SPaulo Alcantara 	if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
1175a18280e7SPaulo Alcantara 	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
1176a18280e7SPaulo Alcantara 		tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
117738c8a9a5SSteve French 		if (tmprc)
117838c8a9a5SSteve French 			cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
117938c8a9a5SSteve French 	}
118038c8a9a5SSteve French 
118138c8a9a5SSteve French 	/* fill in 0777 bits from ACL */
118238c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
1183a18280e7SPaulo Alcantara 		rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
1184a18280e7SPaulo Alcantara 				       true, full_path, fid);
118538c8a9a5SSteve French 		if (rc == -EREMOTE)
118638c8a9a5SSteve French 			rc = 0;
118738c8a9a5SSteve French 		if (rc) {
118838c8a9a5SSteve French 			cifs_dbg(FYI, "%s: Get mode from SID failed. rc=%d\n",
118938c8a9a5SSteve French 				 __func__, rc);
119038c8a9a5SSteve French 			goto out;
119138c8a9a5SSteve French 		}
119238c8a9a5SSteve French 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
1193a18280e7SPaulo Alcantara 		rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
1194a18280e7SPaulo Alcantara 				       false, full_path, fid);
119538c8a9a5SSteve French 		if (rc == -EREMOTE)
119638c8a9a5SSteve French 			rc = 0;
119738c8a9a5SSteve French 		if (rc) {
119838c8a9a5SSteve French 			cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
119938c8a9a5SSteve French 				 __func__, rc);
120038c8a9a5SSteve French 			goto out;
120138c8a9a5SSteve French 		}
120238c8a9a5SSteve French 	}
120338c8a9a5SSteve French 
120438c8a9a5SSteve French 	/* fill in remaining high mode bits e.g. SUID, VTX */
120538c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
1206a18280e7SPaulo Alcantara 		cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
120738c8a9a5SSteve French 
120838c8a9a5SSteve French 	/* check for Minshall+French symlinks */
120938c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
1210a18280e7SPaulo Alcantara 		tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
121138c8a9a5SSteve French 		cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
121238c8a9a5SSteve French 	}
121338c8a9a5SSteve French 
121438c8a9a5SSteve French out:
121538c8a9a5SSteve French 	cifs_buf_release(smb1_backup_rsp_buf);
121638c8a9a5SSteve French 	cifs_put_tlink(tlink);
121738c8a9a5SSteve French 	cifs_free_open_info(&tmp_data);
1218a18280e7SPaulo Alcantara 	return rc;
1219a18280e7SPaulo Alcantara }
1220a18280e7SPaulo Alcantara 
cifs_get_inode_info(struct inode ** inode,const char * full_path,struct cifs_open_info_data * data,struct super_block * sb,int xid,const struct cifs_fid * fid)1221a18280e7SPaulo Alcantara int cifs_get_inode_info(struct inode **inode,
1222a18280e7SPaulo Alcantara 			const char *full_path,
1223a18280e7SPaulo Alcantara 			struct cifs_open_info_data *data,
1224a18280e7SPaulo Alcantara 			struct super_block *sb, int xid,
1225a18280e7SPaulo Alcantara 			const struct cifs_fid *fid)
1226a18280e7SPaulo Alcantara {
1227a18280e7SPaulo Alcantara 	struct cifs_fattr fattr = {};
1228a18280e7SPaulo Alcantara 	int rc;
1229a18280e7SPaulo Alcantara 
1230a18280e7SPaulo Alcantara 	if (is_inode_cache_good(*inode)) {
1231a18280e7SPaulo Alcantara 		cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1232a18280e7SPaulo Alcantara 		return 0;
1233a18280e7SPaulo Alcantara 	}
1234a18280e7SPaulo Alcantara 
1235a18280e7SPaulo Alcantara 	rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path);
1236a18280e7SPaulo Alcantara 	if (rc)
1237a18280e7SPaulo Alcantara 		goto out;
1238a18280e7SPaulo Alcantara 
1239a18280e7SPaulo Alcantara 	rc = update_inode_info(sb, &fattr, inode);
1240a18280e7SPaulo Alcantara out:
124138c8a9a5SSteve French 	kfree(fattr.cf_symlink_target);
124238c8a9a5SSteve French 	return rc;
124338c8a9a5SSteve French }
124438c8a9a5SSteve French 
smb311_posix_get_fattr(struct cifs_open_info_data * data,struct cifs_fattr * fattr,const char * full_path,struct super_block * sb,const unsigned int xid)124502bcf865SSteve French static int smb311_posix_get_fattr(struct cifs_open_info_data *data,
124602bcf865SSteve French 				  struct cifs_fattr *fattr,
124738c8a9a5SSteve French 				  const char *full_path,
1248a18280e7SPaulo Alcantara 				  struct super_block *sb,
1249a18280e7SPaulo Alcantara 				  const unsigned int xid)
125038c8a9a5SSteve French {
125102bcf865SSteve French 	struct cifs_open_info_data tmp_data = {};
1252cfb8f73dSPaulo Alcantara 	struct TCP_Server_Info *server;
1253a18280e7SPaulo Alcantara 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
125438c8a9a5SSteve French 	struct cifs_tcon *tcon;
125538c8a9a5SSteve French 	struct tcon_link *tlink;
1256a18280e7SPaulo Alcantara 	int tmprc;
125702bcf865SSteve French 	int rc = 0;
125838c8a9a5SSteve French 
125938c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
126038c8a9a5SSteve French 	if (IS_ERR(tlink))
126138c8a9a5SSteve French 		return PTR_ERR(tlink);
126238c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
1263cfb8f73dSPaulo Alcantara 	server = tcon->ses->server;
126438c8a9a5SSteve French 
126538c8a9a5SSteve French 	/*
126602bcf865SSteve French 	 * 1. Fetch file metadata if not provided (data)
126738c8a9a5SSteve French 	 */
126802bcf865SSteve French 	if (!data) {
1269cfb8f73dSPaulo Alcantara 		rc = server->ops->query_path_info(xid, tcon, cifs_sb,
1270a90f37e3SSteve French 						  full_path, &tmp_data);
127102bcf865SSteve French 		data = &tmp_data;
127202bcf865SSteve French 	}
127338c8a9a5SSteve French 
127438c8a9a5SSteve French 	/*
127538c8a9a5SSteve French 	 * 2. Convert it to internal cifs metadata (fattr)
127638c8a9a5SSteve French 	 */
127738c8a9a5SSteve French 
127838c8a9a5SSteve French 	switch (rc) {
127938c8a9a5SSteve French 	case 0:
128002bcf865SSteve French 		if (cifs_open_data_reparse(data)) {
128102bcf865SSteve French 			rc = reparse_info_to_fattr(data, sb, xid, tcon,
1282a90f37e3SSteve French 						   full_path, fattr);
128302bcf865SSteve French 		} else {
1284a90f37e3SSteve French 			smb311_posix_info_to_fattr(fattr, data, sb);
128502bcf865SSteve French 		}
128638c8a9a5SSteve French 		break;
128738c8a9a5SSteve French 	case -EREMOTE:
128838c8a9a5SSteve French 		/* DFS link, no metadata available on this server */
1289a18280e7SPaulo Alcantara 		cifs_create_junction_fattr(fattr, sb);
129038c8a9a5SSteve French 		rc = 0;
129138c8a9a5SSteve French 		break;
129238c8a9a5SSteve French 	case -EACCES:
129338c8a9a5SSteve French 		/*
129438c8a9a5SSteve French 		 * For SMB2 and later the backup intent flag
129538c8a9a5SSteve French 		 * is already sent if needed on open and there
129638c8a9a5SSteve French 		 * is no path based FindFirst operation to use
129738c8a9a5SSteve French 		 * to retry with so nothing we can do, bail out
129838c8a9a5SSteve French 		 */
129938c8a9a5SSteve French 		goto out;
130038c8a9a5SSteve French 	default:
130138c8a9a5SSteve French 		cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc);
130238c8a9a5SSteve French 		goto out;
130338c8a9a5SSteve French 	}
130438c8a9a5SSteve French 
130538c8a9a5SSteve French 	/*
130638c8a9a5SSteve French 	 * 3. Tweak fattr based on mount options
130738c8a9a5SSteve French 	 */
130838c8a9a5SSteve French 	/* check for Minshall+French symlinks */
130938c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
1310a18280e7SPaulo Alcantara 		tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
131138c8a9a5SSteve French 		cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
131238c8a9a5SSteve French 	}
131338c8a9a5SSteve French 
131438c8a9a5SSteve French out:
131538c8a9a5SSteve French 	cifs_put_tlink(tlink);
131602bcf865SSteve French 	cifs_free_open_info(data);
131738c8a9a5SSteve French 	return rc;
131838c8a9a5SSteve French }
131938c8a9a5SSteve French 
smb311_posix_get_inode_info(struct inode ** inode,const char * full_path,struct cifs_open_info_data * data,struct super_block * sb,const unsigned int xid)132002bcf865SSteve French int smb311_posix_get_inode_info(struct inode **inode,
132102bcf865SSteve French 				const char *full_path,
132202bcf865SSteve French 				struct cifs_open_info_data *data,
132302bcf865SSteve French 				struct super_block *sb,
132402bcf865SSteve French 				const unsigned int xid)
1325a18280e7SPaulo Alcantara {
1326a18280e7SPaulo Alcantara 	struct cifs_fattr fattr = {};
1327a18280e7SPaulo Alcantara 	int rc;
1328a18280e7SPaulo Alcantara 
1329a18280e7SPaulo Alcantara 	if (is_inode_cache_good(*inode)) {
1330a18280e7SPaulo Alcantara 		cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1331a18280e7SPaulo Alcantara 		return 0;
1332a18280e7SPaulo Alcantara 	}
1333a18280e7SPaulo Alcantara 
133402bcf865SSteve French 	rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid);
1335a18280e7SPaulo Alcantara 	if (rc)
1336a18280e7SPaulo Alcantara 		goto out;
1337a18280e7SPaulo Alcantara 
1338a18280e7SPaulo Alcantara 	rc = update_inode_info(sb, &fattr, inode);
13391598a015SMeetakshi Setiya 	if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
13401598a015SMeetakshi Setiya 		cifs_mark_open_handles_for_deleted_file(*inode, full_path);
1341a18280e7SPaulo Alcantara out:
1342a18280e7SPaulo Alcantara 	kfree(fattr.cf_symlink_target);
1343a18280e7SPaulo Alcantara 	return rc;
1344a18280e7SPaulo Alcantara }
134538c8a9a5SSteve French 
134638c8a9a5SSteve French static const struct inode_operations cifs_ipc_inode_ops = {
134738c8a9a5SSteve French 	.lookup = cifs_lookup,
134838c8a9a5SSteve French };
134938c8a9a5SSteve French 
135038c8a9a5SSteve French static int
cifs_find_inode(struct inode * inode,void * opaque)135138c8a9a5SSteve French cifs_find_inode(struct inode *inode, void *opaque)
135238c8a9a5SSteve French {
135338c8a9a5SSteve French 	struct cifs_fattr *fattr = opaque;
135438c8a9a5SSteve French 
1355614bc8c7SDavid Howells 	/* [!] The compared values must be the same in struct cifs_fscache_inode_key. */
1356614bc8c7SDavid Howells 
135738c8a9a5SSteve French 	/* don't match inode with different uniqueid */
135838c8a9a5SSteve French 	if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
135938c8a9a5SSteve French 		return 0;
136038c8a9a5SSteve French 
136138c8a9a5SSteve French 	/* use createtime like an i_generation field */
136238c8a9a5SSteve French 	if (CIFS_I(inode)->createtime != fattr->cf_createtime)
136338c8a9a5SSteve French 		return 0;
136438c8a9a5SSteve French 
136538c8a9a5SSteve French 	/* don't match inode of different type */
136638c8a9a5SSteve French 	if (inode_wrong_type(inode, fattr->cf_mode))
136738c8a9a5SSteve French 		return 0;
136838c8a9a5SSteve French 
136938c8a9a5SSteve French 	/* if it's not a directory or has no dentries, then flag it */
137038c8a9a5SSteve French 	if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
137138c8a9a5SSteve French 		fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
137238c8a9a5SSteve French 
137338c8a9a5SSteve French 	return 1;
137438c8a9a5SSteve French }
137538c8a9a5SSteve French 
137638c8a9a5SSteve French static int
cifs_init_inode(struct inode * inode,void * opaque)137738c8a9a5SSteve French cifs_init_inode(struct inode *inode, void *opaque)
137838c8a9a5SSteve French {
137938c8a9a5SSteve French 	struct cifs_fattr *fattr = opaque;
138038c8a9a5SSteve French 
138138c8a9a5SSteve French 	CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
138238c8a9a5SSteve French 	CIFS_I(inode)->createtime = fattr->cf_createtime;
138338c8a9a5SSteve French 	return 0;
138438c8a9a5SSteve French }
138538c8a9a5SSteve French 
138638c8a9a5SSteve French /*
138738c8a9a5SSteve French  * walk dentry list for an inode and report whether it has aliases that
138838c8a9a5SSteve French  * are hashed. We use this to determine if a directory inode can actually
138938c8a9a5SSteve French  * be used.
139038c8a9a5SSteve French  */
139138c8a9a5SSteve French static bool
inode_has_hashed_dentries(struct inode * inode)139238c8a9a5SSteve French inode_has_hashed_dentries(struct inode *inode)
139338c8a9a5SSteve French {
139438c8a9a5SSteve French 	struct dentry *dentry;
139538c8a9a5SSteve French 
139638c8a9a5SSteve French 	spin_lock(&inode->i_lock);
139738c8a9a5SSteve French 	hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
139838c8a9a5SSteve French 		if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
139938c8a9a5SSteve French 			spin_unlock(&inode->i_lock);
140038c8a9a5SSteve French 			return true;
140138c8a9a5SSteve French 		}
140238c8a9a5SSteve French 	}
140338c8a9a5SSteve French 	spin_unlock(&inode->i_lock);
140438c8a9a5SSteve French 	return false;
140538c8a9a5SSteve French }
140638c8a9a5SSteve French 
140738c8a9a5SSteve French /* Given fattrs, get a corresponding inode */
140838c8a9a5SSteve French struct inode *
cifs_iget(struct super_block * sb,struct cifs_fattr * fattr)140938c8a9a5SSteve French cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
141038c8a9a5SSteve French {
141138c8a9a5SSteve French 	unsigned long hash;
141238c8a9a5SSteve French 	struct inode *inode;
141338c8a9a5SSteve French 
141438c8a9a5SSteve French retry_iget5_locked:
141538c8a9a5SSteve French 	cifs_dbg(FYI, "looking for uniqueid=%llu\n", fattr->cf_uniqueid);
141638c8a9a5SSteve French 
141738c8a9a5SSteve French 	/* hash down to 32-bits on 32-bit arch */
141838c8a9a5SSteve French 	hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
141938c8a9a5SSteve French 
142038c8a9a5SSteve French 	inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
142138c8a9a5SSteve French 	if (inode) {
142238c8a9a5SSteve French 		/* was there a potentially problematic inode collision? */
142338c8a9a5SSteve French 		if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
142438c8a9a5SSteve French 			fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
142538c8a9a5SSteve French 
142638c8a9a5SSteve French 			if (inode_has_hashed_dentries(inode)) {
142738c8a9a5SSteve French 				cifs_autodisable_serverino(CIFS_SB(sb));
142838c8a9a5SSteve French 				iput(inode);
142938c8a9a5SSteve French 				fattr->cf_uniqueid = iunique(sb, ROOT_I);
143038c8a9a5SSteve French 				goto retry_iget5_locked;
143138c8a9a5SSteve French 			}
143238c8a9a5SSteve French 		}
143338c8a9a5SSteve French 
143438c8a9a5SSteve French 		/* can't fail - see cifs_find_inode() */
14359179aa27SBharath SM 		cifs_fattr_to_inode(inode, fattr, false);
143638c8a9a5SSteve French 		if (sb->s_flags & SB_NOATIME)
143738c8a9a5SSteve French 			inode->i_flags |= S_NOATIME | S_NOCMTIME;
143838c8a9a5SSteve French 		if (inode->i_state & I_NEW) {
143938c8a9a5SSteve French 			inode->i_ino = hash;
144038c8a9a5SSteve French 			cifs_fscache_get_inode_cookie(inode);
144138c8a9a5SSteve French 			unlock_new_inode(inode);
144238c8a9a5SSteve French 		}
144338c8a9a5SSteve French 	}
144438c8a9a5SSteve French 
144538c8a9a5SSteve French 	return inode;
144638c8a9a5SSteve French }
144738c8a9a5SSteve French 
144838c8a9a5SSteve French /* gets root inode */
cifs_root_iget(struct super_block * sb)144938c8a9a5SSteve French struct inode *cifs_root_iget(struct super_block *sb)
145038c8a9a5SSteve French {
145138c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1452a18280e7SPaulo Alcantara 	struct cifs_fattr fattr = {};
145338c8a9a5SSteve French 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1454a18280e7SPaulo Alcantara 	struct inode *inode = NULL;
1455a18280e7SPaulo Alcantara 	unsigned int xid;
145638c8a9a5SSteve French 	char *path = NULL;
145738c8a9a5SSteve French 	int len;
1458a18280e7SPaulo Alcantara 	int rc;
145938c8a9a5SSteve French 
146038c8a9a5SSteve French 	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
146138c8a9a5SSteve French 	    && cifs_sb->prepath) {
146238c8a9a5SSteve French 		len = strlen(cifs_sb->prepath);
146338c8a9a5SSteve French 		path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
146438c8a9a5SSteve French 		if (path == NULL)
146538c8a9a5SSteve French 			return ERR_PTR(-ENOMEM);
146638c8a9a5SSteve French 		path[0] = '/';
146738c8a9a5SSteve French 		memcpy(path+1, cifs_sb->prepath, len);
146838c8a9a5SSteve French 	} else {
146938c8a9a5SSteve French 		path = kstrdup("", GFP_KERNEL);
147038c8a9a5SSteve French 		if (path == NULL)
147138c8a9a5SSteve French 			return ERR_PTR(-ENOMEM);
147238c8a9a5SSteve French 	}
147338c8a9a5SSteve French 
147438c8a9a5SSteve French 	xid = get_xid();
147538c8a9a5SSteve French 	if (tcon->unix_ext) {
1476a18280e7SPaulo Alcantara 		rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid);
147738c8a9a5SSteve French 		/* some servers mistakenly claim POSIX support */
147838c8a9a5SSteve French 		if (rc != -EOPNOTSUPP)
1479a18280e7SPaulo Alcantara 			goto iget_root;
148038c8a9a5SSteve French 		cifs_dbg(VFS, "server does not support POSIX extensions\n");
148138c8a9a5SSteve French 		tcon->unix_ext = false;
148238c8a9a5SSteve French 	}
148338c8a9a5SSteve French 
148438c8a9a5SSteve French 	convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
148538c8a9a5SSteve French 	if (tcon->posix_extensions)
148602bcf865SSteve French 		rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid);
148738c8a9a5SSteve French 	else
1488a18280e7SPaulo Alcantara 		rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path);
148938c8a9a5SSteve French 
1490a18280e7SPaulo Alcantara iget_root:
1491a18280e7SPaulo Alcantara 	if (!rc) {
1492a18280e7SPaulo Alcantara 		if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
1493a18280e7SPaulo Alcantara 			fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
1494a18280e7SPaulo Alcantara 			cifs_autodisable_serverino(cifs_sb);
1495a18280e7SPaulo Alcantara 		}
1496a18280e7SPaulo Alcantara 		inode = cifs_iget(sb, &fattr);
1497a18280e7SPaulo Alcantara 	}
1498a18280e7SPaulo Alcantara 
149938c8a9a5SSteve French 	if (!inode) {
150038c8a9a5SSteve French 		inode = ERR_PTR(rc);
150138c8a9a5SSteve French 		goto out;
150238c8a9a5SSteve French 	}
150338c8a9a5SSteve French 
15041598a015SMeetakshi Setiya 	if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
15051598a015SMeetakshi Setiya 		cifs_mark_open_handles_for_deleted_file(inode, path);
15061598a015SMeetakshi Setiya 
150738c8a9a5SSteve French 	if (rc && tcon->pipe) {
150838c8a9a5SSteve French 		cifs_dbg(FYI, "ipc connection - fake read inode\n");
150938c8a9a5SSteve French 		spin_lock(&inode->i_lock);
151038c8a9a5SSteve French 		inode->i_mode |= S_IFDIR;
151138c8a9a5SSteve French 		set_nlink(inode, 2);
151238c8a9a5SSteve French 		inode->i_op = &cifs_ipc_inode_ops;
151338c8a9a5SSteve French 		inode->i_fop = &simple_dir_operations;
151438c8a9a5SSteve French 		inode->i_uid = cifs_sb->ctx->linux_uid;
151538c8a9a5SSteve French 		inode->i_gid = cifs_sb->ctx->linux_gid;
151638c8a9a5SSteve French 		spin_unlock(&inode->i_lock);
151738c8a9a5SSteve French 	} else if (rc) {
151838c8a9a5SSteve French 		iget_failed(inode);
151938c8a9a5SSteve French 		inode = ERR_PTR(rc);
152038c8a9a5SSteve French 	}
152138c8a9a5SSteve French 
152238c8a9a5SSteve French out:
152338c8a9a5SSteve French 	kfree(path);
152438c8a9a5SSteve French 	free_xid(xid);
1525a18280e7SPaulo Alcantara 	kfree(fattr.cf_symlink_target);
152638c8a9a5SSteve French 	return inode;
152738c8a9a5SSteve French }
152838c8a9a5SSteve French 
152938c8a9a5SSteve French int
cifs_set_file_info(struct inode * inode,struct iattr * attrs,unsigned int xid,const char * full_path,__u32 dosattr)153038c8a9a5SSteve French cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
153138c8a9a5SSteve French 		   const char *full_path, __u32 dosattr)
153238c8a9a5SSteve French {
153338c8a9a5SSteve French 	bool set_time = false;
153438c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
153538c8a9a5SSteve French 	struct TCP_Server_Info *server;
153638c8a9a5SSteve French 	FILE_BASIC_INFO	info_buf;
153738c8a9a5SSteve French 
153838c8a9a5SSteve French 	if (attrs == NULL)
153938c8a9a5SSteve French 		return -EINVAL;
154038c8a9a5SSteve French 
154138c8a9a5SSteve French 	server = cifs_sb_master_tcon(cifs_sb)->ses->server;
154238c8a9a5SSteve French 	if (!server->ops->set_file_info)
154338c8a9a5SSteve French 		return -ENOSYS;
154438c8a9a5SSteve French 
154538c8a9a5SSteve French 	info_buf.Pad = 0;
154638c8a9a5SSteve French 
154738c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_ATIME) {
154838c8a9a5SSteve French 		set_time = true;
154938c8a9a5SSteve French 		info_buf.LastAccessTime =
155038c8a9a5SSteve French 			cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
155138c8a9a5SSteve French 	} else
155238c8a9a5SSteve French 		info_buf.LastAccessTime = 0;
155338c8a9a5SSteve French 
155438c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_MTIME) {
155538c8a9a5SSteve French 		set_time = true;
155638c8a9a5SSteve French 		info_buf.LastWriteTime =
155738c8a9a5SSteve French 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
155838c8a9a5SSteve French 	} else
155938c8a9a5SSteve French 		info_buf.LastWriteTime = 0;
156038c8a9a5SSteve French 
156138c8a9a5SSteve French 	/*
156238c8a9a5SSteve French 	 * Samba throws this field away, but windows may actually use it.
156338c8a9a5SSteve French 	 * Do not set ctime unless other time stamps are changed explicitly
156438c8a9a5SSteve French 	 * (i.e. by utimes()) since we would then have a mix of client and
156538c8a9a5SSteve French 	 * server times.
156638c8a9a5SSteve French 	 */
156738c8a9a5SSteve French 	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
156838c8a9a5SSteve French 		cifs_dbg(FYI, "CIFS - CTIME changed\n");
156938c8a9a5SSteve French 		info_buf.ChangeTime =
157038c8a9a5SSteve French 		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
157138c8a9a5SSteve French 	} else
157238c8a9a5SSteve French 		info_buf.ChangeTime = 0;
157338c8a9a5SSteve French 
157438c8a9a5SSteve French 	info_buf.CreationTime = 0;	/* don't change */
157538c8a9a5SSteve French 	info_buf.Attributes = cpu_to_le32(dosattr);
157638c8a9a5SSteve French 
157738c8a9a5SSteve French 	return server->ops->set_file_info(inode, full_path, &info_buf, xid);
157838c8a9a5SSteve French }
157938c8a9a5SSteve French 
158038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
158138c8a9a5SSteve French /*
158238c8a9a5SSteve French  * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
158338c8a9a5SSteve French  * and rename it to a random name that hopefully won't conflict with
158438c8a9a5SSteve French  * anything else.
158538c8a9a5SSteve French  */
158638c8a9a5SSteve French int
cifs_rename_pending_delete(const char * full_path,struct dentry * dentry,const unsigned int xid)158738c8a9a5SSteve French cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
158838c8a9a5SSteve French 			   const unsigned int xid)
158938c8a9a5SSteve French {
159038c8a9a5SSteve French 	int oplock = 0;
159138c8a9a5SSteve French 	int rc;
159238c8a9a5SSteve French 	struct cifs_fid fid;
159338c8a9a5SSteve French 	struct cifs_open_parms oparms;
159438c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
159538c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
159638c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
159738c8a9a5SSteve French 	struct tcon_link *tlink;
159838c8a9a5SSteve French 	struct cifs_tcon *tcon;
159938c8a9a5SSteve French 	__u32 dosattr, origattr;
160038c8a9a5SSteve French 	FILE_BASIC_INFO *info_buf = NULL;
160138c8a9a5SSteve French 
160238c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
160338c8a9a5SSteve French 	if (IS_ERR(tlink))
160438c8a9a5SSteve French 		return PTR_ERR(tlink);
160538c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
160638c8a9a5SSteve French 
160738c8a9a5SSteve French 	/*
160838c8a9a5SSteve French 	 * We cannot rename the file if the server doesn't support
160938c8a9a5SSteve French 	 * CAP_INFOLEVEL_PASSTHRU
161038c8a9a5SSteve French 	 */
161138c8a9a5SSteve French 	if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) {
161238c8a9a5SSteve French 		rc = -EBUSY;
161338c8a9a5SSteve French 		goto out;
161438c8a9a5SSteve French 	}
161538c8a9a5SSteve French 
161638c8a9a5SSteve French 	oparms = (struct cifs_open_parms) {
161738c8a9a5SSteve French 		.tcon = tcon,
161838c8a9a5SSteve French 		.cifs_sb = cifs_sb,
161938c8a9a5SSteve French 		.desired_access = DELETE | FILE_WRITE_ATTRIBUTES,
162038c8a9a5SSteve French 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
162138c8a9a5SSteve French 		.disposition = FILE_OPEN,
162238c8a9a5SSteve French 		.path = full_path,
162338c8a9a5SSteve French 		.fid = &fid,
162438c8a9a5SSteve French 	};
162538c8a9a5SSteve French 
162638c8a9a5SSteve French 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
162738c8a9a5SSteve French 	if (rc != 0)
162838c8a9a5SSteve French 		goto out;
162938c8a9a5SSteve French 
163038c8a9a5SSteve French 	origattr = cifsInode->cifsAttrs;
163138c8a9a5SSteve French 	if (origattr == 0)
163238c8a9a5SSteve French 		origattr |= ATTR_NORMAL;
163338c8a9a5SSteve French 
163438c8a9a5SSteve French 	dosattr = origattr & ~ATTR_READONLY;
163538c8a9a5SSteve French 	if (dosattr == 0)
163638c8a9a5SSteve French 		dosattr |= ATTR_NORMAL;
163738c8a9a5SSteve French 	dosattr |= ATTR_HIDDEN;
163838c8a9a5SSteve French 
163938c8a9a5SSteve French 	/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
164038c8a9a5SSteve French 	if (dosattr != origattr) {
164138c8a9a5SSteve French 		info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
164238c8a9a5SSteve French 		if (info_buf == NULL) {
164338c8a9a5SSteve French 			rc = -ENOMEM;
164438c8a9a5SSteve French 			goto out_close;
164538c8a9a5SSteve French 		}
164638c8a9a5SSteve French 		info_buf->Attributes = cpu_to_le32(dosattr);
164738c8a9a5SSteve French 		rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid,
164838c8a9a5SSteve French 					current->tgid);
164938c8a9a5SSteve French 		/* although we would like to mark the file hidden
165038c8a9a5SSteve French  		   if that fails we will still try to rename it */
165138c8a9a5SSteve French 		if (!rc)
165238c8a9a5SSteve French 			cifsInode->cifsAttrs = dosattr;
165338c8a9a5SSteve French 		else
165438c8a9a5SSteve French 			dosattr = origattr; /* since not able to change them */
165538c8a9a5SSteve French 	}
165638c8a9a5SSteve French 
165738c8a9a5SSteve French 	/* rename the file */
165838c8a9a5SSteve French 	rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL,
165938c8a9a5SSteve French 				   cifs_sb->local_nls,
166038c8a9a5SSteve French 				   cifs_remap(cifs_sb));
166138c8a9a5SSteve French 	if (rc != 0) {
166238c8a9a5SSteve French 		rc = -EBUSY;
166338c8a9a5SSteve French 		goto undo_setattr;
166438c8a9a5SSteve French 	}
166538c8a9a5SSteve French 
166638c8a9a5SSteve French 	/* try to set DELETE_ON_CLOSE */
166738c8a9a5SSteve French 	if (!test_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags)) {
166838c8a9a5SSteve French 		rc = CIFSSMBSetFileDisposition(xid, tcon, true, fid.netfid,
166938c8a9a5SSteve French 					       current->tgid);
167038c8a9a5SSteve French 		/*
167138c8a9a5SSteve French 		 * some samba versions return -ENOENT when we try to set the
167238c8a9a5SSteve French 		 * file disposition here. Likely a samba bug, but work around
167338c8a9a5SSteve French 		 * it for now. This means that some cifsXXX files may hang
167438c8a9a5SSteve French 		 * around after they shouldn't.
167538c8a9a5SSteve French 		 *
167638c8a9a5SSteve French 		 * BB: remove this hack after more servers have the fix
167738c8a9a5SSteve French 		 */
167838c8a9a5SSteve French 		if (rc == -ENOENT)
167938c8a9a5SSteve French 			rc = 0;
168038c8a9a5SSteve French 		else if (rc != 0) {
168138c8a9a5SSteve French 			rc = -EBUSY;
168238c8a9a5SSteve French 			goto undo_rename;
168338c8a9a5SSteve French 		}
168438c8a9a5SSteve French 		set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags);
168538c8a9a5SSteve French 	}
168638c8a9a5SSteve French 
168738c8a9a5SSteve French out_close:
168838c8a9a5SSteve French 	CIFSSMBClose(xid, tcon, fid.netfid);
168938c8a9a5SSteve French out:
169038c8a9a5SSteve French 	kfree(info_buf);
169138c8a9a5SSteve French 	cifs_put_tlink(tlink);
169238c8a9a5SSteve French 	return rc;
169338c8a9a5SSteve French 
169438c8a9a5SSteve French 	/*
169538c8a9a5SSteve French 	 * reset everything back to the original state. Don't bother
169638c8a9a5SSteve French 	 * dealing with errors here since we can't do anything about
169738c8a9a5SSteve French 	 * them anyway.
169838c8a9a5SSteve French 	 */
169938c8a9a5SSteve French undo_rename:
170038c8a9a5SSteve French 	CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name,
170138c8a9a5SSteve French 				cifs_sb->local_nls, cifs_remap(cifs_sb));
170238c8a9a5SSteve French undo_setattr:
170338c8a9a5SSteve French 	if (dosattr != origattr) {
170438c8a9a5SSteve French 		info_buf->Attributes = cpu_to_le32(origattr);
170538c8a9a5SSteve French 		if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid,
170638c8a9a5SSteve French 					current->tgid))
170738c8a9a5SSteve French 			cifsInode->cifsAttrs = origattr;
170838c8a9a5SSteve French 	}
170938c8a9a5SSteve French 
171038c8a9a5SSteve French 	goto out_close;
171138c8a9a5SSteve French }
171238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
171338c8a9a5SSteve French 
171438c8a9a5SSteve French /* copied from fs/nfs/dir.c with small changes */
171538c8a9a5SSteve French static void
cifs_drop_nlink(struct inode * inode)171638c8a9a5SSteve French cifs_drop_nlink(struct inode *inode)
171738c8a9a5SSteve French {
171838c8a9a5SSteve French 	spin_lock(&inode->i_lock);
171938c8a9a5SSteve French 	if (inode->i_nlink > 0)
172038c8a9a5SSteve French 		drop_nlink(inode);
172138c8a9a5SSteve French 	spin_unlock(&inode->i_lock);
172238c8a9a5SSteve French }
172338c8a9a5SSteve French 
172438c8a9a5SSteve French /*
172538c8a9a5SSteve French  * If d_inode(dentry) is null (usually meaning the cached dentry
172638c8a9a5SSteve French  * is a negative dentry) then we would attempt a standard SMB delete, but
172738c8a9a5SSteve French  * if that fails we can not attempt the fall back mechanisms on EACCES
172838c8a9a5SSteve French  * but will return the EACCES to the caller. Note that the VFS does not call
172938c8a9a5SSteve French  * unlink on negative dentries currently.
173038c8a9a5SSteve French  */
cifs_unlink(struct inode * dir,struct dentry * dentry)173138c8a9a5SSteve French int cifs_unlink(struct inode *dir, struct dentry *dentry)
173238c8a9a5SSteve French {
173338c8a9a5SSteve French 	int rc = 0;
173438c8a9a5SSteve French 	unsigned int xid;
173538c8a9a5SSteve French 	const char *full_path;
173638c8a9a5SSteve French 	void *page;
173738c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
173838c8a9a5SSteve French 	struct cifsInodeInfo *cifs_inode;
173938c8a9a5SSteve French 	struct super_block *sb = dir->i_sb;
174038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
174138c8a9a5SSteve French 	struct tcon_link *tlink;
174238c8a9a5SSteve French 	struct cifs_tcon *tcon;
174338c8a9a5SSteve French 	struct TCP_Server_Info *server;
174438c8a9a5SSteve French 	struct iattr *attrs = NULL;
174538c8a9a5SSteve French 	__u32 dosattr = 0, origattr = 0;
174638c8a9a5SSteve French 
174738c8a9a5SSteve French 	cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
174838c8a9a5SSteve French 
174938c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
175038c8a9a5SSteve French 		return -EIO;
175138c8a9a5SSteve French 
175238c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
175338c8a9a5SSteve French 	if (IS_ERR(tlink))
175438c8a9a5SSteve French 		return PTR_ERR(tlink);
175538c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
175638c8a9a5SSteve French 	server = tcon->ses->server;
175738c8a9a5SSteve French 
175838c8a9a5SSteve French 	xid = get_xid();
175938c8a9a5SSteve French 	page = alloc_dentry_path();
176038c8a9a5SSteve French 
176138c8a9a5SSteve French 	if (tcon->nodelete) {
176238c8a9a5SSteve French 		rc = -EACCES;
176338c8a9a5SSteve French 		goto unlink_out;
176438c8a9a5SSteve French 	}
176538c8a9a5SSteve French 
176638c8a9a5SSteve French 	/* Unlink can be called from rename so we can not take the
176738c8a9a5SSteve French 	 * sb->s_vfs_rename_mutex here */
176838c8a9a5SSteve French 	full_path = build_path_from_dentry(dentry, page);
176938c8a9a5SSteve French 	if (IS_ERR(full_path)) {
177038c8a9a5SSteve French 		rc = PTR_ERR(full_path);
177138c8a9a5SSteve French 		goto unlink_out;
177238c8a9a5SSteve French 	}
177338c8a9a5SSteve French 
177438c8a9a5SSteve French 	cifs_close_deferred_file_under_dentry(tcon, full_path);
177538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
177638c8a9a5SSteve French 	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
177738c8a9a5SSteve French 				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
177838c8a9a5SSteve French 		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
177938c8a9a5SSteve French 			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
178038c8a9a5SSteve French 			cifs_remap(cifs_sb));
178138c8a9a5SSteve French 		cifs_dbg(FYI, "posix del rc %d\n", rc);
178238c8a9a5SSteve French 		if ((rc == 0) || (rc == -ENOENT))
178338c8a9a5SSteve French 			goto psx_del_no_retry;
178438c8a9a5SSteve French 	}
178538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
178638c8a9a5SSteve French 
178738c8a9a5SSteve French retry_std_delete:
178838c8a9a5SSteve French 	if (!server->ops->unlink) {
178938c8a9a5SSteve French 		rc = -ENOSYS;
179038c8a9a5SSteve French 		goto psx_del_no_retry;
179138c8a9a5SSteve French 	}
179238c8a9a5SSteve French 
1793f93d145fSMeetakshi Setiya 	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
179438c8a9a5SSteve French 
179538c8a9a5SSteve French psx_del_no_retry:
179638c8a9a5SSteve French 	if (!rc) {
1797b6e27f7fSSteve French 		if (inode) {
1798b6e27f7fSSteve French 			cifs_mark_open_handles_for_deleted_file(inode, full_path);
179938c8a9a5SSteve French 			cifs_drop_nlink(inode);
1800b6e27f7fSSteve French 		}
180138c8a9a5SSteve French 	} else if (rc == -ENOENT) {
180238c8a9a5SSteve French 		d_drop(dentry);
180338c8a9a5SSteve French 	} else if (rc == -EBUSY) {
180438c8a9a5SSteve French 		if (server->ops->rename_pending_delete) {
180538c8a9a5SSteve French 			rc = server->ops->rename_pending_delete(full_path,
180638c8a9a5SSteve French 								dentry, xid);
1807b6e27f7fSSteve French 			if (rc == 0) {
1808b6e27f7fSSteve French 				cifs_mark_open_handles_for_deleted_file(inode, full_path);
180938c8a9a5SSteve French 				cifs_drop_nlink(inode);
181038c8a9a5SSteve French 			}
1811b6e27f7fSSteve French 		}
181238c8a9a5SSteve French 	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
181338c8a9a5SSteve French 		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
181438c8a9a5SSteve French 		if (attrs == NULL) {
181538c8a9a5SSteve French 			rc = -ENOMEM;
181638c8a9a5SSteve French 			goto out_reval;
181738c8a9a5SSteve French 		}
181838c8a9a5SSteve French 
181938c8a9a5SSteve French 		/* try to reset dos attributes */
182038c8a9a5SSteve French 		cifs_inode = CIFS_I(inode);
182138c8a9a5SSteve French 		origattr = cifs_inode->cifsAttrs;
182238c8a9a5SSteve French 		if (origattr == 0)
182338c8a9a5SSteve French 			origattr |= ATTR_NORMAL;
182438c8a9a5SSteve French 		dosattr = origattr & ~ATTR_READONLY;
182538c8a9a5SSteve French 		if (dosattr == 0)
182638c8a9a5SSteve French 			dosattr |= ATTR_NORMAL;
182738c8a9a5SSteve French 		dosattr |= ATTR_HIDDEN;
182838c8a9a5SSteve French 
182938c8a9a5SSteve French 		rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
183038c8a9a5SSteve French 		if (rc != 0)
183138c8a9a5SSteve French 			goto out_reval;
183238c8a9a5SSteve French 
183338c8a9a5SSteve French 		goto retry_std_delete;
183438c8a9a5SSteve French 	}
183538c8a9a5SSteve French 
183638c8a9a5SSteve French 	/* undo the setattr if we errored out and it's needed */
183738c8a9a5SSteve French 	if (rc != 0 && dosattr != 0)
183838c8a9a5SSteve French 		cifs_set_file_info(inode, attrs, xid, full_path, origattr);
183938c8a9a5SSteve French 
184038c8a9a5SSteve French out_reval:
184138c8a9a5SSteve French 	if (inode) {
184238c8a9a5SSteve French 		cifs_inode = CIFS_I(inode);
184338c8a9a5SSteve French 		cifs_inode->time = 0;	/* will force revalidate to get info
184438c8a9a5SSteve French 					   when needed */
184594487653SJeff Layton 		inode_set_ctime_current(inode);
184638c8a9a5SSteve French 	}
184723171df5SJeff Layton 	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
184838c8a9a5SSteve French 	cifs_inode = CIFS_I(dir);
184938c8a9a5SSteve French 	CIFS_I(dir)->time = 0;	/* force revalidate of dir as well */
185038c8a9a5SSteve French unlink_out:
185138c8a9a5SSteve French 	free_dentry_path(page);
185238c8a9a5SSteve French 	kfree(attrs);
185338c8a9a5SSteve French 	free_xid(xid);
185438c8a9a5SSteve French 	cifs_put_tlink(tlink);
185538c8a9a5SSteve French 	return rc;
185638c8a9a5SSteve French }
185738c8a9a5SSteve French 
185838c8a9a5SSteve French static int
cifs_mkdir_qinfo(struct inode * parent,struct dentry * dentry,umode_t mode,const char * full_path,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)185938c8a9a5SSteve French cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
186038c8a9a5SSteve French 		 const char *full_path, struct cifs_sb_info *cifs_sb,
186138c8a9a5SSteve French 		 struct cifs_tcon *tcon, const unsigned int xid)
186238c8a9a5SSteve French {
186338c8a9a5SSteve French 	int rc = 0;
186438c8a9a5SSteve French 	struct inode *inode = NULL;
186538c8a9a5SSteve French 
186602bcf865SSteve French 	if (tcon->posix_extensions) {
186702bcf865SSteve French 		rc = smb311_posix_get_inode_info(&inode, full_path,
186802bcf865SSteve French 						 NULL, parent->i_sb, xid);
186938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
187002bcf865SSteve French 	} else if (tcon->unix_ext) {
187138c8a9a5SSteve French 		rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
187238c8a9a5SSteve French 					      xid);
187338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
187402bcf865SSteve French 	} else {
187538c8a9a5SSteve French 		rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb,
187638c8a9a5SSteve French 					 xid, NULL);
187702bcf865SSteve French 	}
187838c8a9a5SSteve French 
187938c8a9a5SSteve French 	if (rc)
188038c8a9a5SSteve French 		return rc;
188138c8a9a5SSteve French 
188238c8a9a5SSteve French 	if (!S_ISDIR(inode->i_mode)) {
188338c8a9a5SSteve French 		/*
188438c8a9a5SSteve French 		 * mkdir succeeded, but another client has managed to remove the
188538c8a9a5SSteve French 		 * sucker and replace it with non-directory.  Return success,
188638c8a9a5SSteve French 		 * but don't leave the child in dcache.
188738c8a9a5SSteve French 		 */
188838c8a9a5SSteve French 		 iput(inode);
188938c8a9a5SSteve French 		 d_drop(dentry);
189038c8a9a5SSteve French 		 return 0;
189138c8a9a5SSteve French 	}
189238c8a9a5SSteve French 	/*
189338c8a9a5SSteve French 	 * setting nlink not necessary except in cases where we failed to get it
189438c8a9a5SSteve French 	 * from the server or was set bogus. Also, since this is a brand new
189538c8a9a5SSteve French 	 * inode, no need to grab the i_lock before setting the i_nlink.
189638c8a9a5SSteve French 	 */
189738c8a9a5SSteve French 	if (inode->i_nlink < 2)
189838c8a9a5SSteve French 		set_nlink(inode, 2);
189938c8a9a5SSteve French 	mode &= ~current_umask();
190038c8a9a5SSteve French 	/* must turn on setgid bit if parent dir has it */
190138c8a9a5SSteve French 	if (parent->i_mode & S_ISGID)
190238c8a9a5SSteve French 		mode |= S_ISGID;
190338c8a9a5SSteve French 
190438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
190538c8a9a5SSteve French 	if (tcon->unix_ext) {
190638c8a9a5SSteve French 		struct cifs_unix_set_info_args args = {
190738c8a9a5SSteve French 			.mode	= mode,
190838c8a9a5SSteve French 			.ctime	= NO_CHANGE_64,
190938c8a9a5SSteve French 			.atime	= NO_CHANGE_64,
191038c8a9a5SSteve French 			.mtime	= NO_CHANGE_64,
191138c8a9a5SSteve French 			.device	= 0,
191238c8a9a5SSteve French 		};
191338c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
191438c8a9a5SSteve French 			args.uid = current_fsuid();
191538c8a9a5SSteve French 			if (parent->i_mode & S_ISGID)
191638c8a9a5SSteve French 				args.gid = parent->i_gid;
191738c8a9a5SSteve French 			else
191838c8a9a5SSteve French 				args.gid = current_fsgid();
191938c8a9a5SSteve French 		} else {
192038c8a9a5SSteve French 			args.uid = INVALID_UID; /* no change */
192138c8a9a5SSteve French 			args.gid = INVALID_GID; /* no change */
192238c8a9a5SSteve French 		}
192338c8a9a5SSteve French 		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
192438c8a9a5SSteve French 				       cifs_sb->local_nls,
192538c8a9a5SSteve French 				       cifs_remap(cifs_sb));
192638c8a9a5SSteve French 	} else {
192738c8a9a5SSteve French #else
192838c8a9a5SSteve French 	{
192938c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
193038c8a9a5SSteve French 		struct TCP_Server_Info *server = tcon->ses->server;
193138c8a9a5SSteve French 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
193238c8a9a5SSteve French 		    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
193338c8a9a5SSteve French 			server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
193438c8a9a5SSteve French 						   tcon, xid);
193538c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
193638c8a9a5SSteve French 			inode->i_mode = (mode | S_IFDIR);
193738c8a9a5SSteve French 
193838c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
193938c8a9a5SSteve French 			inode->i_uid = current_fsuid();
194038c8a9a5SSteve French 			if (inode->i_mode & S_ISGID)
194138c8a9a5SSteve French 				inode->i_gid = parent->i_gid;
194238c8a9a5SSteve French 			else
194338c8a9a5SSteve French 				inode->i_gid = current_fsgid();
194438c8a9a5SSteve French 		}
194538c8a9a5SSteve French 	}
194638c8a9a5SSteve French 	d_instantiate(dentry, inode);
194738c8a9a5SSteve French 	return 0;
194838c8a9a5SSteve French }
194938c8a9a5SSteve French 
195038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
195138c8a9a5SSteve French static int
195238c8a9a5SSteve French cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
195338c8a9a5SSteve French 		 const char *full_path, struct cifs_sb_info *cifs_sb,
195438c8a9a5SSteve French 		 struct cifs_tcon *tcon, const unsigned int xid)
195538c8a9a5SSteve French {
195638c8a9a5SSteve French 	int rc = 0;
195738c8a9a5SSteve French 	u32 oplock = 0;
195838c8a9a5SSteve French 	FILE_UNIX_BASIC_INFO *info = NULL;
195938c8a9a5SSteve French 	struct inode *newinode = NULL;
196038c8a9a5SSteve French 	struct cifs_fattr fattr;
196138c8a9a5SSteve French 
196238c8a9a5SSteve French 	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
196338c8a9a5SSteve French 	if (info == NULL) {
196438c8a9a5SSteve French 		rc = -ENOMEM;
196538c8a9a5SSteve French 		goto posix_mkdir_out;
196638c8a9a5SSteve French 	}
196738c8a9a5SSteve French 
196838c8a9a5SSteve French 	mode &= ~current_umask();
196938c8a9a5SSteve French 	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
197038c8a9a5SSteve French 			     NULL /* netfid */, info, &oplock, full_path,
197138c8a9a5SSteve French 			     cifs_sb->local_nls, cifs_remap(cifs_sb));
197238c8a9a5SSteve French 	if (rc == -EOPNOTSUPP)
197338c8a9a5SSteve French 		goto posix_mkdir_out;
197438c8a9a5SSteve French 	else if (rc) {
197538c8a9a5SSteve French 		cifs_dbg(FYI, "posix mkdir returned 0x%x\n", rc);
197638c8a9a5SSteve French 		d_drop(dentry);
197738c8a9a5SSteve French 		goto posix_mkdir_out;
197838c8a9a5SSteve French 	}
197938c8a9a5SSteve French 
198038c8a9a5SSteve French 	if (info->Type == cpu_to_le32(-1))
198138c8a9a5SSteve French 		/* no return info, go query for it */
198238c8a9a5SSteve French 		goto posix_mkdir_get_info;
198338c8a9a5SSteve French 	/*
198438c8a9a5SSteve French 	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
198538c8a9a5SSteve French 	 * need to set uid/gid.
198638c8a9a5SSteve French 	 */
198738c8a9a5SSteve French 
198838c8a9a5SSteve French 	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
198938c8a9a5SSteve French 	cifs_fill_uniqueid(inode->i_sb, &fattr);
199038c8a9a5SSteve French 	newinode = cifs_iget(inode->i_sb, &fattr);
199138c8a9a5SSteve French 	if (!newinode)
199238c8a9a5SSteve French 		goto posix_mkdir_get_info;
199338c8a9a5SSteve French 
199438c8a9a5SSteve French 	d_instantiate(dentry, newinode);
199538c8a9a5SSteve French 
199638c8a9a5SSteve French #ifdef CONFIG_CIFS_DEBUG2
199738c8a9a5SSteve French 	cifs_dbg(FYI, "instantiated dentry %p %pd to inode %p\n",
199838c8a9a5SSteve French 		 dentry, dentry, newinode);
199938c8a9a5SSteve French 
200038c8a9a5SSteve French 	if (newinode->i_nlink != 2)
200138c8a9a5SSteve French 		cifs_dbg(FYI, "unexpected number of links %d\n",
200238c8a9a5SSteve French 			 newinode->i_nlink);
200338c8a9a5SSteve French #endif
200438c8a9a5SSteve French 
200538c8a9a5SSteve French posix_mkdir_out:
200638c8a9a5SSteve French 	kfree(info);
200738c8a9a5SSteve French 	return rc;
200838c8a9a5SSteve French posix_mkdir_get_info:
200938c8a9a5SSteve French 	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
201038c8a9a5SSteve French 			      xid);
201138c8a9a5SSteve French 	goto posix_mkdir_out;
201238c8a9a5SSteve French }
201338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
201438c8a9a5SSteve French 
201538c8a9a5SSteve French int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
201638c8a9a5SSteve French 	       struct dentry *direntry, umode_t mode)
201738c8a9a5SSteve French {
201838c8a9a5SSteve French 	int rc = 0;
201938c8a9a5SSteve French 	unsigned int xid;
202038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb;
202138c8a9a5SSteve French 	struct tcon_link *tlink;
202238c8a9a5SSteve French 	struct cifs_tcon *tcon;
202338c8a9a5SSteve French 	struct TCP_Server_Info *server;
202438c8a9a5SSteve French 	const char *full_path;
202538c8a9a5SSteve French 	void *page;
202638c8a9a5SSteve French 
202738c8a9a5SSteve French 	cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n",
202838c8a9a5SSteve French 		 mode, inode);
202938c8a9a5SSteve French 
203038c8a9a5SSteve French 	cifs_sb = CIFS_SB(inode->i_sb);
203138c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
203238c8a9a5SSteve French 		return -EIO;
203338c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
203438c8a9a5SSteve French 	if (IS_ERR(tlink))
203538c8a9a5SSteve French 		return PTR_ERR(tlink);
203638c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
203738c8a9a5SSteve French 
203838c8a9a5SSteve French 	xid = get_xid();
203938c8a9a5SSteve French 
204038c8a9a5SSteve French 	page = alloc_dentry_path();
204138c8a9a5SSteve French 	full_path = build_path_from_dentry(direntry, page);
204238c8a9a5SSteve French 	if (IS_ERR(full_path)) {
204338c8a9a5SSteve French 		rc = PTR_ERR(full_path);
204438c8a9a5SSteve French 		goto mkdir_out;
204538c8a9a5SSteve French 	}
204638c8a9a5SSteve French 
204738c8a9a5SSteve French 	server = tcon->ses->server;
204838c8a9a5SSteve French 
204938c8a9a5SSteve French 	if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
205038c8a9a5SSteve French 		rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
205138c8a9a5SSteve French 					      cifs_sb);
205238c8a9a5SSteve French 		d_drop(direntry); /* for time being always refresh inode info */
205338c8a9a5SSteve French 		goto mkdir_out;
205438c8a9a5SSteve French 	}
205538c8a9a5SSteve French 
205638c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
205738c8a9a5SSteve French 	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
205838c8a9a5SSteve French 				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
205938c8a9a5SSteve French 		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
206038c8a9a5SSteve French 				      tcon, xid);
206138c8a9a5SSteve French 		if (rc != -EOPNOTSUPP)
206238c8a9a5SSteve French 			goto mkdir_out;
206338c8a9a5SSteve French 	}
206438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
206538c8a9a5SSteve French 
206638c8a9a5SSteve French 	if (!server->ops->mkdir) {
206738c8a9a5SSteve French 		rc = -ENOSYS;
206838c8a9a5SSteve French 		goto mkdir_out;
206938c8a9a5SSteve French 	}
207038c8a9a5SSteve French 
207138c8a9a5SSteve French 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
207238c8a9a5SSteve French 	rc = server->ops->mkdir(xid, inode, mode, tcon, full_path, cifs_sb);
207338c8a9a5SSteve French 	if (rc) {
207438c8a9a5SSteve French 		cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc);
207538c8a9a5SSteve French 		d_drop(direntry);
207638c8a9a5SSteve French 		goto mkdir_out;
207738c8a9a5SSteve French 	}
207838c8a9a5SSteve French 
207938c8a9a5SSteve French 	/* TODO: skip this for smb2/smb3 */
208038c8a9a5SSteve French 	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
208138c8a9a5SSteve French 			      xid);
208238c8a9a5SSteve French mkdir_out:
208338c8a9a5SSteve French 	/*
208438c8a9a5SSteve French 	 * Force revalidate to get parent dir info when needed since cached
208538c8a9a5SSteve French 	 * attributes are invalid now.
208638c8a9a5SSteve French 	 */
208738c8a9a5SSteve French 	CIFS_I(inode)->time = 0;
208838c8a9a5SSteve French 	free_dentry_path(page);
208938c8a9a5SSteve French 	free_xid(xid);
209038c8a9a5SSteve French 	cifs_put_tlink(tlink);
209138c8a9a5SSteve French 	return rc;
209238c8a9a5SSteve French }
209338c8a9a5SSteve French 
209438c8a9a5SSteve French int cifs_rmdir(struct inode *inode, struct dentry *direntry)
209538c8a9a5SSteve French {
209638c8a9a5SSteve French 	int rc = 0;
209738c8a9a5SSteve French 	unsigned int xid;
209838c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb;
209938c8a9a5SSteve French 	struct tcon_link *tlink;
210038c8a9a5SSteve French 	struct cifs_tcon *tcon;
210138c8a9a5SSteve French 	struct TCP_Server_Info *server;
210238c8a9a5SSteve French 	const char *full_path;
210338c8a9a5SSteve French 	void *page = alloc_dentry_path();
210438c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode;
210538c8a9a5SSteve French 
210638c8a9a5SSteve French 	cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode);
210738c8a9a5SSteve French 
210838c8a9a5SSteve French 	xid = get_xid();
210938c8a9a5SSteve French 
211038c8a9a5SSteve French 	full_path = build_path_from_dentry(direntry, page);
211138c8a9a5SSteve French 	if (IS_ERR(full_path)) {
211238c8a9a5SSteve French 		rc = PTR_ERR(full_path);
211338c8a9a5SSteve French 		goto rmdir_exit;
211438c8a9a5SSteve French 	}
211538c8a9a5SSteve French 
211638c8a9a5SSteve French 	cifs_sb = CIFS_SB(inode->i_sb);
211738c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb))) {
211838c8a9a5SSteve French 		rc = -EIO;
211938c8a9a5SSteve French 		goto rmdir_exit;
212038c8a9a5SSteve French 	}
212138c8a9a5SSteve French 
212238c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
212338c8a9a5SSteve French 	if (IS_ERR(tlink)) {
212438c8a9a5SSteve French 		rc = PTR_ERR(tlink);
212538c8a9a5SSteve French 		goto rmdir_exit;
212638c8a9a5SSteve French 	}
212738c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
212838c8a9a5SSteve French 	server = tcon->ses->server;
212938c8a9a5SSteve French 
213038c8a9a5SSteve French 	if (!server->ops->rmdir) {
213138c8a9a5SSteve French 		rc = -ENOSYS;
213238c8a9a5SSteve French 		cifs_put_tlink(tlink);
213338c8a9a5SSteve French 		goto rmdir_exit;
213438c8a9a5SSteve French 	}
213538c8a9a5SSteve French 
213638c8a9a5SSteve French 	if (tcon->nodelete) {
213738c8a9a5SSteve French 		rc = -EACCES;
213838c8a9a5SSteve French 		cifs_put_tlink(tlink);
213938c8a9a5SSteve French 		goto rmdir_exit;
214038c8a9a5SSteve French 	}
214138c8a9a5SSteve French 
214238c8a9a5SSteve French 	rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
214338c8a9a5SSteve French 	cifs_put_tlink(tlink);
214438c8a9a5SSteve French 
214538c8a9a5SSteve French 	if (!rc) {
214638c8a9a5SSteve French 		spin_lock(&d_inode(direntry)->i_lock);
214738c8a9a5SSteve French 		i_size_write(d_inode(direntry), 0);
214838c8a9a5SSteve French 		clear_nlink(d_inode(direntry));
214938c8a9a5SSteve French 		spin_unlock(&d_inode(direntry)->i_lock);
215038c8a9a5SSteve French 	}
215138c8a9a5SSteve French 
215238c8a9a5SSteve French 	cifsInode = CIFS_I(d_inode(direntry));
215338c8a9a5SSteve French 	/* force revalidate to go get info when needed */
215438c8a9a5SSteve French 	cifsInode->time = 0;
215538c8a9a5SSteve French 
215638c8a9a5SSteve French 	cifsInode = CIFS_I(inode);
215738c8a9a5SSteve French 	/*
215838c8a9a5SSteve French 	 * Force revalidate to get parent dir info when needed since cached
215938c8a9a5SSteve French 	 * attributes are invalid now.
216038c8a9a5SSteve French 	 */
216138c8a9a5SSteve French 	cifsInode->time = 0;
216238c8a9a5SSteve French 
216394487653SJeff Layton 	inode_set_ctime_current(d_inode(direntry));
216423171df5SJeff Layton 	inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
216538c8a9a5SSteve French 
216638c8a9a5SSteve French rmdir_exit:
216738c8a9a5SSteve French 	free_dentry_path(page);
216838c8a9a5SSteve French 	free_xid(xid);
216938c8a9a5SSteve French 	return rc;
217038c8a9a5SSteve French }
217138c8a9a5SSteve French 
217238c8a9a5SSteve French static int
217338c8a9a5SSteve French cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
217438c8a9a5SSteve French 	       const char *from_path, struct dentry *to_dentry,
217538c8a9a5SSteve French 	       const char *to_path)
217638c8a9a5SSteve French {
217738c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
217838c8a9a5SSteve French 	struct tcon_link *tlink;
217938c8a9a5SSteve French 	struct cifs_tcon *tcon;
218038c8a9a5SSteve French 	struct TCP_Server_Info *server;
218138c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
218238c8a9a5SSteve French 	struct cifs_fid fid;
218338c8a9a5SSteve French 	struct cifs_open_parms oparms;
218438c8a9a5SSteve French 	int oplock;
218538c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
218638c8a9a5SSteve French 	int rc;
218738c8a9a5SSteve French 
218838c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
218938c8a9a5SSteve French 	if (IS_ERR(tlink))
219038c8a9a5SSteve French 		return PTR_ERR(tlink);
219138c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
219238c8a9a5SSteve French 	server = tcon->ses->server;
219338c8a9a5SSteve French 
219438c8a9a5SSteve French 	if (!server->ops->rename)
219538c8a9a5SSteve French 		return -ENOSYS;
219638c8a9a5SSteve French 
219738c8a9a5SSteve French 	/* try path-based rename first */
2198c586b0c7SPaulo Alcantara 	rc = server->ops->rename(xid, tcon, from_dentry,
2199c586b0c7SPaulo Alcantara 				 from_path, to_path, cifs_sb);
220038c8a9a5SSteve French 
220138c8a9a5SSteve French 	/*
220238c8a9a5SSteve French 	 * Don't bother with rename by filehandle unless file is busy and
220338c8a9a5SSteve French 	 * source. Note that cross directory moves do not work with
220438c8a9a5SSteve French 	 * rename by filehandle to various Windows servers.
220538c8a9a5SSteve French 	 */
220638c8a9a5SSteve French 	if (rc == 0 || rc != -EBUSY)
220738c8a9a5SSteve French 		goto do_rename_exit;
220838c8a9a5SSteve French 
220938c8a9a5SSteve French 	/* Don't fall back to using SMB on SMB 2+ mount */
221038c8a9a5SSteve French 	if (server->vals->protocol_id != 0)
221138c8a9a5SSteve French 		goto do_rename_exit;
221238c8a9a5SSteve French 
221338c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
221438c8a9a5SSteve French 	/* open-file renames don't work across directories */
221538c8a9a5SSteve French 	if (to_dentry->d_parent != from_dentry->d_parent)
221638c8a9a5SSteve French 		goto do_rename_exit;
221738c8a9a5SSteve French 
221838c8a9a5SSteve French 	oparms = (struct cifs_open_parms) {
221938c8a9a5SSteve French 		.tcon = tcon,
222038c8a9a5SSteve French 		.cifs_sb = cifs_sb,
222138c8a9a5SSteve French 		/* open the file to be renamed -- we need DELETE perms */
222238c8a9a5SSteve French 		.desired_access = DELETE,
222338c8a9a5SSteve French 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
222438c8a9a5SSteve French 		.disposition = FILE_OPEN,
222538c8a9a5SSteve French 		.path = from_path,
222638c8a9a5SSteve French 		.fid = &fid,
222738c8a9a5SSteve French 	};
222838c8a9a5SSteve French 
222938c8a9a5SSteve French 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
223038c8a9a5SSteve French 	if (rc == 0) {
223138c8a9a5SSteve French 		rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid,
223238c8a9a5SSteve French 				(const char *) to_dentry->d_name.name,
223338c8a9a5SSteve French 				cifs_sb->local_nls, cifs_remap(cifs_sb));
223438c8a9a5SSteve French 		CIFSSMBClose(xid, tcon, fid.netfid);
223538c8a9a5SSteve French 	}
223638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
223738c8a9a5SSteve French do_rename_exit:
223838c8a9a5SSteve French 	if (rc == 0)
223938c8a9a5SSteve French 		d_move(from_dentry, to_dentry);
224038c8a9a5SSteve French 	cifs_put_tlink(tlink);
224138c8a9a5SSteve French 	return rc;
224238c8a9a5SSteve French }
224338c8a9a5SSteve French 
224438c8a9a5SSteve French int
224538c8a9a5SSteve French cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
224638c8a9a5SSteve French 	     struct dentry *source_dentry, struct inode *target_dir,
224738c8a9a5SSteve French 	     struct dentry *target_dentry, unsigned int flags)
224838c8a9a5SSteve French {
224938c8a9a5SSteve French 	const char *from_name, *to_name;
225038c8a9a5SSteve French 	void *page1, *page2;
225138c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb;
225238c8a9a5SSteve French 	struct tcon_link *tlink;
225338c8a9a5SSteve French 	struct cifs_tcon *tcon;
225438c8a9a5SSteve French 	unsigned int xid;
225538c8a9a5SSteve French 	int rc, tmprc;
225638c8a9a5SSteve French 	int retry_count = 0;
225738c8a9a5SSteve French 	FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
225838c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
225938c8a9a5SSteve French 	FILE_UNIX_BASIC_INFO *info_buf_target;
226038c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
226138c8a9a5SSteve French 
226238c8a9a5SSteve French 	if (flags & ~RENAME_NOREPLACE)
226338c8a9a5SSteve French 		return -EINVAL;
226438c8a9a5SSteve French 
226538c8a9a5SSteve French 	cifs_sb = CIFS_SB(source_dir->i_sb);
226638c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
226738c8a9a5SSteve French 		return -EIO;
226838c8a9a5SSteve French 
226938c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
227038c8a9a5SSteve French 	if (IS_ERR(tlink))
227138c8a9a5SSteve French 		return PTR_ERR(tlink);
227238c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
227338c8a9a5SSteve French 
227438c8a9a5SSteve French 	page1 = alloc_dentry_path();
227538c8a9a5SSteve French 	page2 = alloc_dentry_path();
227638c8a9a5SSteve French 	xid = get_xid();
227738c8a9a5SSteve French 
227838c8a9a5SSteve French 	from_name = build_path_from_dentry(source_dentry, page1);
227938c8a9a5SSteve French 	if (IS_ERR(from_name)) {
228038c8a9a5SSteve French 		rc = PTR_ERR(from_name);
228138c8a9a5SSteve French 		goto cifs_rename_exit;
228238c8a9a5SSteve French 	}
228338c8a9a5SSteve French 
228438c8a9a5SSteve French 	to_name = build_path_from_dentry(target_dentry, page2);
228538c8a9a5SSteve French 	if (IS_ERR(to_name)) {
228638c8a9a5SSteve French 		rc = PTR_ERR(to_name);
228738c8a9a5SSteve French 		goto cifs_rename_exit;
228838c8a9a5SSteve French 	}
228938c8a9a5SSteve French 
229038c8a9a5SSteve French 	cifs_close_deferred_file_under_dentry(tcon, from_name);
229138c8a9a5SSteve French 	if (d_inode(target_dentry) != NULL)
229238c8a9a5SSteve French 		cifs_close_deferred_file_under_dentry(tcon, to_name);
229338c8a9a5SSteve French 
229438c8a9a5SSteve French 	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
229538c8a9a5SSteve French 			    to_name);
229638c8a9a5SSteve French 
229738c8a9a5SSteve French 	if (rc == -EACCES) {
229838c8a9a5SSteve French 		while (retry_count < 3) {
229938c8a9a5SSteve French 			cifs_close_all_deferred_files(tcon);
230038c8a9a5SSteve French 			rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
230138c8a9a5SSteve French 					    to_name);
230238c8a9a5SSteve French 			if (rc != -EACCES)
230338c8a9a5SSteve French 				break;
230438c8a9a5SSteve French 			retry_count++;
230538c8a9a5SSteve French 		}
230638c8a9a5SSteve French 	}
230738c8a9a5SSteve French 
230838c8a9a5SSteve French 	/*
230938c8a9a5SSteve French 	 * No-replace is the natural behavior for CIFS, so skip unlink hacks.
231038c8a9a5SSteve French 	 */
231138c8a9a5SSteve French 	if (flags & RENAME_NOREPLACE)
231238c8a9a5SSteve French 		goto cifs_rename_exit;
231338c8a9a5SSteve French 
231438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
231538c8a9a5SSteve French 	if (rc == -EEXIST && tcon->unix_ext) {
231638c8a9a5SSteve French 		/*
231738c8a9a5SSteve French 		 * Are src and dst hardlinks of same inode? We can only tell
231838c8a9a5SSteve French 		 * with unix extensions enabled.
231938c8a9a5SSteve French 		 */
232038c8a9a5SSteve French 		info_buf_source =
232138c8a9a5SSteve French 			kmalloc_array(2, sizeof(FILE_UNIX_BASIC_INFO),
232238c8a9a5SSteve French 					GFP_KERNEL);
232338c8a9a5SSteve French 		if (info_buf_source == NULL) {
232438c8a9a5SSteve French 			rc = -ENOMEM;
232538c8a9a5SSteve French 			goto cifs_rename_exit;
232638c8a9a5SSteve French 		}
232738c8a9a5SSteve French 
232838c8a9a5SSteve French 		info_buf_target = info_buf_source + 1;
232938c8a9a5SSteve French 		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
233038c8a9a5SSteve French 					     info_buf_source,
233138c8a9a5SSteve French 					     cifs_sb->local_nls,
233238c8a9a5SSteve French 					     cifs_remap(cifs_sb));
233338c8a9a5SSteve French 		if (tmprc != 0)
233438c8a9a5SSteve French 			goto unlink_target;
233538c8a9a5SSteve French 
233638c8a9a5SSteve French 		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
233738c8a9a5SSteve French 					     info_buf_target,
233838c8a9a5SSteve French 					     cifs_sb->local_nls,
233938c8a9a5SSteve French 					     cifs_remap(cifs_sb));
234038c8a9a5SSteve French 
234138c8a9a5SSteve French 		if (tmprc == 0 && (info_buf_source->UniqueId ==
234238c8a9a5SSteve French 				   info_buf_target->UniqueId)) {
234338c8a9a5SSteve French 			/* same file, POSIX says that this is a noop */
234438c8a9a5SSteve French 			rc = 0;
234538c8a9a5SSteve French 			goto cifs_rename_exit;
234638c8a9a5SSteve French 		}
234738c8a9a5SSteve French 	}
234838c8a9a5SSteve French 	/*
234938c8a9a5SSteve French 	 * else ... BB we could add the same check for Windows by
235038c8a9a5SSteve French 	 * checking the UniqueId via FILE_INTERNAL_INFO
235138c8a9a5SSteve French 	 */
235238c8a9a5SSteve French 
235338c8a9a5SSteve French unlink_target:
235438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
235538c8a9a5SSteve French 
235638c8a9a5SSteve French 	/* Try unlinking the target dentry if it's not negative */
235738c8a9a5SSteve French 	if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) {
235838c8a9a5SSteve French 		if (d_is_dir(target_dentry))
235938c8a9a5SSteve French 			tmprc = cifs_rmdir(target_dir, target_dentry);
236038c8a9a5SSteve French 		else
236138c8a9a5SSteve French 			tmprc = cifs_unlink(target_dir, target_dentry);
236238c8a9a5SSteve French 		if (tmprc)
236338c8a9a5SSteve French 			goto cifs_rename_exit;
236438c8a9a5SSteve French 		rc = cifs_do_rename(xid, source_dentry, from_name,
236538c8a9a5SSteve French 				    target_dentry, to_name);
236638c8a9a5SSteve French 	}
236738c8a9a5SSteve French 
236838c8a9a5SSteve French 	/* force revalidate to go get info when needed */
236938c8a9a5SSteve French 	CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
237038c8a9a5SSteve French 
237138c8a9a5SSteve French cifs_rename_exit:
237238c8a9a5SSteve French 	kfree(info_buf_source);
237338c8a9a5SSteve French 	free_dentry_path(page2);
237438c8a9a5SSteve French 	free_dentry_path(page1);
237538c8a9a5SSteve French 	free_xid(xid);
237638c8a9a5SSteve French 	cifs_put_tlink(tlink);
237738c8a9a5SSteve French 	return rc;
237838c8a9a5SSteve French }
237938c8a9a5SSteve French 
238038c8a9a5SSteve French static bool
238138c8a9a5SSteve French cifs_dentry_needs_reval(struct dentry *dentry)
238238c8a9a5SSteve French {
238338c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
238438c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
238538c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
238638c8a9a5SSteve French 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
238738c8a9a5SSteve French 	struct cached_fid *cfid = NULL;
238838c8a9a5SSteve French 
238938c8a9a5SSteve French 	if (cifs_i->time == 0)
239038c8a9a5SSteve French 		return true;
239138c8a9a5SSteve French 
239238c8a9a5SSteve French 	if (CIFS_CACHE_READ(cifs_i))
239338c8a9a5SSteve French 		return false;
239438c8a9a5SSteve French 
239538c8a9a5SSteve French 	if (!lookupCacheEnabled)
239638c8a9a5SSteve French 		return true;
239738c8a9a5SSteve French 
239838c8a9a5SSteve French 	if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) {
239938c8a9a5SSteve French 		spin_lock(&cfid->fid_lock);
240038c8a9a5SSteve French 		if (cfid->time && cifs_i->time > cfid->time) {
240138c8a9a5SSteve French 			spin_unlock(&cfid->fid_lock);
240238c8a9a5SSteve French 			close_cached_dir(cfid);
240338c8a9a5SSteve French 			return false;
240438c8a9a5SSteve French 		}
240538c8a9a5SSteve French 		spin_unlock(&cfid->fid_lock);
240638c8a9a5SSteve French 		close_cached_dir(cfid);
240738c8a9a5SSteve French 	}
240838c8a9a5SSteve French 	/*
240938c8a9a5SSteve French 	 * depending on inode type, check if attribute caching disabled for
241038c8a9a5SSteve French 	 * files or directories
241138c8a9a5SSteve French 	 */
241238c8a9a5SSteve French 	if (S_ISDIR(inode->i_mode)) {
241338c8a9a5SSteve French 		if (!cifs_sb->ctx->acdirmax)
241438c8a9a5SSteve French 			return true;
241538c8a9a5SSteve French 		if (!time_in_range(jiffies, cifs_i->time,
241638c8a9a5SSteve French 				   cifs_i->time + cifs_sb->ctx->acdirmax))
241738c8a9a5SSteve French 			return true;
241838c8a9a5SSteve French 	} else { /* file */
241938c8a9a5SSteve French 		if (!cifs_sb->ctx->acregmax)
242038c8a9a5SSteve French 			return true;
242138c8a9a5SSteve French 		if (!time_in_range(jiffies, cifs_i->time,
242238c8a9a5SSteve French 				   cifs_i->time + cifs_sb->ctx->acregmax))
242338c8a9a5SSteve French 			return true;
242438c8a9a5SSteve French 	}
242538c8a9a5SSteve French 
242638c8a9a5SSteve French 	/* hardlinked files w/ noserverino get "special" treatment */
242738c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
242838c8a9a5SSteve French 	    S_ISREG(inode->i_mode) && inode->i_nlink != 1)
242938c8a9a5SSteve French 		return true;
243038c8a9a5SSteve French 
243138c8a9a5SSteve French 	return false;
243238c8a9a5SSteve French }
243338c8a9a5SSteve French 
243438c8a9a5SSteve French /*
243538c8a9a5SSteve French  * Zap the cache. Called when invalid_mapping flag is set.
243638c8a9a5SSteve French  */
243738c8a9a5SSteve French int
243838c8a9a5SSteve French cifs_invalidate_mapping(struct inode *inode)
243938c8a9a5SSteve French {
244038c8a9a5SSteve French 	int rc = 0;
244138c8a9a5SSteve French 
244238c8a9a5SSteve French 	if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
244338c8a9a5SSteve French 		rc = invalidate_inode_pages2(inode->i_mapping);
244438c8a9a5SSteve French 		if (rc)
2445acf35d79SSteve French 			cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n",
2446acf35d79SSteve French 				 __func__, inode, rc);
244738c8a9a5SSteve French 	}
244838c8a9a5SSteve French 
244938c8a9a5SSteve French 	return rc;
245038c8a9a5SSteve French }
245138c8a9a5SSteve French 
245238c8a9a5SSteve French /**
245338c8a9a5SSteve French  * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks
245438c8a9a5SSteve French  *
245538c8a9a5SSteve French  * @key:	currently unused
245638c8a9a5SSteve French  * @mode:	the task state to sleep in
245738c8a9a5SSteve French  */
245838c8a9a5SSteve French static int
245938c8a9a5SSteve French cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
246038c8a9a5SSteve French {
246138c8a9a5SSteve French 	schedule();
246238c8a9a5SSteve French 	if (signal_pending_state(mode, current))
246338c8a9a5SSteve French 		return -ERESTARTSYS;
246438c8a9a5SSteve French 	return 0;
246538c8a9a5SSteve French }
246638c8a9a5SSteve French 
246738c8a9a5SSteve French int
246838c8a9a5SSteve French cifs_revalidate_mapping(struct inode *inode)
246938c8a9a5SSteve French {
247038c8a9a5SSteve French 	int rc;
247138c8a9a5SSteve French 	unsigned long *flags = &CIFS_I(inode)->flags;
247238c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
247338c8a9a5SSteve French 
247438c8a9a5SSteve French 	/* swapfiles are not supposed to be shared */
247538c8a9a5SSteve French 	if (IS_SWAPFILE(inode))
247638c8a9a5SSteve French 		return 0;
247738c8a9a5SSteve French 
247838c8a9a5SSteve French 	rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable,
247938c8a9a5SSteve French 				     TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
248038c8a9a5SSteve French 	if (rc)
248138c8a9a5SSteve French 		return rc;
248238c8a9a5SSteve French 
248338c8a9a5SSteve French 	if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) {
248438c8a9a5SSteve French 		/* for cache=singleclient, do not invalidate */
248538c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
248638c8a9a5SSteve French 			goto skip_invalidate;
248738c8a9a5SSteve French 
248838c8a9a5SSteve French 		rc = cifs_invalidate_mapping(inode);
248938c8a9a5SSteve French 		if (rc)
249038c8a9a5SSteve French 			set_bit(CIFS_INO_INVALID_MAPPING, flags);
249138c8a9a5SSteve French 	}
249238c8a9a5SSteve French 
249338c8a9a5SSteve French skip_invalidate:
249438c8a9a5SSteve French 	clear_bit_unlock(CIFS_INO_LOCK, flags);
249538c8a9a5SSteve French 	smp_mb__after_atomic();
249638c8a9a5SSteve French 	wake_up_bit(flags, CIFS_INO_LOCK);
249738c8a9a5SSteve French 
249838c8a9a5SSteve French 	return rc;
249938c8a9a5SSteve French }
250038c8a9a5SSteve French 
250138c8a9a5SSteve French int
250238c8a9a5SSteve French cifs_zap_mapping(struct inode *inode)
250338c8a9a5SSteve French {
250438c8a9a5SSteve French 	set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags);
250538c8a9a5SSteve French 	return cifs_revalidate_mapping(inode);
250638c8a9a5SSteve French }
250738c8a9a5SSteve French 
250838c8a9a5SSteve French int cifs_revalidate_file_attr(struct file *filp)
250938c8a9a5SSteve French {
251038c8a9a5SSteve French 	int rc = 0;
251138c8a9a5SSteve French 	struct dentry *dentry = file_dentry(filp);
251238c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
251338c8a9a5SSteve French 	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
251438c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
251538c8a9a5SSteve French 
251638c8a9a5SSteve French 	if (!cifs_dentry_needs_reval(dentry))
251738c8a9a5SSteve French 		return rc;
251838c8a9a5SSteve French 
251938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
252038c8a9a5SSteve French 	if (tlink_tcon(cfile->tlink)->unix_ext)
252138c8a9a5SSteve French 		rc = cifs_get_file_info_unix(filp);
252238c8a9a5SSteve French 	else
252338c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
252438c8a9a5SSteve French 		rc = cifs_get_file_info(filp);
252538c8a9a5SSteve French 
252638c8a9a5SSteve French 	return rc;
252738c8a9a5SSteve French }
252838c8a9a5SSteve French 
252938c8a9a5SSteve French int cifs_revalidate_dentry_attr(struct dentry *dentry)
253038c8a9a5SSteve French {
253138c8a9a5SSteve French 	unsigned int xid;
253238c8a9a5SSteve French 	int rc = 0;
253338c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
253438c8a9a5SSteve French 	struct super_block *sb = dentry->d_sb;
253538c8a9a5SSteve French 	const char *full_path;
253638c8a9a5SSteve French 	void *page;
253738c8a9a5SSteve French 	int count = 0;
253838c8a9a5SSteve French 
253938c8a9a5SSteve French 	if (inode == NULL)
254038c8a9a5SSteve French 		return -ENOENT;
254138c8a9a5SSteve French 
254238c8a9a5SSteve French 	if (!cifs_dentry_needs_reval(dentry))
254338c8a9a5SSteve French 		return rc;
254438c8a9a5SSteve French 
254538c8a9a5SSteve French 	xid = get_xid();
254638c8a9a5SSteve French 
254738c8a9a5SSteve French 	page = alloc_dentry_path();
254838c8a9a5SSteve French 	full_path = build_path_from_dentry(dentry, page);
254938c8a9a5SSteve French 	if (IS_ERR(full_path)) {
255038c8a9a5SSteve French 		rc = PTR_ERR(full_path);
255138c8a9a5SSteve French 		goto out;
255238c8a9a5SSteve French 	}
255338c8a9a5SSteve French 
255438c8a9a5SSteve French 	cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
255538c8a9a5SSteve French 		 full_path, inode, inode->i_count.counter,
255638c8a9a5SSteve French 		 dentry, cifs_get_time(dentry), jiffies);
255738c8a9a5SSteve French 
255838c8a9a5SSteve French again:
255902bcf865SSteve French 	if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) {
256002bcf865SSteve French 		rc = smb311_posix_get_inode_info(&inode, full_path,
256102bcf865SSteve French 						 NULL, sb, xid);
256202bcf865SSteve French 	} else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) {
256338c8a9a5SSteve French 		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
256402bcf865SSteve French 	} else {
256538c8a9a5SSteve French 		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
256638c8a9a5SSteve French 					 xid, NULL);
256702bcf865SSteve French 	}
256838c8a9a5SSteve French 	if (rc == -EAGAIN && count++ < 10)
256938c8a9a5SSteve French 		goto again;
257038c8a9a5SSteve French out:
257138c8a9a5SSteve French 	free_dentry_path(page);
257238c8a9a5SSteve French 	free_xid(xid);
257338c8a9a5SSteve French 
257438c8a9a5SSteve French 	return rc;
257538c8a9a5SSteve French }
257638c8a9a5SSteve French 
257738c8a9a5SSteve French int cifs_revalidate_file(struct file *filp)
257838c8a9a5SSteve French {
257938c8a9a5SSteve French 	int rc;
258038c8a9a5SSteve French 	struct inode *inode = file_inode(filp);
258138c8a9a5SSteve French 
258238c8a9a5SSteve French 	rc = cifs_revalidate_file_attr(filp);
258338c8a9a5SSteve French 	if (rc)
258438c8a9a5SSteve French 		return rc;
258538c8a9a5SSteve French 
258638c8a9a5SSteve French 	return cifs_revalidate_mapping(inode);
258738c8a9a5SSteve French }
258838c8a9a5SSteve French 
258938c8a9a5SSteve French /* revalidate a dentry's inode attributes */
259038c8a9a5SSteve French int cifs_revalidate_dentry(struct dentry *dentry)
259138c8a9a5SSteve French {
259238c8a9a5SSteve French 	int rc;
259338c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
259438c8a9a5SSteve French 
259538c8a9a5SSteve French 	rc = cifs_revalidate_dentry_attr(dentry);
259638c8a9a5SSteve French 	if (rc)
259738c8a9a5SSteve French 		return rc;
259838c8a9a5SSteve French 
259938c8a9a5SSteve French 	return cifs_revalidate_mapping(inode);
260038c8a9a5SSteve French }
260138c8a9a5SSteve French 
260238c8a9a5SSteve French int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
260338c8a9a5SSteve French 		 struct kstat *stat, u32 request_mask, unsigned int flags)
260438c8a9a5SSteve French {
260538c8a9a5SSteve French 	struct dentry *dentry = path->dentry;
260638c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
260738c8a9a5SSteve French 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
260838c8a9a5SSteve French 	struct inode *inode = d_inode(dentry);
260938c8a9a5SSteve French 	int rc;
261038c8a9a5SSteve French 
261138c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
261238c8a9a5SSteve French 		return -EIO;
261338c8a9a5SSteve French 
261438c8a9a5SSteve French 	/*
261538c8a9a5SSteve French 	 * We need to be sure that all dirty pages are written and the server
261638c8a9a5SSteve French 	 * has actual ctime, mtime and file length.
261738c8a9a5SSteve French 	 */
261838c8a9a5SSteve French 	if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) &&
261938c8a9a5SSteve French 	    !CIFS_CACHE_READ(CIFS_I(inode)) &&
262038c8a9a5SSteve French 	    inode->i_mapping && inode->i_mapping->nrpages != 0) {
262138c8a9a5SSteve French 		rc = filemap_fdatawait(inode->i_mapping);
262238c8a9a5SSteve French 		if (rc) {
262338c8a9a5SSteve French 			mapping_set_error(inode->i_mapping, rc);
262438c8a9a5SSteve French 			return rc;
262538c8a9a5SSteve French 		}
262638c8a9a5SSteve French 	}
262738c8a9a5SSteve French 
262838c8a9a5SSteve French 	if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC)
262938c8a9a5SSteve French 		CIFS_I(inode)->time = 0; /* force revalidate */
263038c8a9a5SSteve French 
263138c8a9a5SSteve French 	/*
263238c8a9a5SSteve French 	 * If the caller doesn't require syncing, only sync if
263338c8a9a5SSteve French 	 * necessary (e.g. due to earlier truncate or setattr
263438c8a9a5SSteve French 	 * invalidating the cached metadata)
263538c8a9a5SSteve French 	 */
263638c8a9a5SSteve French 	if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) ||
263738c8a9a5SSteve French 	    (CIFS_I(inode)->time == 0)) {
263838c8a9a5SSteve French 		rc = cifs_revalidate_dentry_attr(dentry);
263938c8a9a5SSteve French 		if (rc)
264038c8a9a5SSteve French 			return rc;
264138c8a9a5SSteve French 	}
264238c8a9a5SSteve French 
26430d72b928SJeff Layton 	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
264438c8a9a5SSteve French 	stat->blksize = cifs_sb->ctx->bsize;
264538c8a9a5SSteve French 	stat->ino = CIFS_I(inode)->uniqueid;
264638c8a9a5SSteve French 
264738c8a9a5SSteve French 	/* old CIFS Unix Extensions doesn't return create time */
264838c8a9a5SSteve French 	if (CIFS_I(inode)->createtime) {
264938c8a9a5SSteve French 		stat->result_mask |= STATX_BTIME;
265038c8a9a5SSteve French 		stat->btime =
265138c8a9a5SSteve French 		      cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime));
265238c8a9a5SSteve French 	}
265338c8a9a5SSteve French 
265438c8a9a5SSteve French 	stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED);
265538c8a9a5SSteve French 	if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED)
265638c8a9a5SSteve French 		stat->attributes |= STATX_ATTR_COMPRESSED;
265738c8a9a5SSteve French 	if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED)
265838c8a9a5SSteve French 		stat->attributes |= STATX_ATTR_ENCRYPTED;
265938c8a9a5SSteve French 
266038c8a9a5SSteve French 	/*
266138c8a9a5SSteve French 	 * If on a multiuser mount without unix extensions or cifsacl being
266238c8a9a5SSteve French 	 * enabled, and the admin hasn't overridden them, set the ownership
266338c8a9a5SSteve French 	 * to the fsuid/fsgid of the current process.
266438c8a9a5SSteve French 	 */
266538c8a9a5SSteve French 	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
266638c8a9a5SSteve French 	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
266738c8a9a5SSteve French 	    !tcon->unix_ext) {
266838c8a9a5SSteve French 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
266938c8a9a5SSteve French 			stat->uid = current_fsuid();
267038c8a9a5SSteve French 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
267138c8a9a5SSteve French 			stat->gid = current_fsgid();
267238c8a9a5SSteve French 	}
267338c8a9a5SSteve French 	return 0;
267438c8a9a5SSteve French }
267538c8a9a5SSteve French 
267638c8a9a5SSteve French int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
267738c8a9a5SSteve French 		u64 len)
267838c8a9a5SSteve French {
267938c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
268038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->netfs.inode.i_sb);
268138c8a9a5SSteve French 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
268238c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
268338c8a9a5SSteve French 	struct cifsFileInfo *cfile;
268438c8a9a5SSteve French 	int rc;
268538c8a9a5SSteve French 
268638c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
268738c8a9a5SSteve French 		return -EIO;
268838c8a9a5SSteve French 
268938c8a9a5SSteve French 	/*
269038c8a9a5SSteve French 	 * We need to be sure that all dirty pages are written as they
269138c8a9a5SSteve French 	 * might fill holes on the server.
269238c8a9a5SSteve French 	 */
269338c8a9a5SSteve French 	if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
269438c8a9a5SSteve French 	    inode->i_mapping->nrpages != 0) {
269538c8a9a5SSteve French 		rc = filemap_fdatawait(inode->i_mapping);
269638c8a9a5SSteve French 		if (rc) {
269738c8a9a5SSteve French 			mapping_set_error(inode->i_mapping, rc);
269838c8a9a5SSteve French 			return rc;
269938c8a9a5SSteve French 		}
270038c8a9a5SSteve French 	}
270138c8a9a5SSteve French 
270238c8a9a5SSteve French 	cfile = find_readable_file(cifs_i, false);
270338c8a9a5SSteve French 	if (cfile == NULL)
270438c8a9a5SSteve French 		return -EINVAL;
270538c8a9a5SSteve French 
270638c8a9a5SSteve French 	if (server->ops->fiemap) {
270738c8a9a5SSteve French 		rc = server->ops->fiemap(tcon, cfile, fei, start, len);
270838c8a9a5SSteve French 		cifsFileInfo_put(cfile);
270938c8a9a5SSteve French 		return rc;
271038c8a9a5SSteve French 	}
271138c8a9a5SSteve French 
271238c8a9a5SSteve French 	cifsFileInfo_put(cfile);
2713ebc3d4e4SSteve French 	return -EOPNOTSUPP;
271438c8a9a5SSteve French }
271538c8a9a5SSteve French 
271638c8a9a5SSteve French int cifs_truncate_page(struct address_space *mapping, loff_t from)
271738c8a9a5SSteve French {
271838c8a9a5SSteve French 	pgoff_t index = from >> PAGE_SHIFT;
271938c8a9a5SSteve French 	unsigned offset = from & (PAGE_SIZE - 1);
272038c8a9a5SSteve French 	struct page *page;
272138c8a9a5SSteve French 	int rc = 0;
272238c8a9a5SSteve French 
272338c8a9a5SSteve French 	page = grab_cache_page(mapping, index);
272438c8a9a5SSteve French 	if (!page)
272538c8a9a5SSteve French 		return -ENOMEM;
272638c8a9a5SSteve French 
272738c8a9a5SSteve French 	zero_user_segment(page, offset, PAGE_SIZE);
272838c8a9a5SSteve French 	unlock_page(page);
272938c8a9a5SSteve French 	put_page(page);
273038c8a9a5SSteve French 	return rc;
273138c8a9a5SSteve French }
273238c8a9a5SSteve French 
273338c8a9a5SSteve French void cifs_setsize(struct inode *inode, loff_t offset)
273438c8a9a5SSteve French {
273538c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
273638c8a9a5SSteve French 
273738c8a9a5SSteve French 	spin_lock(&inode->i_lock);
273838c8a9a5SSteve French 	i_size_write(inode, offset);
273938c8a9a5SSteve French 	spin_unlock(&inode->i_lock);
274038c8a9a5SSteve French 
274138c8a9a5SSteve French 	/* Cached inode must be refreshed on truncate */
274238c8a9a5SSteve French 	cifs_i->time = 0;
274338c8a9a5SSteve French 	truncate_pagecache(inode, offset);
274438c8a9a5SSteve French }
274538c8a9a5SSteve French 
274638c8a9a5SSteve French static int
274738c8a9a5SSteve French cifs_set_file_size(struct inode *inode, struct iattr *attrs,
2748f93d145fSMeetakshi Setiya 		   unsigned int xid, const char *full_path, struct dentry *dentry)
274938c8a9a5SSteve French {
275038c8a9a5SSteve French 	int rc;
275138c8a9a5SSteve French 	struct cifsFileInfo *open_file;
275238c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
275338c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
275438c8a9a5SSteve French 	struct tcon_link *tlink = NULL;
275538c8a9a5SSteve French 	struct cifs_tcon *tcon = NULL;
275638c8a9a5SSteve French 	struct TCP_Server_Info *server;
275738c8a9a5SSteve French 
275838c8a9a5SSteve French 	/*
275938c8a9a5SSteve French 	 * To avoid spurious oplock breaks from server, in the case of
276038c8a9a5SSteve French 	 * inodes that we already have open, avoid doing path based
276138c8a9a5SSteve French 	 * setting of file size if we can do it by handle.
276238c8a9a5SSteve French 	 * This keeps our caching token (oplock) and avoids timeouts
276338c8a9a5SSteve French 	 * when the local oplock break takes longer to flush
276438c8a9a5SSteve French 	 * writebehind data than the SMB timeout for the SetPathInfo
276538c8a9a5SSteve French 	 * request would allow
276638c8a9a5SSteve French 	 */
276738c8a9a5SSteve French 	open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
276838c8a9a5SSteve French 	if (open_file) {
276938c8a9a5SSteve French 		tcon = tlink_tcon(open_file->tlink);
277038c8a9a5SSteve French 		server = tcon->ses->server;
277138c8a9a5SSteve French 		if (server->ops->set_file_size)
277238c8a9a5SSteve French 			rc = server->ops->set_file_size(xid, tcon, open_file,
277338c8a9a5SSteve French 							attrs->ia_size, false);
277438c8a9a5SSteve French 		else
277538c8a9a5SSteve French 			rc = -ENOSYS;
277638c8a9a5SSteve French 		cifsFileInfo_put(open_file);
277738c8a9a5SSteve French 		cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc);
277838c8a9a5SSteve French 	} else
277938c8a9a5SSteve French 		rc = -EINVAL;
278038c8a9a5SSteve French 
278138c8a9a5SSteve French 	if (!rc)
278238c8a9a5SSteve French 		goto set_size_out;
278338c8a9a5SSteve French 
278438c8a9a5SSteve French 	if (tcon == NULL) {
278538c8a9a5SSteve French 		tlink = cifs_sb_tlink(cifs_sb);
278638c8a9a5SSteve French 		if (IS_ERR(tlink))
278738c8a9a5SSteve French 			return PTR_ERR(tlink);
278838c8a9a5SSteve French 		tcon = tlink_tcon(tlink);
278938c8a9a5SSteve French 		server = tcon->ses->server;
279038c8a9a5SSteve French 	}
279138c8a9a5SSteve French 
279238c8a9a5SSteve French 	/*
279338c8a9a5SSteve French 	 * Set file size by pathname rather than by handle either because no
279438c8a9a5SSteve French 	 * valid, writeable file handle for it was found or because there was
279538c8a9a5SSteve French 	 * an error setting it by handle.
279638c8a9a5SSteve French 	 */
279738c8a9a5SSteve French 	if (server->ops->set_path_size)
279838c8a9a5SSteve French 		rc = server->ops->set_path_size(xid, tcon, full_path,
2799f93d145fSMeetakshi Setiya 						attrs->ia_size, cifs_sb, false, dentry);
280038c8a9a5SSteve French 	else
280138c8a9a5SSteve French 		rc = -ENOSYS;
280238c8a9a5SSteve French 	cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc);
280338c8a9a5SSteve French 
280438c8a9a5SSteve French 	if (tlink)
280538c8a9a5SSteve French 		cifs_put_tlink(tlink);
280638c8a9a5SSteve French 
280738c8a9a5SSteve French set_size_out:
280838c8a9a5SSteve French 	if (rc == 0) {
280938c8a9a5SSteve French 		cifsInode->server_eof = attrs->ia_size;
281038c8a9a5SSteve French 		cifs_setsize(inode, attrs->ia_size);
281138c8a9a5SSteve French 		/*
281238c8a9a5SSteve French 		 * i_blocks is not related to (i_size / i_blksize), but instead
281338c8a9a5SSteve French 		 * 512 byte (2**9) size is required for calculating num blocks.
281438c8a9a5SSteve French 		 * Until we can query the server for actual allocation size,
281538c8a9a5SSteve French 		 * this is best estimate we have for blocks allocated for a file
281638c8a9a5SSteve French 		 * Number of blocks must be rounded up so size 1 is not 0 blocks
281738c8a9a5SSteve French 		 */
281838c8a9a5SSteve French 		inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
281938c8a9a5SSteve French 
282038c8a9a5SSteve French 		/*
282138c8a9a5SSteve French 		 * The man page of truncate says if the size changed,
282238c8a9a5SSteve French 		 * then the st_ctime and st_mtime fields for the file
282338c8a9a5SSteve French 		 * are updated.
282438c8a9a5SSteve French 		 */
282538c8a9a5SSteve French 		attrs->ia_ctime = attrs->ia_mtime = current_time(inode);
282638c8a9a5SSteve French 		attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME;
282738c8a9a5SSteve French 
282838c8a9a5SSteve French 		cifs_truncate_page(inode->i_mapping, inode->i_size);
282938c8a9a5SSteve French 	}
283038c8a9a5SSteve French 
283138c8a9a5SSteve French 	return rc;
283238c8a9a5SSteve French }
283338c8a9a5SSteve French 
283438c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
283538c8a9a5SSteve French static int
283638c8a9a5SSteve French cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
283738c8a9a5SSteve French {
283838c8a9a5SSteve French 	int rc;
283938c8a9a5SSteve French 	unsigned int xid;
284038c8a9a5SSteve French 	const char *full_path;
284138c8a9a5SSteve French 	void *page = alloc_dentry_path();
284238c8a9a5SSteve French 	struct inode *inode = d_inode(direntry);
284338c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
284438c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
284538c8a9a5SSteve French 	struct tcon_link *tlink;
284638c8a9a5SSteve French 	struct cifs_tcon *pTcon;
284738c8a9a5SSteve French 	struct cifs_unix_set_info_args *args = NULL;
284838c8a9a5SSteve French 	struct cifsFileInfo *open_file;
284938c8a9a5SSteve French 
285038c8a9a5SSteve French 	cifs_dbg(FYI, "setattr_unix on file %pd attrs->ia_valid=0x%x\n",
285138c8a9a5SSteve French 		 direntry, attrs->ia_valid);
285238c8a9a5SSteve French 
285338c8a9a5SSteve French 	xid = get_xid();
285438c8a9a5SSteve French 
285538c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
285638c8a9a5SSteve French 		attrs->ia_valid |= ATTR_FORCE;
285738c8a9a5SSteve French 
285838c8a9a5SSteve French 	rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
285938c8a9a5SSteve French 	if (rc < 0)
286038c8a9a5SSteve French 		goto out;
286138c8a9a5SSteve French 
286238c8a9a5SSteve French 	full_path = build_path_from_dentry(direntry, page);
286338c8a9a5SSteve French 	if (IS_ERR(full_path)) {
286438c8a9a5SSteve French 		rc = PTR_ERR(full_path);
286538c8a9a5SSteve French 		goto out;
286638c8a9a5SSteve French 	}
286738c8a9a5SSteve French 
286838c8a9a5SSteve French 	/*
286938c8a9a5SSteve French 	 * Attempt to flush data before changing attributes. We need to do
287038c8a9a5SSteve French 	 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
287138c8a9a5SSteve French 	 * ownership or mode then we may also need to do this. Here, we take
287238c8a9a5SSteve French 	 * the safe way out and just do the flush on all setattr requests. If
287338c8a9a5SSteve French 	 * the flush returns error, store it to report later and continue.
287438c8a9a5SSteve French 	 *
287538c8a9a5SSteve French 	 * BB: This should be smarter. Why bother flushing pages that
287638c8a9a5SSteve French 	 * will be truncated anyway? Also, should we error out here if
287738c8a9a5SSteve French 	 * the flush returns error?
287838c8a9a5SSteve French 	 */
287938c8a9a5SSteve French 	rc = filemap_write_and_wait(inode->i_mapping);
288038c8a9a5SSteve French 	if (is_interrupt_error(rc)) {
288138c8a9a5SSteve French 		rc = -ERESTARTSYS;
288238c8a9a5SSteve French 		goto out;
288338c8a9a5SSteve French 	}
288438c8a9a5SSteve French 
288538c8a9a5SSteve French 	mapping_set_error(inode->i_mapping, rc);
288638c8a9a5SSteve French 	rc = 0;
288738c8a9a5SSteve French 
288838c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_SIZE) {
2889f93d145fSMeetakshi Setiya 		rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
289038c8a9a5SSteve French 		if (rc != 0)
289138c8a9a5SSteve French 			goto out;
289238c8a9a5SSteve French 	}
289338c8a9a5SSteve French 
289438c8a9a5SSteve French 	/* skip mode change if it's just for clearing setuid/setgid */
289538c8a9a5SSteve French 	if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
289638c8a9a5SSteve French 		attrs->ia_valid &= ~ATTR_MODE;
289738c8a9a5SSteve French 
289838c8a9a5SSteve French 	args = kmalloc(sizeof(*args), GFP_KERNEL);
289938c8a9a5SSteve French 	if (args == NULL) {
290038c8a9a5SSteve French 		rc = -ENOMEM;
290138c8a9a5SSteve French 		goto out;
290238c8a9a5SSteve French 	}
290338c8a9a5SSteve French 
290438c8a9a5SSteve French 	/* set up the struct */
290538c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_MODE)
290638c8a9a5SSteve French 		args->mode = attrs->ia_mode;
290738c8a9a5SSteve French 	else
290838c8a9a5SSteve French 		args->mode = NO_CHANGE_64;
290938c8a9a5SSteve French 
291038c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_UID)
291138c8a9a5SSteve French 		args->uid = attrs->ia_uid;
291238c8a9a5SSteve French 	else
291338c8a9a5SSteve French 		args->uid = INVALID_UID; /* no change */
291438c8a9a5SSteve French 
291538c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_GID)
291638c8a9a5SSteve French 		args->gid = attrs->ia_gid;
291738c8a9a5SSteve French 	else
291838c8a9a5SSteve French 		args->gid = INVALID_GID; /* no change */
291938c8a9a5SSteve French 
292038c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_ATIME)
292138c8a9a5SSteve French 		args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
292238c8a9a5SSteve French 	else
292338c8a9a5SSteve French 		args->atime = NO_CHANGE_64;
292438c8a9a5SSteve French 
292538c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_MTIME)
292638c8a9a5SSteve French 		args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
292738c8a9a5SSteve French 	else
292838c8a9a5SSteve French 		args->mtime = NO_CHANGE_64;
292938c8a9a5SSteve French 
293038c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_CTIME)
293138c8a9a5SSteve French 		args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
293238c8a9a5SSteve French 	else
293338c8a9a5SSteve French 		args->ctime = NO_CHANGE_64;
293438c8a9a5SSteve French 
293538c8a9a5SSteve French 	args->device = 0;
293638c8a9a5SSteve French 	open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
293738c8a9a5SSteve French 	if (open_file) {
293838c8a9a5SSteve French 		u16 nfid = open_file->fid.netfid;
293938c8a9a5SSteve French 		u32 npid = open_file->pid;
294038c8a9a5SSteve French 		pTcon = tlink_tcon(open_file->tlink);
294138c8a9a5SSteve French 		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
294238c8a9a5SSteve French 		cifsFileInfo_put(open_file);
294338c8a9a5SSteve French 	} else {
294438c8a9a5SSteve French 		tlink = cifs_sb_tlink(cifs_sb);
294538c8a9a5SSteve French 		if (IS_ERR(tlink)) {
294638c8a9a5SSteve French 			rc = PTR_ERR(tlink);
294738c8a9a5SSteve French 			goto out;
294838c8a9a5SSteve French 		}
294938c8a9a5SSteve French 		pTcon = tlink_tcon(tlink);
295038c8a9a5SSteve French 		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
295138c8a9a5SSteve French 				    cifs_sb->local_nls,
295238c8a9a5SSteve French 				    cifs_remap(cifs_sb));
295338c8a9a5SSteve French 		cifs_put_tlink(tlink);
295438c8a9a5SSteve French 	}
295538c8a9a5SSteve French 
295638c8a9a5SSteve French 	if (rc)
295738c8a9a5SSteve French 		goto out;
295838c8a9a5SSteve French 
295938c8a9a5SSteve French 	if ((attrs->ia_valid & ATTR_SIZE) &&
296038c8a9a5SSteve French 	    attrs->ia_size != i_size_read(inode)) {
296138c8a9a5SSteve French 		truncate_setsize(inode, attrs->ia_size);
296238c8a9a5SSteve French 		fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
296338c8a9a5SSteve French 	}
296438c8a9a5SSteve French 
296538c8a9a5SSteve French 	setattr_copy(&nop_mnt_idmap, inode, attrs);
296638c8a9a5SSteve French 	mark_inode_dirty(inode);
296738c8a9a5SSteve French 
296838c8a9a5SSteve French 	/* force revalidate when any of these times are set since some
296938c8a9a5SSteve French 	   of the fs types (eg ext3, fat) do not have fine enough
297038c8a9a5SSteve French 	   time granularity to match protocol, and we do not have a
297138c8a9a5SSteve French 	   a way (yet) to query the server fs's time granularity (and
297238c8a9a5SSteve French 	   whether it rounds times down).
297338c8a9a5SSteve French 	*/
297438c8a9a5SSteve French 	if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
297538c8a9a5SSteve French 		cifsInode->time = 0;
297638c8a9a5SSteve French out:
297738c8a9a5SSteve French 	kfree(args);
297838c8a9a5SSteve French 	free_dentry_path(page);
297938c8a9a5SSteve French 	free_xid(xid);
298038c8a9a5SSteve French 	return rc;
298138c8a9a5SSteve French }
298238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
298338c8a9a5SSteve French 
298438c8a9a5SSteve French static int
298538c8a9a5SSteve French cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
298638c8a9a5SSteve French {
298738c8a9a5SSteve French 	unsigned int xid;
298838c8a9a5SSteve French 	kuid_t uid = INVALID_UID;
298938c8a9a5SSteve French 	kgid_t gid = INVALID_GID;
299038c8a9a5SSteve French 	struct inode *inode = d_inode(direntry);
299138c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
299238c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
299338c8a9a5SSteve French 	struct cifsFileInfo *wfile;
299438c8a9a5SSteve French 	struct cifs_tcon *tcon;
299538c8a9a5SSteve French 	const char *full_path;
299638c8a9a5SSteve French 	void *page = alloc_dentry_path();
299738c8a9a5SSteve French 	int rc = -EACCES;
299838c8a9a5SSteve French 	__u32 dosattr = 0;
299938c8a9a5SSteve French 	__u64 mode = NO_CHANGE_64;
300038c8a9a5SSteve French 
300138c8a9a5SSteve French 	xid = get_xid();
300238c8a9a5SSteve French 
300338c8a9a5SSteve French 	cifs_dbg(FYI, "setattr on file %pd attrs->ia_valid 0x%x\n",
300438c8a9a5SSteve French 		 direntry, attrs->ia_valid);
300538c8a9a5SSteve French 
300638c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
300738c8a9a5SSteve French 		attrs->ia_valid |= ATTR_FORCE;
300838c8a9a5SSteve French 
300938c8a9a5SSteve French 	rc = setattr_prepare(&nop_mnt_idmap, direntry, attrs);
301038c8a9a5SSteve French 	if (rc < 0)
301138c8a9a5SSteve French 		goto cifs_setattr_exit;
301238c8a9a5SSteve French 
301338c8a9a5SSteve French 	full_path = build_path_from_dentry(direntry, page);
301438c8a9a5SSteve French 	if (IS_ERR(full_path)) {
301538c8a9a5SSteve French 		rc = PTR_ERR(full_path);
301638c8a9a5SSteve French 		goto cifs_setattr_exit;
301738c8a9a5SSteve French 	}
301838c8a9a5SSteve French 
301938c8a9a5SSteve French 	/*
302038c8a9a5SSteve French 	 * Attempt to flush data before changing attributes. We need to do
302138c8a9a5SSteve French 	 * this for ATTR_SIZE and ATTR_MTIME.  If the flush of the data
302238c8a9a5SSteve French 	 * returns error, store it to report later and continue.
302338c8a9a5SSteve French 	 *
302438c8a9a5SSteve French 	 * BB: This should be smarter. Why bother flushing pages that
302538c8a9a5SSteve French 	 * will be truncated anyway? Also, should we error out here if
302638c8a9a5SSteve French 	 * the flush returns error? Do we need to check for ATTR_MTIME_SET flag?
302738c8a9a5SSteve French 	 */
302838c8a9a5SSteve French 	if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) {
302938c8a9a5SSteve French 		rc = filemap_write_and_wait(inode->i_mapping);
303038c8a9a5SSteve French 		if (is_interrupt_error(rc)) {
303138c8a9a5SSteve French 			rc = -ERESTARTSYS;
303238c8a9a5SSteve French 			goto cifs_setattr_exit;
303338c8a9a5SSteve French 		}
303438c8a9a5SSteve French 		mapping_set_error(inode->i_mapping, rc);
303538c8a9a5SSteve French 	}
303638c8a9a5SSteve French 
303738c8a9a5SSteve French 	rc = 0;
303838c8a9a5SSteve French 
303938c8a9a5SSteve French 	if ((attrs->ia_valid & ATTR_MTIME) &&
304038c8a9a5SSteve French 	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
304138c8a9a5SSteve French 		rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
304238c8a9a5SSteve French 		if (!rc) {
304338c8a9a5SSteve French 			tcon = tlink_tcon(wfile->tlink);
304438c8a9a5SSteve French 			rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
304538c8a9a5SSteve French 			cifsFileInfo_put(wfile);
304638c8a9a5SSteve French 			if (rc)
304738c8a9a5SSteve French 				goto cifs_setattr_exit;
304838c8a9a5SSteve French 		} else if (rc != -EBADF)
304938c8a9a5SSteve French 			goto cifs_setattr_exit;
305038c8a9a5SSteve French 		else
305138c8a9a5SSteve French 			rc = 0;
305238c8a9a5SSteve French 	}
305338c8a9a5SSteve French 
305438c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_SIZE) {
3055f93d145fSMeetakshi Setiya 		rc = cifs_set_file_size(inode, attrs, xid, full_path, direntry);
305638c8a9a5SSteve French 		if (rc != 0)
305738c8a9a5SSteve French 			goto cifs_setattr_exit;
305838c8a9a5SSteve French 	}
305938c8a9a5SSteve French 
306038c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_UID)
306138c8a9a5SSteve French 		uid = attrs->ia_uid;
306238c8a9a5SSteve French 
306338c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_GID)
306438c8a9a5SSteve French 		gid = attrs->ia_gid;
306538c8a9a5SSteve French 
306638c8a9a5SSteve French 	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
306738c8a9a5SSteve French 	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
306838c8a9a5SSteve French 		if (uid_valid(uid) || gid_valid(gid)) {
306938c8a9a5SSteve French 			mode = NO_CHANGE_64;
307038c8a9a5SSteve French 			rc = id_mode_to_cifs_acl(inode, full_path, &mode,
307138c8a9a5SSteve French 							uid, gid);
307238c8a9a5SSteve French 			if (rc) {
307338c8a9a5SSteve French 				cifs_dbg(FYI, "%s: Setting id failed with error: %d\n",
307438c8a9a5SSteve French 					 __func__, rc);
307538c8a9a5SSteve French 				goto cifs_setattr_exit;
307638c8a9a5SSteve French 			}
307738c8a9a5SSteve French 		}
307838c8a9a5SSteve French 	} else
307938c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
308038c8a9a5SSteve French 		attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
308138c8a9a5SSteve French 
308238c8a9a5SSteve French 	/* skip mode change if it's just for clearing setuid/setgid */
308338c8a9a5SSteve French 	if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
308438c8a9a5SSteve French 		attrs->ia_valid &= ~ATTR_MODE;
308538c8a9a5SSteve French 
308638c8a9a5SSteve French 	if (attrs->ia_valid & ATTR_MODE) {
308738c8a9a5SSteve French 		mode = attrs->ia_mode;
308838c8a9a5SSteve French 		rc = 0;
308938c8a9a5SSteve French 		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
309038c8a9a5SSteve French 		    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
309138c8a9a5SSteve French 			rc = id_mode_to_cifs_acl(inode, full_path, &mode,
309238c8a9a5SSteve French 						INVALID_UID, INVALID_GID);
309338c8a9a5SSteve French 			if (rc) {
309438c8a9a5SSteve French 				cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n",
309538c8a9a5SSteve French 					 __func__, rc);
309638c8a9a5SSteve French 				goto cifs_setattr_exit;
309738c8a9a5SSteve French 			}
309838c8a9a5SSteve French 
309938c8a9a5SSteve French 			/*
310038c8a9a5SSteve French 			 * In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes.
310138c8a9a5SSteve French 			 * Pick up the actual mode bits that were set.
310238c8a9a5SSteve French 			 */
310338c8a9a5SSteve French 			if (mode != attrs->ia_mode)
310438c8a9a5SSteve French 				attrs->ia_mode = mode;
310538c8a9a5SSteve French 		} else
310638c8a9a5SSteve French 		if (((mode & S_IWUGO) == 0) &&
310738c8a9a5SSteve French 		    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
310838c8a9a5SSteve French 
310938c8a9a5SSteve French 			dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
311038c8a9a5SSteve French 
311138c8a9a5SSteve French 			/* fix up mode if we're not using dynperm */
311238c8a9a5SSteve French 			if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
311338c8a9a5SSteve French 				attrs->ia_mode = inode->i_mode & ~S_IWUGO;
311438c8a9a5SSteve French 		} else if ((mode & S_IWUGO) &&
311538c8a9a5SSteve French 			   (cifsInode->cifsAttrs & ATTR_READONLY)) {
311638c8a9a5SSteve French 
311738c8a9a5SSteve French 			dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
311838c8a9a5SSteve French 			/* Attributes of 0 are ignored */
311938c8a9a5SSteve French 			if (dosattr == 0)
312038c8a9a5SSteve French 				dosattr |= ATTR_NORMAL;
312138c8a9a5SSteve French 
312238c8a9a5SSteve French 			/* reset local inode permissions to normal */
312338c8a9a5SSteve French 			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
312438c8a9a5SSteve French 				attrs->ia_mode &= ~(S_IALLUGO);
312538c8a9a5SSteve French 				if (S_ISDIR(inode->i_mode))
312638c8a9a5SSteve French 					attrs->ia_mode |=
312738c8a9a5SSteve French 						cifs_sb->ctx->dir_mode;
312838c8a9a5SSteve French 				else
312938c8a9a5SSteve French 					attrs->ia_mode |=
313038c8a9a5SSteve French 						cifs_sb->ctx->file_mode;
313138c8a9a5SSteve French 			}
313238c8a9a5SSteve French 		} else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
313338c8a9a5SSteve French 			/* ignore mode change - ATTR_READONLY hasn't changed */
313438c8a9a5SSteve French 			attrs->ia_valid &= ~ATTR_MODE;
313538c8a9a5SSteve French 		}
313638c8a9a5SSteve French 	}
313738c8a9a5SSteve French 
313838c8a9a5SSteve French 	if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
313938c8a9a5SSteve French 	    ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
314038c8a9a5SSteve French 		rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
314138c8a9a5SSteve French 		/* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
314238c8a9a5SSteve French 
314338c8a9a5SSteve French 		/* Even if error on time set, no sense failing the call if
314438c8a9a5SSteve French 		the server would set the time to a reasonable value anyway,
314538c8a9a5SSteve French 		and this check ensures that we are not being called from
314638c8a9a5SSteve French 		sys_utimes in which case we ought to fail the call back to
314738c8a9a5SSteve French 		the user when the server rejects the call */
314838c8a9a5SSteve French 		if ((rc) && (attrs->ia_valid &
314938c8a9a5SSteve French 				(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
315038c8a9a5SSteve French 			rc = 0;
315138c8a9a5SSteve French 	}
315238c8a9a5SSteve French 
315338c8a9a5SSteve French 	/* do not need local check to inode_check_ok since the server does
315438c8a9a5SSteve French 	   that */
315538c8a9a5SSteve French 	if (rc)
315638c8a9a5SSteve French 		goto cifs_setattr_exit;
315738c8a9a5SSteve French 
315838c8a9a5SSteve French 	if ((attrs->ia_valid & ATTR_SIZE) &&
315938c8a9a5SSteve French 	    attrs->ia_size != i_size_read(inode)) {
316038c8a9a5SSteve French 		truncate_setsize(inode, attrs->ia_size);
316138c8a9a5SSteve French 		fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
316238c8a9a5SSteve French 	}
316338c8a9a5SSteve French 
316438c8a9a5SSteve French 	setattr_copy(&nop_mnt_idmap, inode, attrs);
316538c8a9a5SSteve French 	mark_inode_dirty(inode);
316638c8a9a5SSteve French 
316738c8a9a5SSteve French cifs_setattr_exit:
316838c8a9a5SSteve French 	free_xid(xid);
316938c8a9a5SSteve French 	free_dentry_path(page);
317038c8a9a5SSteve French 	return rc;
317138c8a9a5SSteve French }
317238c8a9a5SSteve French 
317338c8a9a5SSteve French int
317438c8a9a5SSteve French cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
317538c8a9a5SSteve French 	     struct iattr *attrs)
317638c8a9a5SSteve French {
317738c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
317838c8a9a5SSteve French 	int rc, retries = 0;
317938c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
318038c8a9a5SSteve French 	struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
318138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
318238c8a9a5SSteve French 
318338c8a9a5SSteve French 	if (unlikely(cifs_forced_shutdown(cifs_sb)))
318438c8a9a5SSteve French 		return -EIO;
318538c8a9a5SSteve French 
318638c8a9a5SSteve French 	do {
318738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
318838c8a9a5SSteve French 		if (pTcon->unix_ext)
318938c8a9a5SSteve French 			rc = cifs_setattr_unix(direntry, attrs);
319038c8a9a5SSteve French 		else
319138c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
319238c8a9a5SSteve French 			rc = cifs_setattr_nounix(direntry, attrs);
319338c8a9a5SSteve French 		retries++;
319438c8a9a5SSteve French 	} while (is_retryable_error(rc) && retries < 2);
319538c8a9a5SSteve French 
319638c8a9a5SSteve French 	/* BB: add cifs_setattr_legacy for really old servers */
319738c8a9a5SSteve French 	return rc;
319838c8a9a5SSteve French }
3199