xref: /openbmc/linux/fs/smb/client/smb2inode.c (revision 360823a09426347ea8f232b0b0b5156d0aed0302)
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 
17938c8a9a5SSteve French 	struct smb2_query_info_rsp *qi_rsp = NULL;
1805ddcc9e9SPaulo Alcantara 	struct smb2_compound_vars *vars = NULL;
1815ddcc9e9SPaulo Alcantara 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
18238c8a9a5SSteve French 	struct cifs_open_info_data *idata;
1835ddcc9e9SPaulo Alcantara 	struct cifs_ses *ses = tcon->ses;
1845ddcc9e9SPaulo Alcantara 	struct reparse_data_buffer *rbuf;
1855ddcc9e9SPaulo Alcantara 	struct TCP_Server_Info *server;
1865ddcc9e9SPaulo Alcantara 	int resp_buftype[MAX_COMPOUND];
187433042a9SShyam Prasad N 	int retries = 0, cur_sleep = 1;
1885ddcc9e9SPaulo Alcantara 	__u8 delete_pending[8] = {1,};
1895ddcc9e9SPaulo Alcantara 	struct kvec *rsp_iov, *iov;
1905ddcc9e9SPaulo Alcantara 	struct inode *inode = NULL;
1915ddcc9e9SPaulo Alcantara 	__le16 *utf16_path = NULL;
1925ddcc9e9SPaulo Alcantara 	struct smb_rqst *rqst;
1935ddcc9e9SPaulo Alcantara 	unsigned int size[2];
1945ddcc9e9SPaulo Alcantara 	struct cifs_fid fid;
1955ddcc9e9SPaulo Alcantara 	int num_rqst = 0, i;
1965ddcc9e9SPaulo Alcantara 	unsigned int len;
1975ddcc9e9SPaulo Alcantara 	int tmp_rc, rc;
1985ddcc9e9SPaulo Alcantara 	int flags = 0;
1995ddcc9e9SPaulo Alcantara 	void *data[2];
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++;
301*7a5f926bSRuben Devos 			trace_smb3_query_info_compound_enter(xid, tcon->tid,
302*7a5f926bSRuben Devos 							     ses->Suid, 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) +
31846c22d37SChenXiaoSong 							  (sizeof(struct smb_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) +
32846c22d37SChenXiaoSong 							  (sizeof(struct smb_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++;
337*7a5f926bSRuben Devos 			trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
338*7a5f926bSRuben Devos 								   ses->Suid, full_path);
33938c8a9a5SSteve French 			break;
34038c8a9a5SSteve French 		case SMB2_OP_DELETE:
341*7a5f926bSRuben Devos 			trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, 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 			 */
348*7a5f926bSRuben Devos 			trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, 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++]);
366*7a5f926bSRuben Devos 			trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, 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++;
401*7a5f926bSRuben Devos 			trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, 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++;
432*7a5f926bSRuben Devos 			trace_smb3_set_info_compound_enter(xid, tcon->tid,
433*7a5f926bSRuben Devos 							   ses->Suid, 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++;
472*7a5f926bSRuben Devos 			trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, 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++]);
499*7a5f926bSRuben Devos 			trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, 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++;
526*7a5f926bSRuben Devos 			trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
527*7a5f926bSRuben Devos 							      ses->Suid, 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++;
552*7a5f926bSRuben Devos 			trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
553*7a5f926bSRuben Devos 							      ses->Suid, 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 
6405ddcc9e9SPaulo Alcantara 	tmp_rc = rc;
641886b7fb4SSteve French 	for (i = 0; i < num_cmds; i++) {
6425ddcc9e9SPaulo Alcantara 		char *buf = rsp_iov[i + i].iov_base;
6435ddcc9e9SPaulo Alcantara 
6445ddcc9e9SPaulo Alcantara 		if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
6455ddcc9e9SPaulo Alcantara 			rc = server->ops->map_error(buf, false);
6465ddcc9e9SPaulo Alcantara 		else
6475ddcc9e9SPaulo Alcantara 			rc = tmp_rc;
648886b7fb4SSteve French 		switch (cmds[i]) {
64938c8a9a5SSteve French 		case SMB2_OP_QUERY_INFO:
650886b7fb4SSteve French 			idata = in_iov[i].iov_base;
65138c8a9a5SSteve French 			if (rc == 0 && cfile && cfile->symlink_target) {
65238c8a9a5SSteve French 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
65338c8a9a5SSteve French 				if (!idata->symlink_target)
65438c8a9a5SSteve French 					rc = -ENOMEM;
65538c8a9a5SSteve French 			}
65638c8a9a5SSteve French 			if (rc == 0) {
65738c8a9a5SSteve French 				qi_rsp = (struct smb2_query_info_rsp *)
658886b7fb4SSteve French 					rsp_iov[i + 1].iov_base;
65938c8a9a5SSteve French 				rc = smb2_validate_and_copy_iov(
66038c8a9a5SSteve French 					le16_to_cpu(qi_rsp->OutputBufferOffset),
66138c8a9a5SSteve French 					le32_to_cpu(qi_rsp->OutputBufferLength),
662886b7fb4SSteve French 					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
66338c8a9a5SSteve French 			}
664886b7fb4SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
66538c8a9a5SSteve French 			if (rc)
666*7a5f926bSRuben Devos 				trace_smb3_query_info_compound_err(xid,  tcon->tid,
667*7a5f926bSRuben Devos 								   ses->Suid, rc);
66838c8a9a5SSteve French 			else
669*7a5f926bSRuben Devos 				trace_smb3_query_info_compound_done(xid, tcon->tid,
670*7a5f926bSRuben Devos 								    ses->Suid);
67138c8a9a5SSteve French 			break;
67238c8a9a5SSteve French 		case SMB2_OP_POSIX_QUERY_INFO:
673886b7fb4SSteve French 			idata = in_iov[i].iov_base;
67438c8a9a5SSteve French 			if (rc == 0 && cfile && cfile->symlink_target) {
67538c8a9a5SSteve French 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
67638c8a9a5SSteve French 				if (!idata->symlink_target)
67738c8a9a5SSteve French 					rc = -ENOMEM;
67838c8a9a5SSteve French 			}
67938c8a9a5SSteve French 			if (rc == 0) {
68038c8a9a5SSteve French 				qi_rsp = (struct smb2_query_info_rsp *)
681886b7fb4SSteve French 					rsp_iov[i + 1].iov_base;
68238c8a9a5SSteve French 				rc = smb2_validate_and_copy_iov(
68338c8a9a5SSteve French 					le16_to_cpu(qi_rsp->OutputBufferOffset),
68438c8a9a5SSteve French 					le32_to_cpu(qi_rsp->OutputBufferLength),
685886b7fb4SSteve French 					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
68638c8a9a5SSteve French 					(char *)&idata->posix_fi);
68738c8a9a5SSteve French 			}
688a90f37e3SSteve French 			if (rc == 0)
689a90f37e3SSteve French 				rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
69038c8a9a5SSteve French 
691886b7fb4SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
69238c8a9a5SSteve French 			if (rc)
693*7a5f926bSRuben Devos 				trace_smb3_posix_query_info_compound_err(xid,  tcon->tid,
694*7a5f926bSRuben Devos 									 ses->Suid, rc);
69538c8a9a5SSteve French 			else
696*7a5f926bSRuben Devos 				trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
697*7a5f926bSRuben Devos 									  ses->Suid);
69838c8a9a5SSteve French 			break;
69938c8a9a5SSteve French 		case SMB2_OP_DELETE:
70038c8a9a5SSteve French 			if (rc)
701*7a5f926bSRuben Devos 				trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
702b6e27f7fSSteve French 			else {
703b6e27f7fSSteve French 				/*
704b6e27f7fSSteve French 				 * If dentry (hence, inode) is NULL, lease break is going to
705b6e27f7fSSteve French 				 * take care of degrading leases on handles for deleted files.
706b6e27f7fSSteve French 				 */
707b6e27f7fSSteve French 				if (inode)
708b6e27f7fSSteve French 					cifs_mark_open_handles_for_deleted_file(inode, full_path);
709*7a5f926bSRuben Devos 				trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
710b6e27f7fSSteve French 			}
71138c8a9a5SSteve French 			break;
71238c8a9a5SSteve French 		case SMB2_OP_MKDIR:
71338c8a9a5SSteve French 			if (rc)
714*7a5f926bSRuben Devos 				trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
71538c8a9a5SSteve French 			else
716*7a5f926bSRuben Devos 				trace_smb3_mkdir_done(xid, tcon->tid, ses->Suid);
71738c8a9a5SSteve French 			break;
71838c8a9a5SSteve French 		case SMB2_OP_HARDLINK:
71938c8a9a5SSteve French 			if (rc)
720*7a5f926bSRuben Devos 				trace_smb3_hardlink_err(xid,  tcon->tid, ses->Suid, rc);
72138c8a9a5SSteve French 			else
722*7a5f926bSRuben Devos 				trace_smb3_hardlink_done(xid, tcon->tid, ses->Suid);
723886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
72438c8a9a5SSteve French 			break;
72538c8a9a5SSteve French 		case SMB2_OP_RENAME:
72638c8a9a5SSteve French 			if (rc)
727*7a5f926bSRuben Devos 				trace_smb3_rename_err(xid, tcon->tid, ses->Suid, rc);
72838c8a9a5SSteve French 			else
729*7a5f926bSRuben Devos 				trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
730886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
73138c8a9a5SSteve French 			break;
73238c8a9a5SSteve French 		case SMB2_OP_RMDIR:
73338c8a9a5SSteve French 			if (rc)
734*7a5f926bSRuben Devos 				trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
73538c8a9a5SSteve French 			else
736*7a5f926bSRuben Devos 				trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
737886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
73838c8a9a5SSteve French 			break;
73938c8a9a5SSteve French 		case SMB2_OP_SET_EOF:
74038c8a9a5SSteve French 			if (rc)
741*7a5f926bSRuben Devos 				trace_smb3_set_eof_err(xid, tcon->tid, ses->Suid, rc);
74238c8a9a5SSteve French 			else
743*7a5f926bSRuben Devos 				trace_smb3_set_eof_done(xid, tcon->tid, ses->Suid);
744886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
74538c8a9a5SSteve French 			break;
74638c8a9a5SSteve French 		case SMB2_OP_SET_INFO:
74738c8a9a5SSteve French 			if (rc)
748*7a5f926bSRuben Devos 				trace_smb3_set_info_compound_err(xid,  tcon->tid,
749*7a5f926bSRuben Devos 								 ses->Suid, rc);
75038c8a9a5SSteve French 			else
751*7a5f926bSRuben Devos 				trace_smb3_set_info_compound_done(xid, tcon->tid,
752*7a5f926bSRuben Devos 								  ses->Suid);
753886b7fb4SSteve French 			SMB2_set_info_free(&rqst[num_rqst++]);
75438c8a9a5SSteve French 			break;
75502bcf865SSteve French 		case SMB2_OP_SET_REPARSE:
75602bcf865SSteve French 			if (rc) {
757*7a5f926bSRuben Devos 				trace_smb3_set_reparse_compound_err(xid, tcon->tid,
758*7a5f926bSRuben Devos 								    ses->Suid, rc);
75902bcf865SSteve French 			} else {
760*7a5f926bSRuben Devos 				trace_smb3_set_reparse_compound_done(xid, tcon->tid,
761*7a5f926bSRuben Devos 								     ses->Suid);
76202bcf865SSteve French 			}
76302bcf865SSteve French 			SMB2_ioctl_free(&rqst[num_rqst++]);
76402bcf865SSteve French 			break;
765a158bb66SSteve French 		case SMB2_OP_GET_REPARSE:
766a158bb66SSteve French 			if (!rc) {
767a158bb66SSteve French 				iov = &rsp_iov[i + 1];
768a158bb66SSteve French 				idata = in_iov[i].iov_base;
769a158bb66SSteve French 				idata->reparse.io.iov = *iov;
770a158bb66SSteve French 				idata->reparse.io.buftype = resp_buftype[i + 1];
771a158bb66SSteve French 				rbuf = reparse_buf_ptr(iov);
772a158bb66SSteve French 				if (IS_ERR(rbuf)) {
773a158bb66SSteve French 					rc = PTR_ERR(rbuf);
774*7a5f926bSRuben Devos 					trace_smb3_get_reparse_compound_err(xid, tcon->tid,
775*7a5f926bSRuben Devos 									    ses->Suid, rc);
776a158bb66SSteve French 				} else {
777a158bb66SSteve French 					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
778*7a5f926bSRuben Devos 					trace_smb3_get_reparse_compound_done(xid, tcon->tid,
779*7a5f926bSRuben Devos 									     ses->Suid);
780a158bb66SSteve French 				}
781a158bb66SSteve French 				memset(iov, 0, sizeof(*iov));
782a158bb66SSteve French 				resp_buftype[i + 1] = CIFS_NO_BUFFER;
783a158bb66SSteve French 			} else {
784*7a5f926bSRuben Devos 				trace_smb3_get_reparse_compound_err(xid, tcon->tid,
785*7a5f926bSRuben Devos 								    ses->Suid, rc);
786a158bb66SSteve French 			}
787a158bb66SSteve French 			SMB2_ioctl_free(&rqst[num_rqst++]);
788a158bb66SSteve French 			break;
7897449d736SSteve French 		case SMB2_OP_QUERY_WSL_EA:
7907449d736SSteve French 			if (!rc) {
7917449d736SSteve French 				idata = in_iov[i].iov_base;
7927449d736SSteve French 				qi_rsp = rsp_iov[i + 1].iov_base;
7937449d736SSteve French 				data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
7947449d736SSteve French 				size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
7957449d736SSteve French 				rc = check_wsl_eas(&rsp_iov[i + 1]);
7967449d736SSteve French 				if (!rc) {
7977449d736SSteve French 					memcpy(idata->wsl.eas, data[0], size[0]);
7987449d736SSteve French 					idata->wsl.eas_len = size[0];
7997449d736SSteve French 				}
8007449d736SSteve French 			}
8017449d736SSteve French 			if (!rc) {
802*7a5f926bSRuben Devos 				trace_smb3_query_wsl_ea_compound_done(xid, tcon->tid,
803*7a5f926bSRuben Devos 								      ses->Suid);
8047449d736SSteve French 			} else {
805*7a5f926bSRuben Devos 				trace_smb3_query_wsl_ea_compound_err(xid, tcon->tid,
806*7a5f926bSRuben Devos 								     ses->Suid, rc);
8077449d736SSteve French 			}
8087449d736SSteve French 			SMB2_query_info_free(&rqst[num_rqst++]);
8097449d736SSteve French 			break;
81038c8a9a5SSteve French 		}
811886b7fb4SSteve French 	}
812886b7fb4SSteve French 	SMB2_close_free(&rqst[num_rqst]);
8135ddcc9e9SPaulo Alcantara 	rc = tmp_rc;
81438c8a9a5SSteve French 
815886b7fb4SSteve French 	num_cmds += 2;
816c5f44a3dSPaulo Alcantara 	if (out_iov && out_buftype) {
817886b7fb4SSteve French 		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
818886b7fb4SSteve French 		memcpy(out_buftype, resp_buftype,
819886b7fb4SSteve French 		       num_cmds * sizeof(*out_buftype));
82038c8a9a5SSteve French 	} else {
821886b7fb4SSteve French 		for (i = 0; i < num_cmds; i++)
822886b7fb4SSteve French 			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
82338c8a9a5SSteve French 	}
824433042a9SShyam Prasad N 	num_cmds -= 2; /* correct num_cmds as there could be a retry */
82538c8a9a5SSteve French 	kfree(vars);
826433042a9SShyam Prasad N 
827433042a9SShyam Prasad N 	if (is_replayable_error(rc) &&
828433042a9SShyam Prasad N 	    smb2_should_replay(tcon, &retries, &cur_sleep))
829433042a9SShyam Prasad N 		goto replay_again;
830433042a9SShyam Prasad N 
831433042a9SShyam Prasad N 	if (cfile)
832433042a9SShyam Prasad N 		cifsFileInfo_put(cfile);
833433042a9SShyam Prasad N 
83438c8a9a5SSteve French 	return rc;
83538c8a9a5SSteve French }
83638c8a9a5SSteve French 
parse_create_response(struct cifs_open_info_data * data,struct cifs_sb_info * cifs_sb,const char * full_path,const struct kvec * iov)8375f71ebc4SPaulo Alcantara static int parse_create_response(struct cifs_open_info_data *data,
8385f71ebc4SPaulo Alcantara 				 struct cifs_sb_info *cifs_sb,
839430afd3eSPali Rohár 				 const char *full_path,
8405f71ebc4SPaulo Alcantara 				 const struct kvec *iov)
8415f71ebc4SPaulo Alcantara {
8425f71ebc4SPaulo Alcantara 	struct smb2_create_rsp *rsp = iov->iov_base;
8435f71ebc4SPaulo Alcantara 	bool reparse_point = false;
8445f71ebc4SPaulo Alcantara 	u32 tag = 0;
8455f71ebc4SPaulo Alcantara 	int rc = 0;
8465f71ebc4SPaulo Alcantara 
8475f71ebc4SPaulo Alcantara 	switch (rsp->hdr.Status) {
8487fb77d9cSPaulo Alcantara 	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
8497fb77d9cSPaulo Alcantara 		reparse_point = true;
8507fb77d9cSPaulo Alcantara 		break;
8515f71ebc4SPaulo Alcantara 	case STATUS_STOPPED_ON_SYMLINK:
8525f71ebc4SPaulo Alcantara 		rc = smb2_parse_symlink_response(cifs_sb, iov,
853430afd3eSPali Rohár 						 full_path,
8545f71ebc4SPaulo Alcantara 						 &data->symlink_target);
8555f71ebc4SPaulo Alcantara 		if (rc)
8565f71ebc4SPaulo Alcantara 			return rc;
8575f71ebc4SPaulo Alcantara 		tag = IO_REPARSE_TAG_SYMLINK;
8585f71ebc4SPaulo Alcantara 		reparse_point = true;
8595f71ebc4SPaulo Alcantara 		break;
8605f71ebc4SPaulo Alcantara 	case STATUS_SUCCESS:
8615f71ebc4SPaulo Alcantara 		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
8625f71ebc4SPaulo Alcantara 		break;
8635f71ebc4SPaulo Alcantara 	}
8645f71ebc4SPaulo Alcantara 	data->reparse_point = reparse_point;
865df32e887SPaulo Alcantara 	data->reparse.tag = tag;
8665f71ebc4SPaulo Alcantara 	return rc;
8675f71ebc4SPaulo Alcantara }
8685f71ebc4SPaulo Alcantara 
8695ddcc9e9SPaulo Alcantara /* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
ea_unsupported(int * cmds,int num_cmds,struct kvec * out_iov,int * out_buftype)8705ddcc9e9SPaulo Alcantara static bool ea_unsupported(int *cmds, int num_cmds,
8715ddcc9e9SPaulo Alcantara 			   struct kvec *out_iov, int *out_buftype)
8725ddcc9e9SPaulo Alcantara {
8735ddcc9e9SPaulo Alcantara 	int i;
8745ddcc9e9SPaulo Alcantara 
8755ddcc9e9SPaulo Alcantara 	if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
8765ddcc9e9SPaulo Alcantara 		return false;
8775ddcc9e9SPaulo Alcantara 
8785ddcc9e9SPaulo Alcantara 	for (i = 1; i < num_cmds - 1; i++) {
8795ddcc9e9SPaulo Alcantara 		struct smb2_hdr *hdr = out_iov[i].iov_base;
8805ddcc9e9SPaulo Alcantara 
8815ddcc9e9SPaulo Alcantara 		if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
8825ddcc9e9SPaulo Alcantara 		    hdr->Status != STATUS_SUCCESS)
8835ddcc9e9SPaulo Alcantara 			return false;
8845ddcc9e9SPaulo Alcantara 	}
8855ddcc9e9SPaulo Alcantara 	return true;
8865ddcc9e9SPaulo Alcantara }
8875ddcc9e9SPaulo Alcantara 
free_rsp_iov(struct kvec * iovs,int * buftype,int count)8885ddcc9e9SPaulo Alcantara static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
8895ddcc9e9SPaulo Alcantara {
8905ddcc9e9SPaulo Alcantara 	int i;
8915ddcc9e9SPaulo Alcantara 
8925ddcc9e9SPaulo Alcantara 	for (i = 0; i < count; i++) {
8935ddcc9e9SPaulo Alcantara 		free_rsp_buf(buftype[i], iovs[i].iov_base);
8945ddcc9e9SPaulo Alcantara 		memset(&iovs[i], 0, sizeof(*iovs));
8955ddcc9e9SPaulo Alcantara 		buftype[i] = CIFS_NO_BUFFER;
8965ddcc9e9SPaulo Alcantara 	}
8975ddcc9e9SPaulo Alcantara }
8985ddcc9e9SPaulo 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)8998b4e285dSPaulo Alcantara int smb2_query_path_info(const unsigned int xid,
9008b4e285dSPaulo Alcantara 			 struct cifs_tcon *tcon,
9018b4e285dSPaulo Alcantara 			 struct cifs_sb_info *cifs_sb,
9028b4e285dSPaulo Alcantara 			 const char *full_path,
9038b4e285dSPaulo Alcantara 			 struct cifs_open_info_data *data)
90438c8a9a5SSteve French {
9055ddcc9e9SPaulo Alcantara 	struct kvec in_iov[3], out_iov[5] = {};
90638c8a9a5SSteve French 	struct cached_fid *cfid = NULL;
9075ddcc9e9SPaulo Alcantara 	struct cifs_open_parms oparms;
9085ddcc9e9SPaulo Alcantara 	struct cifsFileInfo *cfile;
9095ddcc9e9SPaulo Alcantara 	__u32 create_options = 0;
9105ddcc9e9SPaulo Alcantara 	int out_buftype[5] = {};
9115f71ebc4SPaulo Alcantara 	struct smb2_hdr *hdr;
9125ddcc9e9SPaulo Alcantara 	int num_cmds = 0;
9137449d736SSteve French 	int cmds[3];
91438c8a9a5SSteve French 	bool islink;
91538c8a9a5SSteve French 	int rc, rc2;
91638c8a9a5SSteve French 
9178b4e285dSPaulo Alcantara 	data->adjust_tz = false;
9188b4e285dSPaulo Alcantara 	data->reparse_point = false;
91938c8a9a5SSteve French 
920cfb8f73dSPaulo Alcantara 	/*
921cfb8f73dSPaulo Alcantara 	 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
922cfb8f73dSPaulo Alcantara 	 * Create SMB2_query_posix_info worker function to do non-compounded
923cfb8f73dSPaulo Alcantara 	 * query when we already have an open file handle for this. For now this
924cfb8f73dSPaulo Alcantara 	 * is fast enough (always using the compounded version).
925cfb8f73dSPaulo Alcantara 	 */
926cfb8f73dSPaulo Alcantara 	if (!tcon->posix_extensions) {
927cfb8f73dSPaulo Alcantara 		if (*full_path) {
92838c8a9a5SSteve French 			rc = -ENOENT;
929cfb8f73dSPaulo Alcantara 		} else {
930cfb8f73dSPaulo Alcantara 			rc = open_cached_dir(xid, tcon, full_path,
931cfb8f73dSPaulo Alcantara 					     cifs_sb, false, &cfid);
932cfb8f73dSPaulo Alcantara 		}
93338c8a9a5SSteve French 		/* If it is a root and its handle is cached then use it */
93438c8a9a5SSteve French 		if (!rc) {
93538c8a9a5SSteve French 			if (cfid->file_all_info_is_valid) {
936cfb8f73dSPaulo Alcantara 				memcpy(&data->fi, &cfid->file_all_info,
937cfb8f73dSPaulo Alcantara 				       sizeof(data->fi));
93838c8a9a5SSteve French 			} else {
939cfb8f73dSPaulo Alcantara 				rc = SMB2_query_info(xid, tcon,
940cfb8f73dSPaulo Alcantara 						     cfid->fid.persistent_fid,
941cfb8f73dSPaulo Alcantara 						     cfid->fid.volatile_fid,
942cfb8f73dSPaulo Alcantara 						     &data->fi);
94338c8a9a5SSteve French 			}
94438c8a9a5SSteve French 			close_cached_dir(cfid);
94538c8a9a5SSteve French 			return rc;
94638c8a9a5SSteve French 		}
9477449d736SSteve French 		cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
948cfb8f73dSPaulo Alcantara 	} else {
9497449d736SSteve French 		cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
950cfb8f73dSPaulo Alcantara 	}
95138c8a9a5SSteve French 
952a158bb66SSteve French 	in_iov[0].iov_base = data;
953a158bb66SSteve French 	in_iov[0].iov_len = sizeof(*data);
954a158bb66SSteve French 	in_iov[1] = in_iov[0];
9557449d736SSteve French 	in_iov[2] = in_iov[0];
956886b7fb4SSteve French 
95738c8a9a5SSteve French 	cifs_get_readable_path(tcon, full_path, &cfile);
958831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
959831ffbd1SPaulo Alcantara 			     FILE_OPEN, create_options, ACL_NO_MODE);
960886b7fb4SSteve French 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
9617449d736SSteve French 			      &oparms, in_iov, cmds, num_cmds,
9627449d736SSteve French 			      cfile, out_iov, out_buftype, NULL);
9635f71ebc4SPaulo Alcantara 	hdr = out_iov[0].iov_base;
9645f71ebc4SPaulo Alcantara 	/*
9655f71ebc4SPaulo Alcantara 	 * If first iov is unset, then SMB session was dropped or we've got a
9665f71ebc4SPaulo Alcantara 	 * cached open file (@cfile).
9675f71ebc4SPaulo Alcantara 	 */
9685f71ebc4SPaulo Alcantara 	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
96938c8a9a5SSteve French 		goto out;
97038c8a9a5SSteve French 
9715f71ebc4SPaulo Alcantara 	switch (rc) {
9725f71ebc4SPaulo Alcantara 	case 0:
973430afd3eSPali Rohár 		rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
9740397a48cSPaulo Alcantara 		break;
9755f71ebc4SPaulo Alcantara 	case -EOPNOTSUPP:
976cfb8f73dSPaulo Alcantara 		/*
977cfb8f73dSPaulo Alcantara 		 * BB TODO: When support for special files added to Samba
978cfb8f73dSPaulo Alcantara 		 * re-verify this path.
979cfb8f73dSPaulo Alcantara 		 */
980430afd3eSPali Rohár 		rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
9815f71ebc4SPaulo Alcantara 		if (rc || !data->reparse_point)
9825f71ebc4SPaulo Alcantara 			goto out;
9835f71ebc4SPaulo Alcantara 
9847449d736SSteve French 		/*
9857449d736SSteve French 		 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
9867449d736SSteve French 		 * response.
9877449d736SSteve French 		 */
9887449d736SSteve French 		if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
9897449d736SSteve French 			cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
9905ddcc9e9SPaulo Alcantara 		if (!tcon->posix_extensions)
9915ddcc9e9SPaulo Alcantara 			cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
9927449d736SSteve French 
993831ffbd1SPaulo Alcantara 		oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
99477e5d743SPaulo Alcantara 				     FILE_READ_ATTRIBUTES |
99577e5d743SPaulo Alcantara 				     FILE_READ_EA | SYNCHRONIZE,
9967449d736SSteve French 				     FILE_OPEN, create_options |
9977449d736SSteve French 				     OPEN_REPARSE_POINT, ACL_NO_MODE);
99838c8a9a5SSteve French 		cifs_get_readable_path(tcon, full_path, &cfile);
9995ddcc9e9SPaulo Alcantara 		free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
100038c8a9a5SSteve French 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1001831ffbd1SPaulo Alcantara 				      &oparms, in_iov, cmds, num_cmds,
10025ddcc9e9SPaulo Alcantara 				      cfile, out_iov, out_buftype, NULL);
10035ddcc9e9SPaulo Alcantara 		if (rc && ea_unsupported(cmds, num_cmds,
10045ddcc9e9SPaulo Alcantara 					 out_iov, out_buftype)) {
10055ddcc9e9SPaulo Alcantara 			if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
10065ddcc9e9SPaulo Alcantara 			    data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
10075ddcc9e9SPaulo Alcantara 				rc = 0;
10085ddcc9e9SPaulo Alcantara 			else
10095ddcc9e9SPaulo Alcantara 				rc = -EOPNOTSUPP;
10105ddcc9e9SPaulo Alcantara 		}
10115f71ebc4SPaulo Alcantara 		break;
10125f71ebc4SPaulo Alcantara 	case -EREMOTE:
10135f71ebc4SPaulo Alcantara 		break;
10145f71ebc4SPaulo Alcantara 	default:
10155f71ebc4SPaulo Alcantara 		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
10165f71ebc4SPaulo Alcantara 			break;
101738c8a9a5SSteve French 		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
101838c8a9a5SSteve French 						     full_path, &islink);
101938c8a9a5SSteve French 		if (rc2) {
102038c8a9a5SSteve French 			rc = rc2;
102138c8a9a5SSteve French 			goto out;
102238c8a9a5SSteve French 		}
102338c8a9a5SSteve French 		if (islink)
102438c8a9a5SSteve French 			rc = -EREMOTE;
102538c8a9a5SSteve French 	}
102638c8a9a5SSteve French 
102738c8a9a5SSteve French out:
10285ddcc9e9SPaulo Alcantara 	free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
102938c8a9a5SSteve French 	return rc;
103038c8a9a5SSteve French }
103138c8a9a5SSteve French 
103238c8a9a5SSteve 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)103338c8a9a5SSteve French smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
103438c8a9a5SSteve French 	   struct cifs_tcon *tcon, const char *name,
103538c8a9a5SSteve French 	   struct cifs_sb_info *cifs_sb)
103638c8a9a5SSteve French {
1037831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1038831ffbd1SPaulo Alcantara 
1039831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1040831ffbd1SPaulo Alcantara 			     FILE_CREATE, CREATE_NOT_FILE, mode);
1041831ffbd1SPaulo Alcantara 	return smb2_compound_op(xid, tcon, cifs_sb,
1042831ffbd1SPaulo Alcantara 				name, &oparms, NULL,
1043831ffbd1SPaulo Alcantara 				&(int){SMB2_OP_MKDIR}, 1,
1044f93d145fSMeetakshi Setiya 				NULL, NULL, NULL, NULL);
104538c8a9a5SSteve French }
104638c8a9a5SSteve French 
104738c8a9a5SSteve 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)104838c8a9a5SSteve French smb2_mkdir_setinfo(struct inode *inode, const char *name,
104938c8a9a5SSteve French 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
105038c8a9a5SSteve French 		   const unsigned int xid)
105138c8a9a5SSteve French {
1052831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1053886b7fb4SSteve French 	FILE_BASIC_INFO data = {};
105438c8a9a5SSteve French 	struct cifsInodeInfo *cifs_i;
105538c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1056886b7fb4SSteve French 	struct kvec in_iov;
105738c8a9a5SSteve French 	u32 dosattrs;
105838c8a9a5SSteve French 	int tmprc;
105938c8a9a5SSteve French 
1060886b7fb4SSteve French 	in_iov.iov_base = &data;
1061886b7fb4SSteve French 	in_iov.iov_len = sizeof(data);
106238c8a9a5SSteve French 	cifs_i = CIFS_I(inode);
106338c8a9a5SSteve French 	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
106438c8a9a5SSteve French 	data.Attributes = cpu_to_le32(dosattrs);
106538c8a9a5SSteve French 	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1066831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1067831ffbd1SPaulo Alcantara 			     FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
106838c8a9a5SSteve French 	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1069831ffbd1SPaulo Alcantara 				 &oparms, &in_iov,
1070886b7fb4SSteve French 				 &(int){SMB2_OP_SET_INFO}, 1,
1071f93d145fSMeetakshi Setiya 				 cfile, NULL, NULL, NULL);
107238c8a9a5SSteve French 	if (tmprc == 0)
107338c8a9a5SSteve French 		cifs_i->cifsAttrs = dosattrs;
107438c8a9a5SSteve French }
107538c8a9a5SSteve French 
107638c8a9a5SSteve French int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)107738c8a9a5SSteve French smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
107838c8a9a5SSteve French 	   struct cifs_sb_info *cifs_sb)
107938c8a9a5SSteve French {
1080831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1081831ffbd1SPaulo Alcantara 
108238c8a9a5SSteve French 	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1083831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1084831ffbd1SPaulo Alcantara 			     FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1085831ffbd1SPaulo Alcantara 	return smb2_compound_op(xid, tcon, cifs_sb,
1086831ffbd1SPaulo Alcantara 				name, &oparms, NULL,
1087a90f37e3SSteve French 				&(int){SMB2_OP_RMDIR}, 1,
1088f93d145fSMeetakshi Setiya 				NULL, NULL, NULL, NULL);
108938c8a9a5SSteve French }
109038c8a9a5SSteve French 
109138c8a9a5SSteve French int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb,struct dentry * dentry)109238c8a9a5SSteve French smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1093f93d145fSMeetakshi Setiya 	    struct cifs_sb_info *cifs_sb, struct dentry *dentry)
109438c8a9a5SSteve French {
1095831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1096831ffbd1SPaulo Alcantara 
1097831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1098831ffbd1SPaulo Alcantara 			     DELETE, FILE_OPEN,
109938c8a9a5SSteve French 			     CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1100831ffbd1SPaulo Alcantara 			     ACL_NO_MODE);
1101831ffbd1SPaulo Alcantara 	int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1102831ffbd1SPaulo Alcantara 				  NULL, &(int){SMB2_OP_DELETE}, 1,
1103f93d145fSMeetakshi Setiya 				  NULL, NULL, NULL, dentry);
11041e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
11051e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1106831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1107831ffbd1SPaulo Alcantara 				      NULL, &(int){SMB2_OP_DELETE}, 1,
11081e60bc0eSMeetakshi Setiya 				      NULL, NULL, NULL, NULL);
11091e60bc0eSMeetakshi Setiya 	}
11101e60bc0eSMeetakshi Setiya 	return rc;
111138c8a9a5SSteve French }
111238c8a9a5SSteve 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)1113c586b0c7SPaulo Alcantara static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
111438c8a9a5SSteve French 			      const char *from_name, const char *to_name,
1115c586b0c7SPaulo Alcantara 			      struct cifs_sb_info *cifs_sb,
1116c586b0c7SPaulo Alcantara 			      __u32 create_options, __u32 access,
1117f93d145fSMeetakshi Setiya 			      int command, struct cifsFileInfo *cfile,
1118f93d145fSMeetakshi Setiya 				  struct dentry *dentry)
111938c8a9a5SSteve French {
1120831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1121886b7fb4SSteve French 	struct kvec in_iov;
112238c8a9a5SSteve French 	__le16 *smb2_to_name = NULL;
112338c8a9a5SSteve French 	int rc;
112438c8a9a5SSteve French 
112538c8a9a5SSteve French 	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
112638c8a9a5SSteve French 	if (smb2_to_name == NULL) {
112738c8a9a5SSteve French 		rc = -ENOMEM;
112838c8a9a5SSteve French 		goto smb2_rename_path;
112938c8a9a5SSteve French 	}
1130886b7fb4SSteve French 	in_iov.iov_base = smb2_to_name;
1131886b7fb4SSteve French 	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1132831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1133831ffbd1SPaulo Alcantara 			     create_options, ACL_NO_MODE);
1134831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1135831ffbd1SPaulo Alcantara 			      &oparms, &in_iov, &command, 1,
1136831ffbd1SPaulo Alcantara 			      cfile, NULL, NULL, dentry);
113738c8a9a5SSteve French smb2_rename_path:
113838c8a9a5SSteve French 	kfree(smb2_to_name);
113938c8a9a5SSteve French 	return rc;
114038c8a9a5SSteve French }
114138c8a9a5SSteve 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)1142c586b0c7SPaulo Alcantara int smb2_rename_path(const unsigned int xid,
1143c586b0c7SPaulo Alcantara 		     struct cifs_tcon *tcon,
1144c586b0c7SPaulo Alcantara 		     struct dentry *source_dentry,
114538c8a9a5SSteve French 		     const char *from_name, const char *to_name,
114638c8a9a5SSteve French 		     struct cifs_sb_info *cifs_sb)
114738c8a9a5SSteve French {
114838c8a9a5SSteve French 	struct cifsFileInfo *cfile;
11498c944f8aSPaulo Alcantara 	__u32 co = file_create_options(source_dentry);
115038c8a9a5SSteve French 
115138c8a9a5SSteve French 	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
115238c8a9a5SSteve French 	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
115338c8a9a5SSteve French 
11541e60bc0eSMeetakshi Setiya 	int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1155f93d145fSMeetakshi Setiya 				  co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
11561e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
11571e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1158b27ea9c9SPaulo Alcantara 		cifs_get_writable_path(tcon, from_name,
1159b27ea9c9SPaulo Alcantara 				       FIND_WR_WITH_DELETE, &cfile);
11601e60bc0eSMeetakshi Setiya 		rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
11611e60bc0eSMeetakshi Setiya 				  co, DELETE, SMB2_OP_RENAME, cfile, NULL);
11621e60bc0eSMeetakshi Setiya 	}
11631e60bc0eSMeetakshi Setiya 	return rc;
116438c8a9a5SSteve French }
116538c8a9a5SSteve 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)11668c944f8aSPaulo Alcantara int smb2_create_hardlink(const unsigned int xid,
11678c944f8aSPaulo Alcantara 			 struct cifs_tcon *tcon,
11688c944f8aSPaulo Alcantara 			 struct dentry *source_dentry,
116938c8a9a5SSteve French 			 const char *from_name, const char *to_name,
117038c8a9a5SSteve French 			 struct cifs_sb_info *cifs_sb)
117138c8a9a5SSteve French {
11728c944f8aSPaulo Alcantara 	__u32 co = file_create_options(source_dentry);
11738c944f8aSPaulo Alcantara 
1174c586b0c7SPaulo Alcantara 	return smb2_set_path_attr(xid, tcon, from_name, to_name,
11758c944f8aSPaulo Alcantara 				  cifs_sb, co, FILE_READ_ATTRIBUTES,
1176f93d145fSMeetakshi Setiya 				  SMB2_OP_HARDLINK, NULL, NULL);
117738c8a9a5SSteve French }
117838c8a9a5SSteve French 
117938c8a9a5SSteve 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)118038c8a9a5SSteve French smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
118138c8a9a5SSteve French 		   const char *full_path, __u64 size,
1182f93d145fSMeetakshi Setiya 		   struct cifs_sb_info *cifs_sb, bool set_alloc,
1183f93d145fSMeetakshi Setiya 		   struct dentry *dentry)
118438c8a9a5SSteve French {
1185831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
118638c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1187886b7fb4SSteve French 	struct kvec in_iov;
1188886b7fb4SSteve French 	__le64 eof = cpu_to_le64(size);
1189831ffbd1SPaulo Alcantara 	int rc;
119038c8a9a5SSteve French 
1191886b7fb4SSteve French 	in_iov.iov_base = &eof;
1192886b7fb4SSteve French 	in_iov.iov_len = sizeof(eof);
119338c8a9a5SSteve French 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1194831ffbd1SPaulo Alcantara 
1195831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1196831ffbd1SPaulo Alcantara 			     FILE_OPEN, 0, ACL_NO_MODE);
1197831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1198831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1199886b7fb4SSteve French 			      &(int){SMB2_OP_SET_EOF}, 1,
1200f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, dentry);
12011e60bc0eSMeetakshi Setiya 	if (rc == -EINVAL) {
12021e60bc0eSMeetakshi Setiya 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
12035a72d1edSPaulo Alcantara 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1204831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb,
1205831ffbd1SPaulo Alcantara 				      full_path, &oparms, &in_iov,
12061e60bc0eSMeetakshi Setiya 				      &(int){SMB2_OP_SET_EOF}, 1,
12071e60bc0eSMeetakshi Setiya 				      cfile, NULL, NULL, NULL);
12081e60bc0eSMeetakshi Setiya 	}
12091e60bc0eSMeetakshi Setiya 	return rc;
121038c8a9a5SSteve French }
121138c8a9a5SSteve French 
121238c8a9a5SSteve French int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)121338c8a9a5SSteve French smb2_set_file_info(struct inode *inode, const char *full_path,
121438c8a9a5SSteve French 		   FILE_BASIC_INFO *buf, const unsigned int xid)
121538c8a9a5SSteve French {
1216831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
121738c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
121838c8a9a5SSteve French 	struct tcon_link *tlink;
121938c8a9a5SSteve French 	struct cifs_tcon *tcon;
122038c8a9a5SSteve French 	struct cifsFileInfo *cfile;
1221886b7fb4SSteve French 	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
122238c8a9a5SSteve French 	int rc;
122338c8a9a5SSteve French 
122438c8a9a5SSteve French 	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
122538c8a9a5SSteve French 	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
122638c8a9a5SSteve French 	    (buf->Attributes == 0))
122738c8a9a5SSteve French 		return 0; /* would be a no op, no sense sending this */
122838c8a9a5SSteve French 
122938c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
123038c8a9a5SSteve French 	if (IS_ERR(tlink))
123138c8a9a5SSteve French 		return PTR_ERR(tlink);
123238c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
123338c8a9a5SSteve French 
123438c8a9a5SSteve French 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1235831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1236831ffbd1SPaulo Alcantara 			     FILE_OPEN, 0, ACL_NO_MODE);
1237831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1238831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1239a90f37e3SSteve French 			      &(int){SMB2_OP_SET_INFO}, 1,
1240f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, NULL);
124138c8a9a5SSteve French 	cifs_put_tlink(tlink);
124238c8a9a5SSteve French 	return rc;
124338c8a9a5SSteve French }
124402bcf865SSteve 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,bool directory,struct kvec * reparse_iov,struct kvec * xattr_iov)124502bcf865SSteve French struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
124602bcf865SSteve French 				     struct super_block *sb,
124702bcf865SSteve French 				     const unsigned int xid,
124802bcf865SSteve French 				     struct cifs_tcon *tcon,
124902bcf865SSteve French 				     const char *full_path,
1250201430d2SPali Rohár 				     bool directory,
1251df0a8a19SPaulo Alcantara 				     struct kvec *reparse_iov,
1252df0a8a19SPaulo Alcantara 				     struct kvec *xattr_iov)
125302bcf865SSteve French {
1254831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
125502bcf865SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
125602bcf865SSteve French 	struct cifsFileInfo *cfile;
125702bcf865SSteve French 	struct inode *new = NULL;
1258e4c886ddSPali Rohár 	int out_buftype[4] = {};
1259e4c886ddSPali Rohár 	struct kvec out_iov[4] = {};
126002bcf865SSteve French 	struct kvec in_iov[2];
126102bcf865SSteve French 	int cmds[2];
126202bcf865SSteve French 	int rc;
1263e4c886ddSPali Rohár 	int i;
126402bcf865SSteve French 
1265831ffbd1SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1266831ffbd1SPaulo Alcantara 			     SYNCHRONIZE | DELETE |
126702bcf865SSteve French 			     FILE_READ_ATTRIBUTES |
1268831ffbd1SPaulo Alcantara 			     FILE_WRITE_ATTRIBUTES,
1269831ffbd1SPaulo Alcantara 			     FILE_CREATE,
1270201430d2SPali Rohár 			     (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
1271831ffbd1SPaulo Alcantara 			     ACL_NO_MODE);
1272df0a8a19SPaulo Alcantara 	if (xattr_iov)
1273df0a8a19SPaulo Alcantara 		oparms.ea_cctx = xattr_iov;
1274df0a8a19SPaulo Alcantara 
127502bcf865SSteve French 	cmds[0] = SMB2_OP_SET_REPARSE;
1276df0a8a19SPaulo Alcantara 	in_iov[0] = *reparse_iov;
127702bcf865SSteve French 	in_iov[1].iov_base = data;
127802bcf865SSteve French 	in_iov[1].iov_len = sizeof(*data);
127902bcf865SSteve French 
128002bcf865SSteve French 	if (tcon->posix_extensions) {
128102bcf865SSteve French 		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
128202bcf865SSteve French 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1283831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1284e4c886ddSPali Rohár 				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
128502bcf865SSteve French 		if (!rc) {
128602bcf865SSteve French 			rc = smb311_posix_get_inode_info(&new, full_path,
128702bcf865SSteve French 							 data, sb, xid);
128802bcf865SSteve French 		}
128902bcf865SSteve French 	} else {
129002bcf865SSteve French 		cmds[1] = SMB2_OP_QUERY_INFO;
129102bcf865SSteve French 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1292831ffbd1SPaulo Alcantara 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1293e4c886ddSPali Rohár 				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
129402bcf865SSteve French 		if (!rc) {
129502bcf865SSteve French 			rc = cifs_get_inode_info(&new, full_path,
129602bcf865SSteve French 						 data, sb, xid, NULL);
129702bcf865SSteve French 		}
129802bcf865SSteve French 	}
1299e4c886ddSPali Rohár 
1300e4c886ddSPali Rohár 
1301e4c886ddSPali Rohár 	/*
1302e4c886ddSPali Rohár 	 * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1303e4c886ddSPali Rohár 	 * remove the intermediate object created by CREATE. Otherwise
1304e4c886ddSPali Rohár 	 * empty object stay on the server when reparse call failed.
1305e4c886ddSPali Rohár 	 */
1306e4c886ddSPali Rohár 	if (rc &&
1307e4c886ddSPali Rohár 	    out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1308e4c886ddSPali Rohár 	    ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1309e4c886ddSPali Rohár 	    (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1310e4c886ddSPali Rohár 	     ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1311e4c886ddSPali Rohár 		smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1312e4c886ddSPali Rohár 
1313e4c886ddSPali Rohár 	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1314e4c886ddSPali Rohár 		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1315e4c886ddSPali Rohár 
131602bcf865SSteve French 	return rc ? ERR_PTR(rc) : new;
131702bcf865SSteve French }
1318870c73abSPaulo 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)1319870c73abSPaulo Alcantara int smb2_query_reparse_point(const unsigned int xid,
1320870c73abSPaulo Alcantara 			     struct cifs_tcon *tcon,
1321870c73abSPaulo Alcantara 			     struct cifs_sb_info *cifs_sb,
1322870c73abSPaulo Alcantara 			     const char *full_path,
1323870c73abSPaulo Alcantara 			     u32 *tag, struct kvec *rsp,
1324870c73abSPaulo Alcantara 			     int *rsp_buftype)
1325870c73abSPaulo Alcantara {
1326831ffbd1SPaulo Alcantara 	struct cifs_open_parms oparms;
1327870c73abSPaulo Alcantara 	struct cifs_open_info_data data = {};
1328870c73abSPaulo Alcantara 	struct cifsFileInfo *cfile;
1329870c73abSPaulo Alcantara 	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1330870c73abSPaulo Alcantara 	int rc;
1331870c73abSPaulo Alcantara 
1332870c73abSPaulo Alcantara 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1333870c73abSPaulo Alcantara 
1334870c73abSPaulo Alcantara 	cifs_get_readable_path(tcon, full_path, &cfile);
133577e5d743SPaulo Alcantara 	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
133677e5d743SPaulo Alcantara 			     FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1337831ffbd1SPaulo Alcantara 			     FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1338831ffbd1SPaulo Alcantara 	rc = smb2_compound_op(xid, tcon, cifs_sb,
1339831ffbd1SPaulo Alcantara 			      full_path, &oparms, &in_iov,
1340a90f37e3SSteve French 			      &(int){SMB2_OP_GET_REPARSE}, 1,
1341f93d145fSMeetakshi Setiya 			      cfile, NULL, NULL, NULL);
1342870c73abSPaulo Alcantara 	if (rc)
1343870c73abSPaulo Alcantara 		goto out;
1344870c73abSPaulo Alcantara 
1345870c73abSPaulo Alcantara 	*tag = data.reparse.tag;
1346870c73abSPaulo Alcantara 	*rsp = data.reparse.io.iov;
1347870c73abSPaulo Alcantara 	*rsp_buftype = data.reparse.io.buftype;
1348870c73abSPaulo Alcantara 	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1349870c73abSPaulo Alcantara 	data.reparse.io.buftype = CIFS_NO_BUFFER;
1350870c73abSPaulo Alcantara out:
1351870c73abSPaulo Alcantara 	cifs_free_open_info(&data);
1352870c73abSPaulo Alcantara 	return rc;
1353870c73abSPaulo Alcantara }
1354