xref: /openbmc/linux/fs/smb/client/smb2inode.c (revision 7449d736)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   Copyright (C) International Business Machines  Corp., 2002, 2011
538c8a9a5SSteve French  *                 Etersoft, 2012
638c8a9a5SSteve French  *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
738c8a9a5SSteve French  *              Steve French (sfrench@us.ibm.com)
838c8a9a5SSteve French  *
938c8a9a5SSteve French  */
1038c8a9a5SSteve French #include <linux/fs.h>
1138c8a9a5SSteve French #include <linux/stat.h>
1238c8a9a5SSteve French #include <linux/slab.h>
1338c8a9a5SSteve French #include <linux/pagemap.h>
1438c8a9a5SSteve French #include <asm/div64.h>
1538c8a9a5SSteve French #include "cifsfs.h"
1638c8a9a5SSteve French #include "cifspdu.h"
1738c8a9a5SSteve French #include "cifsglob.h"
1838c8a9a5SSteve French #include "cifsproto.h"
1938c8a9a5SSteve French #include "cifs_debug.h"
2038c8a9a5SSteve French #include "cifs_fs_sb.h"
2138c8a9a5SSteve French #include "cifs_unicode.h"
2238c8a9a5SSteve French #include "fscache.h"
2338c8a9a5SSteve French #include "smb2glob.h"
2438c8a9a5SSteve French #include "smb2pdu.h"
2538c8a9a5SSteve French #include "smb2proto.h"
2638c8a9a5SSteve French #include "cached_dir.h"
2738c8a9a5SSteve French #include "smb2status.h"
2838c8a9a5SSteve French 
file_create_options(struct dentry * dentry)298c944f8aSPaulo Alcantara static inline __u32 file_create_options(struct dentry *dentry)
308c944f8aSPaulo Alcantara {
318c944f8aSPaulo Alcantara 	struct cifsInodeInfo *ci;
328c944f8aSPaulo Alcantara 
338c944f8aSPaulo Alcantara 	if (dentry) {
348c944f8aSPaulo Alcantara 		ci = CIFS_I(d_inode(dentry));
358c944f8aSPaulo Alcantara 		if (ci->cifsAttrs & ATTR_REPARSE)
368c944f8aSPaulo Alcantara 			return OPEN_REPARSE_POINT;
378c944f8aSPaulo Alcantara 	}
388c944f8aSPaulo Alcantara 	return 0;
398c944f8aSPaulo Alcantara }
408c944f8aSPaulo Alcantara 
reparse_buf_ptr(struct kvec * iov)41a158bb66SSteve French static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
42a158bb66SSteve French {
43a158bb66SSteve French 	struct reparse_data_buffer *buf;
44a158bb66SSteve French 	struct smb2_ioctl_rsp *io = iov->iov_base;
45a158bb66SSteve French 	u32 off, count, len;
46a158bb66SSteve French 
47a158bb66SSteve French 	count = le32_to_cpu(io->OutputCount);
48a158bb66SSteve French 	off = le32_to_cpu(io->OutputOffset);
49a158bb66SSteve French 	if (check_add_overflow(off, count, &len) || len > iov->iov_len)
50a158bb66SSteve French 		return ERR_PTR(-EIO);
51a158bb66SSteve French 
52a158bb66SSteve French 	buf = (struct reparse_data_buffer *)((u8 *)io + off);
53a158bb66SSteve French 	len = sizeof(*buf);
54a158bb66SSteve French 	if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
55a158bb66SSteve French 		return ERR_PTR(-EIO);
56a158bb66SSteve French 	return buf;
57a158bb66SSteve French }
58a158bb66SSteve French 
59a90f37e3SSteve French /* Parse owner and group from SMB3.1.1 POSIX query info */
parse_posix_sids(struct cifs_open_info_data * data,struct kvec * rsp_iov)60a90f37e3SSteve French static int parse_posix_sids(struct cifs_open_info_data *data,
61a90f37e3SSteve French 			    struct kvec *rsp_iov)
62a90f37e3SSteve French {
63a90f37e3SSteve French 	struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
64a90f37e3SSteve French 	unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
65a90f37e3SSteve French 	unsigned int qi_len = sizeof(data->posix_fi);
66a90f37e3SSteve French 	int owner_len, group_len;
67a90f37e3SSteve French 	u8 *sidsbuf, *sidsbuf_end;
68a90f37e3SSteve French 
69a90f37e3SSteve French 	if (out_len <= qi_len)
70a90f37e3SSteve French 		return -EINVAL;
71a90f37e3SSteve French 
72a90f37e3SSteve French 	sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
73a90f37e3SSteve French 	sidsbuf_end = sidsbuf + out_len - qi_len;
74a90f37e3SSteve French 
75a90f37e3SSteve French 	owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
76a90f37e3SSteve French 	if (owner_len == -1)
77a90f37e3SSteve French 		return -EINVAL;
78a90f37e3SSteve French 
79a90f37e3SSteve French 	memcpy(&data->posix_owner, sidsbuf, owner_len);
80a90f37e3SSteve French 	group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
81a90f37e3SSteve French 	if (group_len == -1)
82a90f37e3SSteve French 		return -EINVAL;
83a90f37e3SSteve French 
84a90f37e3SSteve French 	memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
85a90f37e3SSteve French 	return 0;
86a90f37e3SSteve French }
87a90f37e3SSteve French 
887449d736SSteve French struct wsl_query_ea {
897449d736SSteve French 	__le32	next;
907449d736SSteve French 	__u8	name_len;
917449d736SSteve French 	__u8	name[SMB2_WSL_XATTR_NAME_LEN + 1];
927449d736SSteve French } __packed;
937449d736SSteve French 
947449d736SSteve French #define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
957449d736SSteve French 
967449d736SSteve French static const struct wsl_query_ea wsl_query_eas[] = {
977449d736SSteve French 	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
987449d736SSteve French 	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
997449d736SSteve French 	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
1007449d736SSteve French 	{ .next = 0,        .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
1017449d736SSteve French };
1027449d736SSteve French 
check_wsl_eas(struct kvec * rsp_iov)1037449d736SSteve French static int check_wsl_eas(struct kvec *rsp_iov)
1047449d736SSteve French {
1057449d736SSteve French 	struct smb2_file_full_ea_info *ea;
1067449d736SSteve French 	struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
1077449d736SSteve French 	unsigned long addr;
1087449d736SSteve French 	u32 outlen, next;
1097449d736SSteve French 	u16 vlen;
1107449d736SSteve French 	u8 nlen;
1117449d736SSteve French 	u8 *end;
1127449d736SSteve French 
1137449d736SSteve French 	outlen = le32_to_cpu(rsp->OutputBufferLength);
1147449d736SSteve French 	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
1157449d736SSteve French 	    outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
1167449d736SSteve French 		return -EINVAL;
1177449d736SSteve French 
1187449d736SSteve French 	ea = (void *)((u8 *)rsp_iov->iov_base +
1197449d736SSteve French 		      le16_to_cpu(rsp->OutputBufferOffset));
1207449d736SSteve French 	end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
1217449d736SSteve French 	for (;;) {
1227449d736SSteve French 		if ((u8 *)ea > end - sizeof(*ea))
1237449d736SSteve French 			return -EINVAL;
1247449d736SSteve French 
1257449d736SSteve French 		nlen = ea->ea_name_length;
1267449d736SSteve French 		vlen = le16_to_cpu(ea->ea_value_length);
1277449d736SSteve French 		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
1287449d736SSteve French 		    (u8 *)ea + nlen + 1 + vlen > end)
1297449d736SSteve French 			return -EINVAL;
1307449d736SSteve French 
1317449d736SSteve French 		switch (vlen) {
1327449d736SSteve French 		case 4:
1337449d736SSteve French 			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
1347449d736SSteve French 			    strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
1357449d736SSteve French 			    strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
1367449d736SSteve French 				return -EINVAL;
1377449d736SSteve French 			break;
1387449d736SSteve French 		case 8:
1397449d736SSteve French 			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
1407449d736SSteve French 				return -EINVAL;
1417449d736SSteve French 			break;
1427449d736SSteve French 		case 0:
1437449d736SSteve French 			if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
1447449d736SSteve French 			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
1457449d736SSteve French 			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
1467449d736SSteve French 			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
1477449d736SSteve French 				break;
1487449d736SSteve French 			fallthrough;
1497449d736SSteve French 		default:
1507449d736SSteve French 			return -EINVAL;
1517449d736SSteve French 		}
1527449d736SSteve French 
1537449d736SSteve French 		next = le32_to_cpu(ea->next_entry_offset);
1547449d736SSteve French 		if (!next)
1557449d736SSteve French 			break;
1567449d736SSteve French 		if (!IS_ALIGNED(next, 4) ||
1577449d736SSteve French 		    check_add_overflow((unsigned long)ea, next, &addr))
1587449d736SSteve French 			return -EINVAL;
1597449d736SSteve French 		ea = (void *)addr;
1607449d736SSteve French 	}
1617449d736SSteve French 	return 0;
1627449d736SSteve French }
1637449d736SSteve French 
16438c8a9a5SSteve French /*
16538c8a9a5SSteve French  * note: If cfile is passed, the reference to it is dropped here.
16638c8a9a5SSteve French  * So make sure that you do not reuse cfile after return from this func.
16738c8a9a5SSteve French  *
168c5f44a3dSPaulo Alcantara  * If passing @out_iov and @out_buftype, ensure to make them both large enough
169c5f44a3dSPaulo Alcantara  * (>= 3) to hold all compounded responses.  Caller is also responsible for
170c5f44a3dSPaulo Alcantara  * freeing them up with free_rsp_buf().
17138c8a9a5SSteve French  */
smb2_compound_op(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,struct cifs_open_parms * oparms,struct kvec * in_iov,int * cmds,int num_cmds,struct cifsFileInfo * cfile,struct kvec * out_iov,int * out_buftype,struct dentry * dentry)17238c8a9a5SSteve French static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
17338c8a9a5SSteve French 			    struct cifs_sb_info *cifs_sb, const char *full_path,
174831ffbd1SPaulo Alcantara 			    struct cifs_open_parms *oparms, struct kvec *in_iov,
175886b7fb4SSteve French 			    int *cmds, int num_cmds, struct cifsFileInfo *cfile,
176f93d145fSMeetakshi Setiya 			    struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
17738c8a9a5SSteve French {
178a158bb66SSteve French 
179a158bb66SSteve French 	struct reparse_data_buffer *rbuf;
180f4e5ceb6SPaulo Alcantara 	struct smb2_compound_vars *vars = NULL;
181a158bb66SSteve French 	struct kvec *rsp_iov, *iov;
18238c8a9a5SSteve French 	struct smb_rqst *rqst;
18338c8a9a5SSteve French 	int rc;
18438c8a9a5SSteve French 	__le16 *utf16_path = NULL;
18538c8a9a5SSteve French 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
18638c8a9a5SSteve French 	struct cifs_fid fid;
18738c8a9a5SSteve French 	struct cifs_ses *ses = tcon->ses;
18838c8a9a5SSteve French 	struct TCP_Server_Info *server;
189886b7fb4SSteve French 	int num_rqst = 0, i;
190886b7fb4SSteve French 	int resp_buftype[MAX_COMPOUND];
19138c8a9a5SSteve French 	struct smb2_query_info_rsp *qi_rsp = NULL;
19238c8a9a5SSteve French 	struct cifs_open_info_data *idata;
193f93d145fSMeetakshi Setiya 	struct inode *inode = NULL;
19438c8a9a5SSteve French 	int flags = 0;
19538c8a9a5SSteve French 	__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
19638c8a9a5SSteve French 	unsigned int size[2];
19738c8a9a5SSteve French 	void *data[2];
1987449d736SSteve French 	unsigned int len;
199433042a9SShyam Prasad N 	int retries = 0, cur_sleep = 1;
200433042a9SShyam Prasad N 
201433042a9SShyam Prasad N replay_again:
202433042a9SShyam Prasad N 	/* reinitialize for possible replay */
203433042a9SShyam Prasad N 	flags = 0;
204433042a9SShyam Prasad N 	oplock = SMB2_OPLOCK_LEVEL_NONE;
205433042a9SShyam Prasad N 	num_rqst = 0;
206433042a9SShyam Prasad N 	server = cifs_pick_channel(ses);
20738c8a9a5SSteve French 
20838c8a9a5SSteve French 	vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
20938c8a9a5SSteve French 	if (vars == NULL)
21038c8a9a5SSteve French 		return -ENOMEM;
21138c8a9a5SSteve French 	rqst = &vars->rqst[0];
21238c8a9a5SSteve French 	rsp_iov = &vars->rsp_iov[0];
21338c8a9a5SSteve French 
21438c8a9a5SSteve French 	if (smb3_encryption_required(tcon))
21538c8a9a5SSteve French 		flags |= CIFS_TRANSFORM_REQ;
21638c8a9a5SSteve French 
217886b7fb4SSteve French 	for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
218886b7fb4SSteve French 		resp_buftype[i] = CIFS_NO_BUFFER;
21938c8a9a5SSteve French 
22038c8a9a5SSteve French 	/* We already have a handle so we can skip the open */
22138c8a9a5SSteve French 	if (cfile)
22238c8a9a5SSteve French 		goto after_open;
22338c8a9a5SSteve French 
22438c8a9a5SSteve French 	/* Open */
22538c8a9a5SSteve French 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
22638c8a9a5SSteve French 	if (!utf16_path) {
22738c8a9a5SSteve French 		rc = -ENOMEM;
22838c8a9a5SSteve French 		goto finished;
22938c8a9a5SSteve French 	}
23038c8a9a5SSteve French 
231f93d145fSMeetakshi Setiya 	/* if there is an existing lease, reuse it */
2321e60bc0eSMeetakshi Setiya 
2331e60bc0eSMeetakshi Setiya 	/*
2341e60bc0eSMeetakshi Setiya 	 * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
2351e60bc0eSMeetakshi Setiya 	 * lease keys are associated with the filepath. We are maintaining lease keys
2361e60bc0eSMeetakshi Setiya 	 * with the inode on the client. If the file has hardlinks, it is possible
2371e60bc0eSMeetakshi Setiya 	 * that the lease for a file be reused for an operation on its hardlink or
2381e60bc0eSMeetakshi Setiya 	 * vice versa.
2391e60bc0eSMeetakshi Setiya 	 * As a workaround, send request using an existing lease key and if the server
2401e60bc0eSMeetakshi Setiya 	 * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
2411e60bc0eSMeetakshi Setiya 	 * again without the lease.
2421e60bc0eSMeetakshi Setiya 	 */
243f93d145fSMeetakshi Setiya 	if (dentry) {
244f93d145fSMeetakshi Setiya 		inode = d_inode(dentry);
245f93d145fSMeetakshi Setiya 		if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
246f93d145fSMeetakshi Setiya 			oplock = SMB2_OPLOCK_LEVEL_LEASE;
247f93d145fSMeetakshi Setiya 			server->ops->get_lease_key(inode, &fid);
248f93d145fSMeetakshi Setiya 		}
249f93d145fSMeetakshi Setiya 	}
250f93d145fSMeetakshi Setiya 
251831ffbd1SPaulo Alcantara 	vars->oparms = *oparms;
252831ffbd1SPaulo Alcantara 	vars->oparms.fid = &fid;
25338c8a9a5SSteve French 
25438c8a9a5SSteve French 	rqst[num_rqst].rq_iov = &vars->open_iov[0];
25538c8a9a5SSteve French 	rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
25638c8a9a5SSteve French 	rc = SMB2_open_init(tcon, server,
25738c8a9a5SSteve French 			    &rqst[num_rqst], &oplock, &vars->oparms,
25838c8a9a5SSteve French 			    utf16_path);
25938c8a9a5SSteve French 	kfree(utf16_path);
26038c8a9a5SSteve French 	if (rc)
26138c8a9a5SSteve French 		goto finished;
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 	smb2_set_next_command(tcon, &rqst[num_rqst]);
26438c8a9a5SSteve French  after_open:
26538c8a9a5SSteve French 	num_rqst++;
26638c8a9a5SSteve French 	rc = 0;
26738c8a9a5SSteve French 
268886b7fb4SSteve French 	for (i = 0; i < num_cmds; i++) {
26938c8a9a5SSteve French 		/* Operation */
270886b7fb4SSteve French 		switch (cmds[i]) {
27138c8a9a5SSteve French 		case SMB2_OP_QUERY_INFO:
272f4e5ceb6SPaulo Alcantara 			rqst[num_rqst].rq_iov = &vars->qi_iov;
27338c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 1;
27438c8a9a5SSteve French 
275886b7fb4SSteve French 			if (cfile) {
27638c8a9a5SSteve French 				rc = SMB2_query_info_init(tcon, server,
27738c8a9a5SSteve French 							  &rqst[num_rqst],
27838c8a9a5SSteve French 							  cfile->fid.persistent_fid,
27938c8a9a5SSteve French 							  cfile->fid.volatile_fid,
28038c8a9a5SSteve French 							  FILE_ALL_INFORMATION,
28138c8a9a5SSteve French 							  SMB2_O_INFO_FILE, 0,
28238c8a9a5SSteve French 							  sizeof(struct smb2_file_all_info) +
28338c8a9a5SSteve French 							  PATH_MAX * 2, 0, NULL);
284886b7fb4SSteve French 			} else {
28538c8a9a5SSteve French 				rc = SMB2_query_info_init(tcon, server,
28638c8a9a5SSteve French 							  &rqst[num_rqst],
28738c8a9a5SSteve French 							  COMPOUND_FID,
28838c8a9a5SSteve French 							  COMPOUND_FID,
28938c8a9a5SSteve French 							  FILE_ALL_INFORMATION,
29038c8a9a5SSteve French 							  SMB2_O_INFO_FILE, 0,
29138c8a9a5SSteve French 							  sizeof(struct smb2_file_all_info) +
29238c8a9a5SSteve French 							  PATH_MAX * 2, 0, NULL);
29384c597f7SPaulo Alcantara 			}
29484c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
29538c8a9a5SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
29638c8a9a5SSteve French 				smb2_set_related(&rqst[num_rqst]);
29784c597f7SPaulo Alcantara 			} else if (rc) {
29838c8a9a5SSteve French 				goto finished;
29984c597f7SPaulo Alcantara 			}
30038c8a9a5SSteve French 			num_rqst++;
301886b7fb4SSteve French 			trace_smb3_query_info_compound_enter(xid, ses->Suid,
302886b7fb4SSteve French 							     tcon->tid, full_path);
30338c8a9a5SSteve French 			break;
30438c8a9a5SSteve French 		case SMB2_OP_POSIX_QUERY_INFO:
305f4e5ceb6SPaulo Alcantara 			rqst[num_rqst].rq_iov = &vars->qi_iov;
30638c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 1;
30738c8a9a5SSteve French 
308886b7fb4SSteve French 			if (cfile) {
309886b7fb4SSteve French 				/* TBD: fix following to allow for longer SIDs */
31038c8a9a5SSteve French 				rc = SMB2_query_info_init(tcon, server,
31138c8a9a5SSteve French 							  &rqst[num_rqst],
31238c8a9a5SSteve French 							  cfile->fid.persistent_fid,
31338c8a9a5SSteve French 							  cfile->fid.volatile_fid,
31438c8a9a5SSteve French 							  SMB_FIND_FILE_POSIX_INFO,
31538c8a9a5SSteve French 							  SMB2_O_INFO_FILE, 0,
316886b7fb4SSteve French 							  sizeof(struct smb311_posix_qinfo *) +
317886b7fb4SSteve French 							  (PATH_MAX * 2) +
31838c8a9a5SSteve French 							  (sizeof(struct cifs_sid) * 2), 0, NULL);
319886b7fb4SSteve French 			} else {
32038c8a9a5SSteve French 				rc = SMB2_query_info_init(tcon, server,
32138c8a9a5SSteve French 							  &rqst[num_rqst],
32238c8a9a5SSteve French 							  COMPOUND_FID,
32338c8a9a5SSteve French 							  COMPOUND_FID,
32438c8a9a5SSteve French 							  SMB_FIND_FILE_POSIX_INFO,
32538c8a9a5SSteve French 							  SMB2_O_INFO_FILE, 0,
326886b7fb4SSteve French 							  sizeof(struct smb311_posix_qinfo *) +
327886b7fb4SSteve French 							  (PATH_MAX * 2) +
32838c8a9a5SSteve French 							  (sizeof(struct cifs_sid) * 2), 0, NULL);
32984c597f7SPaulo Alcantara 			}
33084c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
33138c8a9a5SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
33238c8a9a5SSteve French 				smb2_set_related(&rqst[num_rqst]);
33384c597f7SPaulo Alcantara 			} else if (rc) {
33438c8a9a5SSteve French 				goto finished;
33584c597f7SPaulo Alcantara 			}
33638c8a9a5SSteve French 			num_rqst++;
337886b7fb4SSteve French 			trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
338886b7fb4SSteve French 								   tcon->tid, full_path);
33938c8a9a5SSteve French 			break;
34038c8a9a5SSteve French 		case SMB2_OP_DELETE:
34138c8a9a5SSteve French 			trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
34238c8a9a5SSteve French 			break;
34338c8a9a5SSteve French 		case SMB2_OP_MKDIR:
34438c8a9a5SSteve French 			/*
34538c8a9a5SSteve French 			 * Directories are created through parameters in the
34638c8a9a5SSteve French 			 * SMB2_open() call.
34738c8a9a5SSteve French 			 */
34838c8a9a5SSteve French 			trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
34938c8a9a5SSteve French 			break;
35038c8a9a5SSteve French 		case SMB2_OP_RMDIR:
35138c8a9a5SSteve French 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
35238c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 1;
35338c8a9a5SSteve French 
35438c8a9a5SSteve French 			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
35538c8a9a5SSteve French 			data[0] = &delete_pending[0];
35638c8a9a5SSteve French 
35738c8a9a5SSteve French 			rc = SMB2_set_info_init(tcon, server,
35838c8a9a5SSteve French 						&rqst[num_rqst], COMPOUND_FID,
35938c8a9a5SSteve French 						COMPOUND_FID, current->tgid,
36038c8a9a5SSteve French 						FILE_DISPOSITION_INFORMATION,
36138c8a9a5SSteve French 						SMB2_O_INFO_FILE, 0, data, size);
36238c8a9a5SSteve French 			if (rc)
36338c8a9a5SSteve French 				goto finished;
36438c8a9a5SSteve French 			smb2_set_next_command(tcon, &rqst[num_rqst]);
36538c8a9a5SSteve French 			smb2_set_related(&rqst[num_rqst++]);
36638c8a9a5SSteve French 			trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
36738c8a9a5SSteve French 			break;
36838c8a9a5SSteve French 		case SMB2_OP_SET_EOF:
36938c8a9a5SSteve French 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
37038c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 1;
37138c8a9a5SSteve French 
372886b7fb4SSteve French 			size[0] = in_iov[i].iov_len;
373886b7fb4SSteve French 			data[0] = in_iov[i].iov_base;
37438c8a9a5SSteve French 
37538c8a9a5SSteve French 			if (cfile) {
37638c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
37738c8a9a5SSteve French 							&rqst[num_rqst],
37838c8a9a5SSteve French 							cfile->fid.persistent_fid,
37938c8a9a5SSteve French 							cfile->fid.volatile_fid,
38038c8a9a5SSteve French 							current->tgid,
38138c8a9a5SSteve French 							FILE_END_OF_FILE_INFORMATION,
38238c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0,
38338c8a9a5SSteve French 							data, size);
38438c8a9a5SSteve French 			} else {
38538c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
38638c8a9a5SSteve French 							&rqst[num_rqst],
38738c8a9a5SSteve French 							COMPOUND_FID,
38838c8a9a5SSteve French 							COMPOUND_FID,
38938c8a9a5SSteve French 							current->tgid,
39038c8a9a5SSteve French 							FILE_END_OF_FILE_INFORMATION,
39138c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0,
39238c8a9a5SSteve French 							data, size);
39384c597f7SPaulo Alcantara 			}
39484c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
39538c8a9a5SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
39638c8a9a5SSteve French 				smb2_set_related(&rqst[num_rqst]);
39784c597f7SPaulo Alcantara 			} else if (rc) {
39838c8a9a5SSteve French 				goto finished;
39984c597f7SPaulo Alcantara 			}
40038c8a9a5SSteve French 			num_rqst++;
40138c8a9a5SSteve French 			trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
40238c8a9a5SSteve French 			break;
40338c8a9a5SSteve French 		case SMB2_OP_SET_INFO:
40438c8a9a5SSteve French 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
40538c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 1;
40638c8a9a5SSteve French 
407886b7fb4SSteve French 			size[0] = in_iov[i].iov_len;
408886b7fb4SSteve French 			data[0] = in_iov[i].iov_base;
40938c8a9a5SSteve French 
410886b7fb4SSteve French 			if (cfile) {
41138c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
41238c8a9a5SSteve French 							&rqst[num_rqst],
41338c8a9a5SSteve French 							cfile->fid.persistent_fid,
41438c8a9a5SSteve French 							cfile->fid.volatile_fid, current->tgid,
41538c8a9a5SSteve French 							FILE_BASIC_INFORMATION,
41638c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0, data, size);
417886b7fb4SSteve French 			} else {
41838c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
41938c8a9a5SSteve French 							&rqst[num_rqst],
42038c8a9a5SSteve French 							COMPOUND_FID,
42138c8a9a5SSteve French 							COMPOUND_FID, current->tgid,
42238c8a9a5SSteve French 							FILE_BASIC_INFORMATION,
42338c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0, data, size);
42484c597f7SPaulo Alcantara 			}
42584c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
42638c8a9a5SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
42738c8a9a5SSteve French 				smb2_set_related(&rqst[num_rqst]);
42884c597f7SPaulo Alcantara 			} else if (rc) {
42938c8a9a5SSteve French 				goto finished;
43084c597f7SPaulo Alcantara 			}
43138c8a9a5SSteve French 			num_rqst++;
432886b7fb4SSteve French 			trace_smb3_set_info_compound_enter(xid, ses->Suid,
433886b7fb4SSteve French 							   tcon->tid, full_path);
43438c8a9a5SSteve French 			break;
43538c8a9a5SSteve French 		case SMB2_OP_RENAME:
43638c8a9a5SSteve French 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
43738c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 2;
43838c8a9a5SSteve French 
439886b7fb4SSteve French 			len = in_iov[i].iov_len;
44038c8a9a5SSteve French 
44138c8a9a5SSteve French 			vars->rename_info.ReplaceIfExists = 1;
44238c8a9a5SSteve French 			vars->rename_info.RootDirectory = 0;
44338c8a9a5SSteve French 			vars->rename_info.FileNameLength = cpu_to_le32(len);
44438c8a9a5SSteve French 
44538c8a9a5SSteve French 			size[0] = sizeof(struct smb2_file_rename_info);
44638c8a9a5SSteve French 			data[0] = &vars->rename_info;
44738c8a9a5SSteve French 
44838c8a9a5SSteve French 			size[1] = len + 2 /* null */;
449886b7fb4SSteve French 			data[1] = in_iov[i].iov_base;
45038c8a9a5SSteve French 
451886b7fb4SSteve French 			if (cfile) {
45238c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
45338c8a9a5SSteve French 							&rqst[num_rqst],
45438c8a9a5SSteve French 							cfile->fid.persistent_fid,
45538c8a9a5SSteve French 							cfile->fid.volatile_fid,
45638c8a9a5SSteve French 							current->tgid, FILE_RENAME_INFORMATION,
45738c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0, data, size);
458886b7fb4SSteve French 			} else {
45938c8a9a5SSteve French 				rc = SMB2_set_info_init(tcon, server,
46038c8a9a5SSteve French 							&rqst[num_rqst],
46138c8a9a5SSteve French 							COMPOUND_FID, COMPOUND_FID,
46238c8a9a5SSteve French 							current->tgid, FILE_RENAME_INFORMATION,
46338c8a9a5SSteve French 							SMB2_O_INFO_FILE, 0, data, size);
46484c597f7SPaulo Alcantara 			}
46584c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
46638c8a9a5SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
46738c8a9a5SSteve French 				smb2_set_related(&rqst[num_rqst]);
46884c597f7SPaulo Alcantara 			} else if (rc) {
46938c8a9a5SSteve French 				goto finished;
47084c597f7SPaulo Alcantara 			}
47138c8a9a5SSteve French 			num_rqst++;
47238c8a9a5SSteve French 			trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
47338c8a9a5SSteve French 			break;
47438c8a9a5SSteve French 		case SMB2_OP_HARDLINK:
47538c8a9a5SSteve French 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
47638c8a9a5SSteve French 			rqst[num_rqst].rq_nvec = 2;
47738c8a9a5SSteve French 
478886b7fb4SSteve French 			len = in_iov[i].iov_len;
47938c8a9a5SSteve French 
48038c8a9a5SSteve French 			vars->link_info.ReplaceIfExists = 0;
48138c8a9a5SSteve French 			vars->link_info.RootDirectory = 0;
48238c8a9a5SSteve French 			vars->link_info.FileNameLength = cpu_to_le32(len);
48338c8a9a5SSteve French 
48438c8a9a5SSteve French 			size[0] = sizeof(struct smb2_file_link_info);
48538c8a9a5SSteve French 			data[0] = &vars->link_info;
48638c8a9a5SSteve French 
48738c8a9a5SSteve French 			size[1] = len + 2 /* null */;
488886b7fb4SSteve French 			data[1] = in_iov[i].iov_base;
48938c8a9a5SSteve French 
49038c8a9a5SSteve French 			rc = SMB2_set_info_init(tcon, server,
49138c8a9a5SSteve French 						&rqst[num_rqst], COMPOUND_FID,
49238c8a9a5SSteve French 						COMPOUND_FID, current->tgid,
49338c8a9a5SSteve French 						FILE_LINK_INFORMATION,
49438c8a9a5SSteve French 						SMB2_O_INFO_FILE, 0, data, size);
49538c8a9a5SSteve French 			if (rc)
49638c8a9a5SSteve French 				goto finished;
49738c8a9a5SSteve French 			smb2_set_next_command(tcon, &rqst[num_rqst]);
49838c8a9a5SSteve French 			smb2_set_related(&rqst[num_rqst++]);
49938c8a9a5SSteve French 			trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
50038c8a9a5SSteve French 			break;
50102bcf865SSteve French 		case SMB2_OP_SET_REPARSE:
50202bcf865SSteve French 			rqst[num_rqst].rq_iov = vars->io_iov;
50302bcf865SSteve French 			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
50402bcf865SSteve French 
50584c597f7SPaulo Alcantara 			if (cfile) {
50684c597f7SPaulo Alcantara 				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
50784c597f7SPaulo Alcantara 						     cfile->fid.persistent_fid,
50884c597f7SPaulo Alcantara 						     cfile->fid.volatile_fid,
50984c597f7SPaulo Alcantara 						     FSCTL_SET_REPARSE_POINT,
51084c597f7SPaulo Alcantara 						     in_iov[i].iov_base,
51184c597f7SPaulo Alcantara 						     in_iov[i].iov_len, 0);
51284c597f7SPaulo Alcantara 			} else {
51302bcf865SSteve French 				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
51402bcf865SSteve French 						     COMPOUND_FID, COMPOUND_FID,
51502bcf865SSteve French 						     FSCTL_SET_REPARSE_POINT,
51602bcf865SSteve French 						     in_iov[i].iov_base,
51702bcf865SSteve French 						     in_iov[i].iov_len, 0);
51884c597f7SPaulo Alcantara 			}
51984c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
52002bcf865SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
52184c597f7SPaulo Alcantara 				smb2_set_related(&rqst[num_rqst]);
52284c597f7SPaulo Alcantara 			} else if (rc) {
52384c597f7SPaulo Alcantara 				goto finished;
52484c597f7SPaulo Alcantara 			}
52584c597f7SPaulo Alcantara 			num_rqst++;
52602bcf865SSteve French 			trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
52702bcf865SSteve French 							      tcon->tid, full_path);
52802bcf865SSteve French 			break;
529a158bb66SSteve French 		case SMB2_OP_GET_REPARSE:
530a158bb66SSteve French 			rqst[num_rqst].rq_iov = vars->io_iov;
531a158bb66SSteve French 			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
532a158bb66SSteve French 
53384c597f7SPaulo Alcantara 			if (cfile) {
53484c597f7SPaulo Alcantara 				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
53584c597f7SPaulo Alcantara 						     cfile->fid.persistent_fid,
53684c597f7SPaulo Alcantara 						     cfile->fid.volatile_fid,
53784c597f7SPaulo Alcantara 						     FSCTL_GET_REPARSE_POINT,
53884c597f7SPaulo Alcantara 						     NULL, 0, CIFSMaxBufSize);
53984c597f7SPaulo Alcantara 			} else {
540a158bb66SSteve French 				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
541a158bb66SSteve French 						     COMPOUND_FID, COMPOUND_FID,
542a158bb66SSteve French 						     FSCTL_GET_REPARSE_POINT,
543a158bb66SSteve French 						     NULL, 0, CIFSMaxBufSize);
54484c597f7SPaulo Alcantara 			}
54584c597f7SPaulo Alcantara 			if (!rc && (!cfile || num_rqst > 1)) {
546a158bb66SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
54784c597f7SPaulo Alcantara 				smb2_set_related(&rqst[num_rqst]);
54884c597f7SPaulo Alcantara 			} else if (rc) {
54984c597f7SPaulo Alcantara 				goto finished;
55084c597f7SPaulo Alcantara 			}
55184c597f7SPaulo Alcantara 			num_rqst++;
552a158bb66SSteve French 			trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
553a158bb66SSteve French 							      tcon->tid, full_path);
554a158bb66SSteve French 			break;
5557449d736SSteve French 		case SMB2_OP_QUERY_WSL_EA:
5567449d736SSteve French 			rqst[num_rqst].rq_iov = &vars->ea_iov;
5577449d736SSteve French 			rqst[num_rqst].rq_nvec = 1;
5587449d736SSteve French 
5597449d736SSteve French 			if (cfile) {
5607449d736SSteve French 				rc = SMB2_query_info_init(tcon, server,
5617449d736SSteve French 							  &rqst[num_rqst],
5627449d736SSteve French 							  cfile->fid.persistent_fid,
5637449d736SSteve French 							  cfile->fid.volatile_fid,
5647449d736SSteve French 							  FILE_FULL_EA_INFORMATION,
5657449d736SSteve French 							  SMB2_O_INFO_FILE, 0,
5667449d736SSteve French 							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
5677449d736SSteve French 							  sizeof(wsl_query_eas),
5687449d736SSteve French 							  (void *)wsl_query_eas);
5697449d736SSteve French 			} else {
5707449d736SSteve French 				rc = SMB2_query_info_init(tcon, server,
5717449d736SSteve French 							  &rqst[num_rqst],
5727449d736SSteve French 							  COMPOUND_FID,
5737449d736SSteve French 							  COMPOUND_FID,
5747449d736SSteve French 							  FILE_FULL_EA_INFORMATION,
5757449d736SSteve French 							  SMB2_O_INFO_FILE, 0,
5767449d736SSteve French 							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
5777449d736SSteve French 							  sizeof(wsl_query_eas),
5787449d736SSteve French 							  (void *)wsl_query_eas);
5797449d736SSteve French 			}
5807449d736SSteve French 			if (!rc && (!cfile || num_rqst > 1)) {
5817449d736SSteve French 				smb2_set_next_command(tcon, &rqst[num_rqst]);
5827449d736SSteve French 				smb2_set_related(&rqst[num_rqst]);
5837449d736SSteve French 			} else if (rc) {
5847449d736SSteve French 				goto finished;
5857449d736SSteve French 			}
5867449d736SSteve French 			num_rqst++;
5877449d736SSteve French 			break;
58838c8a9a5SSteve French 		default:
58938c8a9a5SSteve French 			cifs_dbg(VFS, "Invalid command\n");
59038c8a9a5SSteve French 			rc = -EINVAL;
59138c8a9a5SSteve French 		}
592886b7fb4SSteve French 	}
59338c8a9a5SSteve French 	if (rc)
59438c8a9a5SSteve French 		goto finished;
59538c8a9a5SSteve French 
59638c8a9a5SSteve French 	/* We already have a handle so we can skip the close */
59738c8a9a5SSteve French 	if (cfile)
59838c8a9a5SSteve French 		goto after_close;
59938c8a9a5SSteve French 	/* Close */
60038c8a9a5SSteve French 	flags |= CIFS_CP_CREATE_CLOSE_OP;
601f4e5ceb6SPaulo Alcantara 	rqst[num_rqst].rq_iov = &vars->close_iov;
60238c8a9a5SSteve French 	rqst[num_rqst].rq_nvec = 1;
60338c8a9a5SSteve French 	rc = SMB2_close_init(tcon, server,
60438c8a9a5SSteve French 			     &rqst[num_rqst], COMPOUND_FID,
60538c8a9a5SSteve French 			     COMPOUND_FID, false);
60638c8a9a5SSteve French 	smb2_set_related(&rqst[num_rqst]);
60738c8a9a5SSteve French 	if (rc)
60838c8a9a5SSteve French 		goto finished;
60938c8a9a5SSteve French  after_close:
61038c8a9a5SSteve French 	num_rqst++;
61138c8a9a5SSteve French 
61238c8a9a5SSteve French 	if (cfile) {
613433042a9SShyam Prasad N 		if (retries)
614433042a9SShyam Prasad N 			for (i = 1; i < num_rqst - 2; i++)
615433042a9SShyam Prasad N 				smb2_set_replay(server, &rqst[i]);
616433042a9SShyam Prasad N 
61738c8a9a5SSteve French 		rc = compound_send_recv(xid, ses, server,
61838c8a9a5SSteve French 					flags, num_rqst - 2,
61938c8a9a5SSteve French 					&rqst[1], &resp_buftype[1],
62038c8a9a5SSteve French 					&rsp_iov[1]);
621433042a9SShyam Prasad N 	} else {
622433042a9SShyam Prasad N 		if (retries)
623433042a9SShyam Prasad N 			for (i = 0; i < num_rqst; i++)
624433042a9SShyam Prasad N 				smb2_set_replay(server, &rqst[i]);
625433042a9SShyam Prasad N 
62638c8a9a5SSteve French 		rc = compound_send_recv(xid, ses, server,
62738c8a9a5SSteve French 					flags, num_rqst,
62838c8a9a5SSteve French 					rqst, resp_buftype,
62938c8a9a5SSteve French 					rsp_iov);
630433042a9SShyam Prasad N 	}
63138c8a9a5SSteve French 
63238c8a9a5SSteve French finished:
633886b7fb4SSteve French 	num_rqst = 0;
634886b7fb4SSteve French 	SMB2_open_free(&rqst[num_rqst++]);
63538c8a9a5SSteve French 	if (rc == -EREMCHG) {
63638c8a9a5SSteve French 		pr_warn_once("server share %s deleted\n", tcon->tree_name);
63738c8a9a5SSteve French 		tcon->need_reconnect = true;
63838c8a9a5SSteve French 	}
63938c8a9a5SSteve French 
640886b7fb4SSteve French 	for (i = 0; i < num_cmds; i++) {
641886b7fb4SSteve French 		switch (cmds[i]) {
64238c8a9a5SSteve French 		case SMB2_OP_QUERY_INFO:
643886b7fb4SSteve French 			idata = in_iov[i].iov_base;
64438c8a9a5SSteve French 			if (rc == 0 && cfile && cfile->symlink_target) {
64538c8a9a5SSteve French 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
64638c8a9a5SSteve French 				if (!idata->symlink_target)
64738c8a9a5SSteve French 					rc = -ENOMEM;
64838c8a9a5SSteve French 			}
64938c8a9a5SSteve French 			if (rc == 0) {
65038c8a9a5SSteve French 				qi_rsp = (struct smb2_query_info_rsp *)
651886b7fb4SSteve French 					rsp_iov[i + 1].iov_base;
65238c8a9a5SSteve French 				rc = smb2_validate_and_copy_iov(
65338c8a9a5SSteve French 					le16_to_cpu(qi_rsp->OutputBufferOffset),
65438c8a9a5SSteve French 					le32_to_cpu(qi_rsp->OutputBufferLength),
655886b7fb4SSteve French 					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
65638c8a9a5SSteve French 			}
657886b7fb4SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
65838c8a9a5SSteve French 			if (rc)
65938c8a9a5SSteve French 				trace_smb3_query_info_compound_err(xid,  ses->Suid,
66038c8a9a5SSteve French 								   tcon->tid, rc);
66138c8a9a5SSteve French 			else
66238c8a9a5SSteve French 				trace_smb3_query_info_compound_done(xid, ses->Suid,
66338c8a9a5SSteve French 								    tcon->tid);
66438c8a9a5SSteve French 			break;
66538c8a9a5SSteve French 		case SMB2_OP_POSIX_QUERY_INFO:
666886b7fb4SSteve French 			idata = in_iov[i].iov_base;
66738c8a9a5SSteve French 			if (rc == 0 && cfile && cfile->symlink_target) {
66838c8a9a5SSteve French 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
66938c8a9a5SSteve French 				if (!idata->symlink_target)
67038c8a9a5SSteve French 					rc = -ENOMEM;
67138c8a9a5SSteve French 			}
67238c8a9a5SSteve French 			if (rc == 0) {
67338c8a9a5SSteve French 				qi_rsp = (struct smb2_query_info_rsp *)
674886b7fb4SSteve French 					rsp_iov[i + 1].iov_base;
67538c8a9a5SSteve French 				rc = smb2_validate_and_copy_iov(
67638c8a9a5SSteve French 					le16_to_cpu(qi_rsp->OutputBufferOffset),
67738c8a9a5SSteve French 					le32_to_cpu(qi_rsp->OutputBufferLength),
678886b7fb4SSteve French 					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
67938c8a9a5SSteve French 					(char *)&idata->posix_fi);
68038c8a9a5SSteve French 			}
681a90f37e3SSteve French 			if (rc == 0)
682a90f37e3SSteve French 				rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
68338c8a9a5SSteve French 
684886b7fb4SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
68538c8a9a5SSteve French 			if (rc)
686886b7fb4SSteve French 				trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,
687886b7fb4SSteve French 									 tcon->tid, rc);
68838c8a9a5SSteve French 			else
689886b7fb4SSteve French 				trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
690886b7fb4SSteve French 									  tcon->tid);
69138c8a9a5SSteve French 			break;
69238c8a9a5SSteve French 		case SMB2_OP_DELETE:
69338c8a9a5SSteve French 			if (rc)
69438c8a9a5SSteve French 				trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
695b6e27f7fSSteve French 			else {
696b6e27f7fSSteve French 				/*
697b6e27f7fSSteve French 				 * If dentry (hence, inode) is NULL, lease break is going to
698b6e27f7fSSteve French 				 * take care of degrading leases on handles for deleted files.
699b6e27f7fSSteve French 				 */
700b6e27f7fSSteve French 				if (inode)
701b6e27f7fSSteve French 					cifs_mark_open_handles_for_deleted_file(inode, full_path);
70238c8a9a5SSteve French 				trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
703b6e27f7fSSteve French 			}
70438c8a9a5SSteve French 			break;
70538c8a9a5SSteve French 		case SMB2_OP_MKDIR:
70638c8a9a5SSteve French 			if (rc)
70738c8a9a5SSteve French 				trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
70838c8a9a5SSteve French 			else
70938c8a9a5SSteve French 				trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
71038c8a9a5SSteve French 			break;
71138c8a9a5SSteve French 		case SMB2_OP_HARDLINK:
71238c8a9a5SSteve French 			if (rc)
71338c8a9a5SSteve French 				trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
71438c8a9a5SSteve French 			else
71538c8a9a5SSteve French 				trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
716886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
71738c8a9a5SSteve French 			break;
71838c8a9a5SSteve French 		case SMB2_OP_RENAME:
71938c8a9a5SSteve French 			if (rc)
72038c8a9a5SSteve French 				trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
72138c8a9a5SSteve French 			else
72238c8a9a5SSteve French 				trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
723886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
72438c8a9a5SSteve French 			break;
72538c8a9a5SSteve French 		case SMB2_OP_RMDIR:
72638c8a9a5SSteve French 			if (rc)
72738c8a9a5SSteve French 				trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
72838c8a9a5SSteve French 			else
72938c8a9a5SSteve French 				trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
730886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
73138c8a9a5SSteve French 			break;
73238c8a9a5SSteve French 		case SMB2_OP_SET_EOF:
73338c8a9a5SSteve French 			if (rc)
73438c8a9a5SSteve French 				trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
73538c8a9a5SSteve French 			else
73638c8a9a5SSteve French 				trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
737886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
73838c8a9a5SSteve French 			break;
73938c8a9a5SSteve French 		case SMB2_OP_SET_INFO:
74038c8a9a5SSteve French 			if (rc)
74138c8a9a5SSteve French 				trace_smb3_set_info_compound_err(xid,  ses->Suid,
74238c8a9a5SSteve French 								 tcon->tid, rc);
74338c8a9a5SSteve French 			else
74438c8a9a5SSteve French 				trace_smb3_set_info_compound_done(xid, ses->Suid,
74538c8a9a5SSteve French 								  tcon->tid);
746886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
74738c8a9a5SSteve French 			break;
74802bcf865SSteve French 		case SMB2_OP_SET_REPARSE:
74902bcf865SSteve French 			if (rc) {
75002bcf865SSteve French 				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
75102bcf865SSteve French 								    tcon->tid, rc);
75202bcf865SSteve French 			} else {
75302bcf865SSteve French 				trace_smb3_set_reparse_compound_done(xid, ses->Suid,
75402bcf865SSteve French 								     tcon->tid);
75502bcf865SSteve French 			}
75602bcf865SSteve French 			SMB2_ioctl_free(&rqst[num_rqst++]);
75702bcf865SSteve French 			break;
758a158bb66SSteve French 		case SMB2_OP_GET_REPARSE:
759a158bb66SSteve French 			if (!rc) {
760a158bb66SSteve French 				iov = &rsp_iov[i + 1];
761a158bb66SSteve French 				idata = in_iov[i].iov_base;
762a158bb66SSteve French 				idata->reparse.io.iov = *iov;
763a158bb66SSteve French 				idata->reparse.io.buftype = resp_buftype[i + 1];
764a158bb66SSteve French 				rbuf = reparse_buf_ptr(iov);
765a158bb66SSteve French 				if (IS_ERR(rbuf)) {
766a158bb66SSteve French 					rc = PTR_ERR(rbuf);
767a158bb66SSteve French 					trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
768a158bb66SSteve French 									    tcon->tid, rc);
769a158bb66SSteve French 				} else {
770a158bb66SSteve French 					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
771a158bb66SSteve French 					trace_smb3_set_reparse_compound_done(xid, ses->Suid,
772a158bb66SSteve French 									     tcon->tid);
773a158bb66SSteve French 				}
774a158bb66SSteve French 				memset(iov, 0, sizeof(*iov));
775a158bb66SSteve French 				resp_buftype[i + 1] = CIFS_NO_BUFFER;
776a158bb66SSteve French 			} else {
777a158bb66SSteve French 				trace_smb3_set_reparse_compound_err(xid, ses->Suid,
778a158bb66SSteve French 								    tcon->tid, rc);
779a158bb66SSteve French 			}
780a158bb66SSteve French 			SMB2_ioctl_free(&rqst[num_rqst++]);
781a158bb66SSteve French 			break;
7827449d736SSteve French 		case SMB2_OP_QUERY_WSL_EA:
7837449d736SSteve French 			if (!rc) {
7847449d736SSteve French 				idata = in_iov[i].iov_base;
7857449d736SSteve French 				qi_rsp = rsp_iov[i + 1].iov_base;
7867449d736SSteve French 				data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
7877449d736SSteve French 				size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
7887449d736SSteve French 				rc = check_wsl_eas(&rsp_iov[i + 1]);
7897449d736SSteve French 				if (!rc) {
7907449d736SSteve French 					memcpy(idata->wsl.eas, data[0], size[0]);
7917449d736SSteve French 					idata->wsl.eas_len = size[0];
7927449d736SSteve French 				}
7937449d736SSteve French 			}
7947449d736SSteve French 			if (!rc) {
7957449d736SSteve French 				trace_smb3_query_wsl_ea_compound_done(xid, ses->Suid,
7967449d736SSteve French 								      tcon->tid);
7977449d736SSteve French 			} else {
7987449d736SSteve French 				trace_smb3_query_wsl_ea_compound_err(xid, ses->Suid,
7997449d736SSteve French 								     tcon->tid, rc);
8007449d736SSteve French 			}
8017449d736SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
8027449d736SSteve French 			break;
80338c8a9a5SSteve French 		}
804886b7fb4SSteve French 	}
805886b7fb4SSteve French 	SMB2_close_free(&rqst[num_rqst]);
80638c8a9a5SSteve French 
807886b7fb4SSteve French 	num_cmds += 2;
808c5f44a3dSPaulo Alcantara 	if (out_iov && out_buftype) {
809886b7fb4SSteve French 		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
810886b7fb4SSteve French 		memcpy(out_buftype, resp_buftype,
811886b7fb4SSteve French 		       num_cmds * sizeof(*out_buftype));
81238c8a9a5SSteve French 	} else {
813886b7fb4SSteve French 		for (i = 0; i < num_cmds; i++)
814886b7fb4SSteve French 			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
81538c8a9a5SSteve French 	}
816433042a9SShyam Prasad N 	num_cmds -= 2; /* correct num_cmds as there could be a retry */
81738c8a9a5SSteve French 	kfree(vars);
818433042a9SShyam Prasad N 
819433042a9SShyam Prasad N 	if (is_replayable_error(rc) &&
820433042a9SShyam Prasad N 	    smb2_should_replay(tcon, &retries, &cur_sleep))
821433042a9SShyam Prasad N 		goto replay_again;
822433042a9SShyam Prasad N 
823433042a9SShyam Prasad N 	if (cfile)
824433042a9SShyam Prasad N 		cifsFileInfo_put(cfile);
825433042a9SShyam Prasad N 
82638c8a9a5SSteve French 	return rc;
82738c8a9a5SSteve French }
82838c8a9a5SSteve French 
parse_create_response(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,const struct kvec * iov)8295f71ebc4SPaulo Alcantara static int parse_create_response(struct cifs_open_info_data *data,
8305f71ebc4SPaulo Alcantara 				 struct cifs_sb_info *cifs_sb,
8315f71ebc4SPaulo Alcantara 				 const struct kvec *iov)
8325f71ebc4SPaulo Alcantara {
8335f71ebc4SPaulo Alcantara 	struct smb2_create_rsp *rsp = iov->iov_base;
8345f71ebc4SPaulo Alcantara 	bool reparse_point = false;
8355f71ebc4SPaulo Alcantara 	u32 tag = 0;
8365f71ebc4SPaulo Alcantara 	int rc = 0;
8375f71ebc4SPaulo Alcantara 
8385f71ebc4SPaulo Alcantara 	switch (rsp->hdr.Status) {
8397fb77d9cSPaulo Alcantara 	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
8407fb77d9cSPaulo Alcantara 		reparse_point = true;
8417fb77d9cSPaulo Alcantara 		break;
8425f71ebc4SPaulo Alcantara 	case STATUS_STOPPED_ON_SYMLINK:
8435f71ebc4SPaulo Alcantara 		rc = smb2_parse_symlink_response(cifs_sb, iov,
8445f71ebc4SPaulo Alcantara 						 &data->symlink_target);
8455f71ebc4SPaulo Alcantara 		if (rc)
8465f71ebc4SPaulo Alcantara 			return rc;
8475f71ebc4SPaulo Alcantara 		tag = IO_REPARSE_TAG_SYMLINK;
8485f71ebc4SPaulo Alcantara 		reparse_point = true;
8495f71ebc4SPaulo Alcantara 		break;
8505f71ebc4SPaulo Alcantara 	case STATUS_SUCCESS:
8515f71ebc4SPaulo Alcantara 		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
8525f71ebc4SPaulo Alcantara 		break;
8535f71ebc4SPaulo Alcantara 	}
8545f71ebc4SPaulo Alcantara 	data->reparse_point = reparse_point;
855df32e887SPaulo Alcantara 	data->reparse.tag = tag;
8565f71ebc4SPaulo Alcantara 	return rc;
8575f71ebc4SPaulo Alcantara }
8585f71ebc4SPaulo Alcantara 
smb2_query_path_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,struct cifs_open_info_data * data)8598b4e285dSPaulo Alcantara int smb2_query_path_info(const unsigned int xid,
8608b4e285dSPaulo Alcantara 			 struct cifs_tcon *tcon,
8618b4e285dSPaulo Alcantara 			 struct cifs_sb_info *cifs_sb,
8628b4e285dSPaulo Alcantara 			 const char *full_path,
8638b4e285dSPaulo Alcantara 			 struct cifs_open_info_data *data)
86438c8a9a5SSteve French {
865831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
86638c8a9a5SSteve French 	__u32 create_options = 0;
86738c8a9a5SSteve French 	struct cifsFileInfo *cfile;
86838c8a9a5SSteve French 	struct cached_fid *cfid = NULL;
8695f71ebc4SPaulo Alcantara 	struct smb2_hdr *hdr;
8707449d736SSteve French 	struct kvec in_iov[3], out_iov[3] = {};
871c5f44a3dSPaulo Alcantara 	int out_buftype[3] = {};
8727449d736SSteve French 	int cmds[3];
87338c8a9a5SSteve French 	bool islink;
8747449d736SSteve French 	int i, num_cmds = 0;
87538c8a9a5SSteve French 	int rc, rc2;
87638c8a9a5SSteve French 
8778b4e285dSPaulo Alcantara 	data->adjust_tz = false;
8788b4e285dSPaulo Alcantara 	data->reparse_point = false;
87938c8a9a5SSteve French 
880cfb8f73dSPaulo Alcantara 	/*
881cfb8f73dSPaulo Alcantara 	 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
882cfb8f73dSPaulo Alcantara 	 * Create SMB2_query_posix_info worker function to do non-compounded
883cfb8f73dSPaulo Alcantara 	 * query when we already have an open file handle for this. For now this
884cfb8f73dSPaulo Alcantara 	 * is fast enough (always using the compounded version).
885cfb8f73dSPaulo Alcantara 	 */
886cfb8f73dSPaulo Alcantara 	if (!tcon->posix_extensions) {
887cfb8f73dSPaulo Alcantara 		if (*full_path) {
88838c8a9a5SSteve French 			rc = -ENOENT;
889cfb8f73dSPaulo Alcantara 		} else {
890cfb8f73dSPaulo Alcantara 			rc = open_cached_dir(xid, tcon, full_path,
891cfb8f73dSPaulo Alcantara 					     cifs_sb, false, &cfid);
892cfb8f73dSPaulo Alcantara 		}
89338c8a9a5SSteve French 		/* If it is a root and its handle is cached then use it */
89438c8a9a5SSteve French 		if (!rc) {
89538c8a9a5SSteve French 			if (cfid->file_all_info_is_valid) {
896cfb8f73dSPaulo Alcantara 				memcpy(&data->fi, &cfid->file_all_info,
897cfb8f73dSPaulo Alcantara 				       sizeof(data->fi));
89838c8a9a5SSteve French 			} else {
899cfb8f73dSPaulo Alcantara 				rc = SMB2_query_info(xid, tcon,
900cfb8f73dSPaulo Alcantara 						     cfid->fid.persistent_fid,
901cfb8f73dSPaulo Alcantara 						     cfid->fid.volatile_fid,
902cfb8f73dSPaulo Alcantara 						     &data->fi);
90338c8a9a5SSteve French 			}
90438c8a9a5SSteve French 			close_cached_dir(cfid);
90538c8a9a5SSteve French 			return rc;
90638c8a9a5SSteve French 		}
9077449d736SSteve French 		cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
908cfb8f73dSPaulo Alcantara 	} else {
9097449d736SSteve French 		cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
910cfb8f73dSPaulo Alcantara 	}
91138c8a9a5SSteve French 
912a158bb66SSteve French 	in_iov[0].iov_base = data;
913a158bb66SSteve French 	in_iov[0].iov_len = sizeof(*data);
914a158bb66SSteve French 	in_iov[1] = in_iov[0];
9157449d736SSteve French 	in_iov[2] = in_iov[0];
916886b7fb4SSteve French 
91738c8a9a5SSteve French 	cifs_get_readable_path(tcon, full_path, &cfile);
918831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
919831ffbd1SPaulo Alcantara 			     FILE_OPEN, create_options, ACL_NO_MODE);
920886b7fb4SSteve French 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
9217449d736SSteve French 			      &oparms, in_iov, cmds, num_cmds,
9227449d736SSteve French 			      cfile, out_iov, out_buftype, NULL);
9235f71ebc4SPaulo Alcantara 	hdr = out_iov[0].iov_base;
9245f71ebc4SPaulo Alcantara 	/*
9255f71ebc4SPaulo Alcantara 	 * If first iov is unset, then SMB session was dropped or we've got a
9265f71ebc4SPaulo Alcantara 	 * cached open file (@cfile).
9275f71ebc4SPaulo Alcantara 	 */
9285f71ebc4SPaulo Alcantara 	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
92938c8a9a5SSteve French 		goto out;
93038c8a9a5SSteve French 
9315f71ebc4SPaulo Alcantara 	switch (rc) {
9325f71ebc4SPaulo Alcantara 	case 0:
9335f71ebc4SPaulo Alcantara 	case -EOPNOTSUPP:
934cfb8f73dSPaulo Alcantara 		/*
935cfb8f73dSPaulo Alcantara 		 * BB TODO: When support for special files added to Samba
936cfb8f73dSPaulo Alcantara 		 * re-verify this path.
937cfb8f73dSPaulo Alcantara 		 */
9385f71ebc4SPaulo Alcantara 		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
9395f71ebc4SPaulo Alcantara 		if (rc || !data->reparse_point)
9405f71ebc4SPaulo Alcantara 			goto out;
9415f71ebc4SPaulo Alcantara 
9427449d736SSteve French 		cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
9437449d736SSteve French 		/*
9447449d736SSteve French 		 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
9457449d736SSteve French 		 * response.
9467449d736SSteve French 		 */
9477449d736SSteve French 		if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
9487449d736SSteve French 			cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
9497449d736SSteve French 
950831ffbd1SPaulo Alcantara 		oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
9517449d736SSteve French 				     FILE_READ_ATTRIBUTES | FILE_READ_EA,
9527449d736SSteve French 				     FILE_OPEN, create_options |
9537449d736SSteve French 				     OPEN_REPARSE_POINT, ACL_NO_MODE);
95438c8a9a5SSteve French 		cifs_get_readable_path(tcon, full_path, &cfile);
95538c8a9a5SSteve French 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
956831ffbd1SPaulo Alcantara 				      &oparms, in_iov, cmds, num_cmds,
957831ffbd1SPaulo Alcantara 				      cfile, NULL, NULL, NULL);
9585f71ebc4SPaulo Alcantara 		break;
9595f71ebc4SPaulo Alcantara 	case -EREMOTE:
9605f71ebc4SPaulo Alcantara 		break;
9615f71ebc4SPaulo Alcantara 	default:
9625f71ebc4SPaulo Alcantara 		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
9635f71ebc4SPaulo Alcantara 			break;
96438c8a9a5SSteve French 		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
96538c8a9a5SSteve French 						     full_path, &islink);
96638c8a9a5SSteve French 		if (rc2) {
96738c8a9a5SSteve French 			rc = rc2;
96838c8a9a5SSteve French 			goto out;
96938c8a9a5SSteve French 		}
97038c8a9a5SSteve French 		if (islink)
97138c8a9a5SSteve French 			rc = -EREMOTE;
97238c8a9a5SSteve French 	}
97338c8a9a5SSteve French 
97438c8a9a5SSteve French out:
975a158bb66SSteve French 	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
976a158bb66SSteve French 		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
97738c8a9a5SSteve French 	return rc;
97838c8a9a5SSteve French }
97938c8a9a5SSteve French 
98038c8a9a5SSteve French int
smb2_mkdir(const unsigned int xid,struct inode * parent_inode,umode_t mode,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)98138c8a9a5SSteve French smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
98238c8a9a5SSteve French 	   struct cifs_tcon *tcon, const char *name,
98338c8a9a5SSteve French 	   struct cifs_sb_info *cifs_sb)
98438c8a9a5SSteve French {
985831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
986831ffbd1SPaulo Alcantara 
987831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
988831ffbd1SPaulo Alcantara 			     FILE_CREATE, CREATE_NOT_FILE, mode);
989831ffbd1SPaulo Alcantara 	return smb2_compound_op(xid, tcon, cifs_sb,
990831ffbd1SPaulo Alcantara 				name, &oparms, NULL,
991831ffbd1SPaulo Alcantara 				&(int){SMB2_OP_MKDIR}, 1,
992f93d145fSMeetakshi Setiya 				NULL, NULL, NULL, NULL);
99338c8a9a5SSteve French }
99438c8a9a5SSteve French 
99538c8a9a5SSteve French void
smb2_mkdir_setinfo(struct inode * inode,const char * name,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)99638c8a9a5SSteve French smb2_mkdir_setinfo(struct inode *inode, const char *name,
99738c8a9a5SSteve French 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
99838c8a9a5SSteve French 		   const unsigned int xid)
99938c8a9a5SSteve French {
1000831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1001886b7fb4SSteve French 	FILE_BASIC_INFO data = {};
100238c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i;
100338c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1004886b7fb4SSteve French 	struct kvec in_iov;
100538c8a9a5SSteve French 	u32 dosattrs;
100638c8a9a5SSteve French 	int tmprc;
100738c8a9a5SSteve French 
1008886b7fb4SSteve French 	in_iov.iov_base = &data;
1009886b7fb4SSteve French 	in_iov.iov_len = sizeof(data);
101038c8a9a5SSteve French 	cifs_i = CIFS_I(inode);
101138c8a9a5SSteve French 	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
101238c8a9a5SSteve French 	data.Attributes = cpu_to_le32(dosattrs);
101338c8a9a5SSteve French 	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1014831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1015831ffbd1SPaulo Alcantara 			     FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
101638c8a9a5SSteve French 	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1017831ffbd1SPaulo Alcantara 				 &oparms, &in_iov,
1018886b7fb4SSteve French 				 &(int){SMB2_OP_SET_INFO}, 1,
1019f93d145fSMeetakshi Setiya 				 cfile, NULL, NULL, NULL);
102038c8a9a5SSteve French 	if (tmprc == 0)
102138c8a9a5SSteve French 		cifs_i->cifsAttrs = dosattrs;
102238c8a9a5SSteve French }
102338c8a9a5SSteve French 
102438c8a9a5SSteve French int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)102538c8a9a5SSteve French smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
102638c8a9a5SSteve French 	   struct cifs_sb_info *cifs_sb)
102738c8a9a5SSteve French {
1028831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1029831ffbd1SPaulo Alcantara 
103038c8a9a5SSteve French 	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1031831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1032831ffbd1SPaulo Alcantara 			     FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1033831ffbd1SPaulo Alcantara 	return smb2_compound_op(xid, tcon, cifs_sb,
1034831ffbd1SPaulo Alcantara 				name, &oparms, NULL,
1035a90f37e3SSteve French 				&(int){SMB2_OP_RMDIR}, 1,
1036f93d145fSMeetakshi Setiya 				NULL, NULL, NULL, NULL);
103738c8a9a5SSteve French }
103838c8a9a5SSteve French 
103938c8a9a5SSteve French int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb,struct dentry * dentry)104038c8a9a5SSteve French smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1041f93d145fSMeetakshi Setiya 	    struct cifs_sb_info *cifs_sb, struct dentry *dentry)
104238c8a9a5SSteve French {
1043831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1044831ffbd1SPaulo Alcantara 
1045831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1046831ffbd1SPaulo Alcantara 			     DELETE, FILE_OPEN,
104738c8a9a5SSteve French 			     CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1048831ffbd1SPaulo Alcantara 			     ACL_NO_MODE);
1049831ffbd1SPaulo Alcantara 	int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1050831ffbd1SPaulo Alcantara 				  NULL, &(int){SMB2_OP_DELETE}, 1,
1051f93d145fSMeetakshi Setiya 				  NULL, NULL, NULL, dentry);
10521e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
10531e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1054831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1055831ffbd1SPaulo Alcantara 				      NULL, &(int){SMB2_OP_DELETE}, 1,
10561e60bc0eSMeetakshi Setiya 				      NULL, NULL, NULL, NULL);
10571e60bc0eSMeetakshi Setiya 	}
10581e60bc0eSMeetakshi Setiya 	return rc;
105938c8a9a5SSteve French }
106038c8a9a5SSteve French 
smb2_set_path_attr(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb,__u32 create_options,__u32 access,int command,struct cifsFileInfo * cfile,struct dentry * dentry)1061c586b0c7SPaulo Alcantara static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
106238c8a9a5SSteve French 			      const char *from_name, const char *to_name,
1063c586b0c7SPaulo Alcantara 			      struct cifs_sb_info *cifs_sb,
1064c586b0c7SPaulo Alcantara 			      __u32 create_options, __u32 access,
1065f93d145fSMeetakshi Setiya 			      int command, struct cifsFileInfo *cfile,
1066f93d145fSMeetakshi Setiya 				  struct dentry *dentry)
106738c8a9a5SSteve French {
1068831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1069886b7fb4SSteve French 	struct kvec in_iov;
107038c8a9a5SSteve French 	__le16 *smb2_to_name = NULL;
107138c8a9a5SSteve French 	int rc;
107238c8a9a5SSteve French 
107338c8a9a5SSteve French 	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
107438c8a9a5SSteve French 	if (smb2_to_name == NULL) {
107538c8a9a5SSteve French 		rc = -ENOMEM;
107638c8a9a5SSteve French 		goto smb2_rename_path;
107738c8a9a5SSteve French 	}
1078886b7fb4SSteve French 	in_iov.iov_base = smb2_to_name;
1079886b7fb4SSteve French 	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1080831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1081831ffbd1SPaulo Alcantara 			     create_options, ACL_NO_MODE);
1082831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1083831ffbd1SPaulo Alcantara 			      &oparms, &in_iov, &command, 1,
1084831ffbd1SPaulo Alcantara 			      cfile, NULL, NULL, dentry);
108538c8a9a5SSteve French smb2_rename_path:
108638c8a9a5SSteve French 	kfree(smb2_to_name);
108738c8a9a5SSteve French 	return rc;
108838c8a9a5SSteve French }
108938c8a9a5SSteve French 
smb2_rename_path(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)1090c586b0c7SPaulo Alcantara int smb2_rename_path(const unsigned int xid,
1091c586b0c7SPaulo Alcantara 		     struct cifs_tcon *tcon,
1092c586b0c7SPaulo Alcantara 		     struct dentry *source_dentry,
109338c8a9a5SSteve French 		     const char *from_name, const char *to_name,
109438c8a9a5SSteve French 		     struct cifs_sb_info *cifs_sb)
109538c8a9a5SSteve French {
109638c8a9a5SSteve French 	struct cifsFileInfo *cfile;
10978c944f8aSPaulo Alcantara 	__u32 co = file_create_options(source_dentry);
109838c8a9a5SSteve French 
109938c8a9a5SSteve French 	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
110038c8a9a5SSteve French 	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
110138c8a9a5SSteve French 
11021e60bc0eSMeetakshi Setiya 	int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1103f93d145fSMeetakshi Setiya 				  co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
11041e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
11051e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
11061e60bc0eSMeetakshi Setiya 		rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
11071e60bc0eSMeetakshi Setiya 				  co, DELETE, SMB2_OP_RENAME, cfile, NULL);
11081e60bc0eSMeetakshi Setiya 	}
11091e60bc0eSMeetakshi Setiya 	return rc;
111038c8a9a5SSteve French }
111138c8a9a5SSteve French 
smb2_create_hardlink(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)11128c944f8aSPaulo Alcantara int smb2_create_hardlink(const unsigned int xid,
11138c944f8aSPaulo Alcantara 			 struct cifs_tcon *tcon,
11148c944f8aSPaulo Alcantara 			 struct dentry *source_dentry,
111538c8a9a5SSteve French 			 const char *from_name, const char *to_name,
111638c8a9a5SSteve French 			 struct cifs_sb_info *cifs_sb)
111738c8a9a5SSteve French {
11188c944f8aSPaulo Alcantara 	__u32 co = file_create_options(source_dentry);
11198c944f8aSPaulo Alcantara 
1120c586b0c7SPaulo Alcantara 	return smb2_set_path_attr(xid, tcon, from_name, to_name,
11218c944f8aSPaulo Alcantara 				  cifs_sb, co, FILE_READ_ATTRIBUTES,
1122f93d145fSMeetakshi Setiya 				  SMB2_OP_HARDLINK, NULL, NULL);
112338c8a9a5SSteve French }
112438c8a9a5SSteve French 
112538c8a9a5SSteve French int
smb2_set_path_size(const unsigned int xid,struct cifs_tcon * tcon,const char * full_path,__u64 size,struct cifs_sb_info * cifs_sb,bool set_alloc,struct dentry * dentry)112638c8a9a5SSteve French smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
112738c8a9a5SSteve French 		   const char *full_path, __u64 size,
1128f93d145fSMeetakshi Setiya 		   struct cifs_sb_info *cifs_sb, bool set_alloc,
1129f93d145fSMeetakshi Setiya 		   struct dentry *dentry)
113038c8a9a5SSteve French {
1131831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
113238c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1133886b7fb4SSteve French 	struct kvec in_iov;
1134886b7fb4SSteve French 	__le64 eof = cpu_to_le64(size);
1135831ffbd1SPaulo Alcantara 	int rc;
113638c8a9a5SSteve French 
1137886b7fb4SSteve French 	in_iov.iov_base = &eof;
1138886b7fb4SSteve French 	in_iov.iov_len = sizeof(eof);
113938c8a9a5SSteve French 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1140831ffbd1SPaulo Alcantara 
1141831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1142831ffbd1SPaulo Alcantara 			     FILE_OPEN, 0, ACL_NO_MODE);
1143831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1144831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1145886b7fb4SSteve French 			      &(int){SMB2_OP_SET_EOF}, 1,
1146f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, dentry);
11471e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
11481e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1149831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb,
1150831ffbd1SPaulo Alcantara 				      full_path, &oparms, &in_iov,
11511e60bc0eSMeetakshi Setiya 				      &(int){SMB2_OP_SET_EOF}, 1,
11521e60bc0eSMeetakshi Setiya 				      cfile, NULL, NULL, NULL);
11531e60bc0eSMeetakshi Setiya 	}
11541e60bc0eSMeetakshi Setiya 	return rc;
115538c8a9a5SSteve French }
115638c8a9a5SSteve French 
115738c8a9a5SSteve French int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)115838c8a9a5SSteve French smb2_set_file_info(struct inode *inode, const char *full_path,
115938c8a9a5SSteve French 		   FILE_BASIC_INFO *buf, const unsigned int xid)
116038c8a9a5SSteve French {
1161831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
116238c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
116338c8a9a5SSteve French 	struct tcon_link *tlink;
116438c8a9a5SSteve French 	struct cifs_tcon *tcon;
116538c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1166886b7fb4SSteve French 	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
116738c8a9a5SSteve French 	int rc;
116838c8a9a5SSteve French 
116938c8a9a5SSteve French 	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
117038c8a9a5SSteve French 	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
117138c8a9a5SSteve French 	    (buf->Attributes == 0))
117238c8a9a5SSteve French 		return 0; /* would be a no op, no sense sending this */
117338c8a9a5SSteve French 
117438c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
117538c8a9a5SSteve French 	if (IS_ERR(tlink))
117638c8a9a5SSteve French 		return PTR_ERR(tlink);
117738c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
117838c8a9a5SSteve French 
117938c8a9a5SSteve French 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1180831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1181831ffbd1SPaulo Alcantara 			     FILE_OPEN, 0, ACL_NO_MODE);
1182831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1183831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1184a90f37e3SSteve French 			      &(int){SMB2_OP_SET_INFO}, 1,
1185f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, NULL);
118638c8a9a5SSteve French 	cifs_put_tlink(tlink);
118738c8a9a5SSteve French 	return rc;
118838c8a9a5SSteve French }
118902bcf865SSteve French 
smb2_get_reparse_inode(struct cifs_open_info_data * data,struct super_block * sb,const unsigned int xid,struct cifs_tcon * tcon,const char * full_path,struct kvec * reparse_iov,struct kvec * xattr_iov)119002bcf865SSteve French struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
119102bcf865SSteve French 				     struct super_block *sb,
119202bcf865SSteve French 				     const unsigned int xid,
119302bcf865SSteve French 				     struct cifs_tcon *tcon,
119402bcf865SSteve French 				     const char *full_path,
1195df0a8a19SPaulo Alcantara 				     struct kvec *reparse_iov,
1196df0a8a19SPaulo Alcantara 				     struct kvec *xattr_iov)
119702bcf865SSteve French {
1198831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
119902bcf865SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
120002bcf865SSteve French 	struct cifsFileInfo *cfile;
120102bcf865SSteve French 	struct inode *new = NULL;
120202bcf865SSteve French 	struct kvec in_iov[2];
120302bcf865SSteve French 	int cmds[2];
120402bcf865SSteve French 	int rc;
120502bcf865SSteve French 
1206831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1207831ffbd1SPaulo Alcantara 			     SYNCHRONIZE | DELETE |
120802bcf865SSteve French 			     FILE_READ_ATTRIBUTES |
1209831ffbd1SPaulo Alcantara 			     FILE_WRITE_ATTRIBUTES,
1210831ffbd1SPaulo Alcantara 			     FILE_CREATE,
1211831ffbd1SPaulo Alcantara 			     CREATE_NOT_DIR | OPEN_REPARSE_POINT,
1212831ffbd1SPaulo Alcantara 			     ACL_NO_MODE);
1213df0a8a19SPaulo Alcantara 	if (xattr_iov)
1214df0a8a19SPaulo Alcantara 		oparms.ea_cctx = xattr_iov;
1215df0a8a19SPaulo Alcantara 
121602bcf865SSteve French 	cmds[0] = SMB2_OP_SET_REPARSE;
1217df0a8a19SPaulo Alcantara 	in_iov[0] = *reparse_iov;
121802bcf865SSteve French 	in_iov[1].iov_base = data;
121902bcf865SSteve French 	in_iov[1].iov_len = sizeof(*data);
122002bcf865SSteve French 
122102bcf865SSteve French 	if (tcon->posix_extensions) {
122202bcf865SSteve French 		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
122302bcf865SSteve French 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1224831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1225831ffbd1SPaulo Alcantara 				      in_iov, cmds, 2, cfile, NULL, NULL, NULL);
122602bcf865SSteve French 		if (!rc) {
122702bcf865SSteve French 			rc = smb311_posix_get_inode_info(&new, full_path,
122802bcf865SSteve French 							 data, sb, xid);
122902bcf865SSteve French 		}
123002bcf865SSteve French 	} else {
123102bcf865SSteve French 		cmds[1] = SMB2_OP_QUERY_INFO;
123202bcf865SSteve French 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1233831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1234831ffbd1SPaulo Alcantara 				      in_iov, cmds, 2, cfile, NULL, NULL, NULL);
123502bcf865SSteve French 		if (!rc) {
123602bcf865SSteve French 			rc = cifs_get_inode_info(&new, full_path,
123702bcf865SSteve French 						 data, sb, xid, NULL);
123802bcf865SSteve French 		}
123902bcf865SSteve French 	}
124002bcf865SSteve French 	return rc ? ERR_PTR(rc) : new;
124102bcf865SSteve French }
1242870c73abSPaulo Alcantara 
smb2_query_reparse_point(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,u32 * tag,struct kvec * rsp,int * rsp_buftype)1243870c73abSPaulo Alcantara int smb2_query_reparse_point(const unsigned int xid,
1244870c73abSPaulo Alcantara 			     struct cifs_tcon *tcon,
1245870c73abSPaulo Alcantara 			     struct cifs_sb_info *cifs_sb,
1246870c73abSPaulo Alcantara 			     const char *full_path,
1247870c73abSPaulo Alcantara 			     u32 *tag, struct kvec *rsp,
1248870c73abSPaulo Alcantara 			     int *rsp_buftype)
1249870c73abSPaulo Alcantara {
1250831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1251870c73abSPaulo Alcantara 	struct cifs_open_info_data data = {};
1252870c73abSPaulo Alcantara 	struct cifsFileInfo *cfile;
1253870c73abSPaulo Alcantara 	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1254870c73abSPaulo Alcantara 	int rc;
1255870c73abSPaulo Alcantara 
1256870c73abSPaulo Alcantara 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1257870c73abSPaulo Alcantara 
1258870c73abSPaulo Alcantara 	cifs_get_readable_path(tcon, full_path, &cfile);
1259831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
1260831ffbd1SPaulo Alcantara 			     FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1261831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1262831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1263a90f37e3SSteve French 			      &(int){SMB2_OP_GET_REPARSE}, 1,
1264f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, NULL);
1265870c73abSPaulo Alcantara 	if (rc)
1266870c73abSPaulo Alcantara 		goto out;
1267870c73abSPaulo Alcantara 
1268870c73abSPaulo Alcantara 	*tag = data.reparse.tag;
1269870c73abSPaulo Alcantara 	*rsp = data.reparse.io.iov;
1270870c73abSPaulo Alcantara 	*rsp_buftype = data.reparse.io.buftype;
1271870c73abSPaulo Alcantara 	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1272870c73abSPaulo Alcantara 	data.reparse.io.buftype = CIFS_NO_BUFFER;
1273870c73abSPaulo Alcantara out:
1274870c73abSPaulo Alcantara 	cifs_free_open_info(&data);
1275870c73abSPaulo Alcantara 	return rc;
1276870c73abSPaulo Alcantara }
1277