brintos

brintos / linux-shallow public Read only

0
0
Text · 37.0 KiB · e49d0c2 Raw
1305 lines · c
1// SPDX-License-Identifier: LGPL-2.12/*3 *4 *   Copyright (C) International Business Machines  Corp., 2002, 20115 *                 Etersoft, 20126 *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),7 *              Steve French (sfrench@us.ibm.com)8 *9 */10#include <linux/fs.h>11#include <linux/stat.h>12#include <linux/slab.h>13#include <linux/pagemap.h>14#include <asm/div64.h>15#include "cifsfs.h"16#include "cifspdu.h"17#include "cifsglob.h"18#include "cifsproto.h"19#include "cifs_debug.h"20#include "cifs_fs_sb.h"21#include "cifs_unicode.h"22#include "fscache.h"23#include "smb2glob.h"24#include "smb2pdu.h"25#include "smb2proto.h"26#include "cached_dir.h"27#include "../common/smb2status.h"28 29static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)30{31	struct reparse_data_buffer *buf;32	struct smb2_ioctl_rsp *io = iov->iov_base;33	u32 off, count, len;34 35	count = le32_to_cpu(io->OutputCount);36	off = le32_to_cpu(io->OutputOffset);37	if (check_add_overflow(off, count, &len) || len > iov->iov_len)38		return ERR_PTR(-EIO);39 40	buf = (struct reparse_data_buffer *)((u8 *)io + off);41	len = sizeof(*buf);42	if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)43		return ERR_PTR(-EIO);44	return buf;45}46 47static inline __u32 file_create_options(struct dentry *dentry)48{49	struct cifsInodeInfo *ci;50 51	if (dentry) {52		ci = CIFS_I(d_inode(dentry));53		if (ci->cifsAttrs & ATTR_REPARSE)54			return OPEN_REPARSE_POINT;55	}56	return 0;57}58 59/* Parse owner and group from SMB3.1.1 POSIX query info */60static int parse_posix_sids(struct cifs_open_info_data *data,61			    struct kvec *rsp_iov)62{63	struct smb2_query_info_rsp *qi = rsp_iov->iov_base;64	unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);65	unsigned int qi_len = sizeof(data->posix_fi);66	int owner_len, group_len;67	u8 *sidsbuf, *sidsbuf_end;68 69	if (out_len <= qi_len)70		return -EINVAL;71 72	sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;73	sidsbuf_end = sidsbuf + out_len - qi_len;74 75	owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);76	if (owner_len == -1)77		return -EINVAL;78 79	memcpy(&data->posix_owner, sidsbuf, owner_len);80	group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);81	if (group_len == -1)82		return -EINVAL;83 84	memcpy(&data->posix_group, sidsbuf + owner_len, group_len);85	return 0;86}87 88struct wsl_query_ea {89	__le32	next;90	__u8	name_len;91	__u8	name[SMB2_WSL_XATTR_NAME_LEN + 1];92} __packed;93 94#define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))95 96static const struct wsl_query_ea wsl_query_eas[] = {97	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },98	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },99	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },100	{ .next = 0,        .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },101};102 103static int check_wsl_eas(struct kvec *rsp_iov)104{105	struct smb2_file_full_ea_info *ea;106	struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;107	unsigned long addr;108	u32 outlen, next;109	u16 vlen;110	u8 nlen;111	u8 *end;112 113	outlen = le32_to_cpu(rsp->OutputBufferLength);114	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||115	    outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)116		return -EINVAL;117 118	ea = (void *)((u8 *)rsp_iov->iov_base +119		      le16_to_cpu(rsp->OutputBufferOffset));120	end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;121	for (;;) {122		if ((u8 *)ea > end - sizeof(*ea))123			return -EINVAL;124 125		nlen = ea->ea_name_length;126		vlen = le16_to_cpu(ea->ea_value_length);127		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||128		    (u8 *)ea + nlen + 1 + vlen > end)129			return -EINVAL;130 131		switch (vlen) {132		case 4:133			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&134			    strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&135			    strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))136				return -EINVAL;137			break;138		case 8:139			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))140				return -EINVAL;141			break;142		case 0:143			if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||144			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||145			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||146			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))147				break;148			fallthrough;149		default:150			return -EINVAL;151		}152 153		next = le32_to_cpu(ea->next_entry_offset);154		if (!next)155			break;156		if (!IS_ALIGNED(next, 4) ||157		    check_add_overflow((unsigned long)ea, next, &addr))158			return -EINVAL;159		ea = (void *)addr;160	}161	return 0;162}163 164/*165 * note: If cfile is passed, the reference to it is dropped here.166 * So make sure that you do not reuse cfile after return from this func.167 *168 * If passing @out_iov and @out_buftype, ensure to make them both large enough169 * (>= 3) to hold all compounded responses.  Caller is also responsible for170 * freeing them up with free_rsp_buf().171 */172static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,173			    struct cifs_sb_info *cifs_sb, const char *full_path,174			    struct cifs_open_parms *oparms, struct kvec *in_iov,175			    int *cmds, int num_cmds, struct cifsFileInfo *cfile,176			    struct kvec *out_iov, int *out_buftype, struct dentry *dentry)177{178 179	struct reparse_data_buffer *rbuf;180	struct smb2_compound_vars *vars = NULL;181	struct kvec *rsp_iov, *iov;182	struct smb_rqst *rqst;183	int rc;184	__le16 *utf16_path = NULL;185	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;186	struct cifs_fid fid;187	struct cifs_ses *ses = tcon->ses;188	struct TCP_Server_Info *server;189	int num_rqst = 0, i;190	int resp_buftype[MAX_COMPOUND];191	struct smb2_query_info_rsp *qi_rsp = NULL;192	struct cifs_open_info_data *idata;193	struct inode *inode = NULL;194	int flags = 0;195	__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};196	unsigned int size[2];197	void *data[2];198	unsigned int len;199	int retries = 0, cur_sleep = 1;200 201replay_again:202	/* reinitialize for possible replay */203	flags = 0;204	oplock = SMB2_OPLOCK_LEVEL_NONE;205	num_rqst = 0;206	server = cifs_pick_channel(ses);207 208	vars = kzalloc(sizeof(*vars), GFP_ATOMIC);209	if (vars == NULL)210		return -ENOMEM;211	rqst = &vars->rqst[0];212	rsp_iov = &vars->rsp_iov[0];213 214	if (smb3_encryption_required(tcon))215		flags |= CIFS_TRANSFORM_REQ;216 217	for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)218		resp_buftype[i] = CIFS_NO_BUFFER;219 220	/* We already have a handle so we can skip the open */221	if (cfile)222		goto after_open;223 224	/* Open */225	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);226	if (!utf16_path) {227		rc = -ENOMEM;228		goto finished;229	}230 231	/* if there is an existing lease, reuse it */232 233	/*234	 * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,235	 * lease keys are associated with the filepath. We are maintaining lease keys236	 * with the inode on the client. If the file has hardlinks, it is possible237	 * that the lease for a file be reused for an operation on its hardlink or238	 * vice versa.239	 * As a workaround, send request using an existing lease key and if the server240	 * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request241	 * again without the lease.242	 */243	if (dentry) {244		inode = d_inode(dentry);245		if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {246			oplock = SMB2_OPLOCK_LEVEL_LEASE;247			server->ops->get_lease_key(inode, &fid);248		}249	}250 251	vars->oparms = *oparms;252	vars->oparms.fid = &fid;253 254	rqst[num_rqst].rq_iov = &vars->open_iov[0];255	rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;256	rc = SMB2_open_init(tcon, server,257			    &rqst[num_rqst], &oplock, &vars->oparms,258			    utf16_path);259	kfree(utf16_path);260	if (rc)261		goto finished;262 263	smb2_set_next_command(tcon, &rqst[num_rqst]);264 after_open:265	num_rqst++;266	rc = 0;267 268	for (i = 0; i < num_cmds; i++) {269		/* Operation */270		switch (cmds[i]) {271		case SMB2_OP_QUERY_INFO:272			rqst[num_rqst].rq_iov = &vars->qi_iov;273			rqst[num_rqst].rq_nvec = 1;274 275			if (cfile) {276				rc = SMB2_query_info_init(tcon, server,277							  &rqst[num_rqst],278							  cfile->fid.persistent_fid,279							  cfile->fid.volatile_fid,280							  FILE_ALL_INFORMATION,281							  SMB2_O_INFO_FILE, 0,282							  sizeof(struct smb2_file_all_info) +283							  PATH_MAX * 2, 0, NULL);284			} else {285				rc = SMB2_query_info_init(tcon, server,286							  &rqst[num_rqst],287							  COMPOUND_FID,288							  COMPOUND_FID,289							  FILE_ALL_INFORMATION,290							  SMB2_O_INFO_FILE, 0,291							  sizeof(struct smb2_file_all_info) +292							  PATH_MAX * 2, 0, NULL);293			}294			if (!rc && (!cfile || num_rqst > 1)) {295				smb2_set_next_command(tcon, &rqst[num_rqst]);296				smb2_set_related(&rqst[num_rqst]);297			} else if (rc) {298				goto finished;299			}300			num_rqst++;301			trace_smb3_query_info_compound_enter(xid, ses->Suid,302							     tcon->tid, full_path);303			break;304		case SMB2_OP_POSIX_QUERY_INFO:305			rqst[num_rqst].rq_iov = &vars->qi_iov;306			rqst[num_rqst].rq_nvec = 1;307 308			if (cfile) {309				/* TBD: fix following to allow for longer SIDs */310				rc = SMB2_query_info_init(tcon, server,311							  &rqst[num_rqst],312							  cfile->fid.persistent_fid,313							  cfile->fid.volatile_fid,314							  SMB_FIND_FILE_POSIX_INFO,315							  SMB2_O_INFO_FILE, 0,316							  sizeof(struct smb311_posix_qinfo *) +317							  (PATH_MAX * 2) +318							  (sizeof(struct smb_sid) * 2), 0, NULL);319			} else {320				rc = SMB2_query_info_init(tcon, server,321							  &rqst[num_rqst],322							  COMPOUND_FID,323							  COMPOUND_FID,324							  SMB_FIND_FILE_POSIX_INFO,325							  SMB2_O_INFO_FILE, 0,326							  sizeof(struct smb311_posix_qinfo *) +327							  (PATH_MAX * 2) +328							  (sizeof(struct smb_sid) * 2), 0, NULL);329			}330			if (!rc && (!cfile || num_rqst > 1)) {331				smb2_set_next_command(tcon, &rqst[num_rqst]);332				smb2_set_related(&rqst[num_rqst]);333			} else if (rc) {334				goto finished;335			}336			num_rqst++;337			trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,338								   tcon->tid, full_path);339			break;340		case SMB2_OP_DELETE:341			trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);342			break;343		case SMB2_OP_MKDIR:344			/*345			 * Directories are created through parameters in the346			 * SMB2_open() call.347			 */348			trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);349			break;350		case SMB2_OP_RMDIR:351			rqst[num_rqst].rq_iov = &vars->si_iov[0];352			rqst[num_rqst].rq_nvec = 1;353 354			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */355			data[0] = &delete_pending[0];356 357			rc = SMB2_set_info_init(tcon, server,358						&rqst[num_rqst], COMPOUND_FID,359						COMPOUND_FID, current->tgid,360						FILE_DISPOSITION_INFORMATION,361						SMB2_O_INFO_FILE, 0, data, size);362			if (rc)363				goto finished;364			smb2_set_next_command(tcon, &rqst[num_rqst]);365			smb2_set_related(&rqst[num_rqst++]);366			trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);367			break;368		case SMB2_OP_SET_EOF:369			rqst[num_rqst].rq_iov = &vars->si_iov[0];370			rqst[num_rqst].rq_nvec = 1;371 372			size[0] = in_iov[i].iov_len;373			data[0] = in_iov[i].iov_base;374 375			if (cfile) {376				rc = SMB2_set_info_init(tcon, server,377							&rqst[num_rqst],378							cfile->fid.persistent_fid,379							cfile->fid.volatile_fid,380							current->tgid,381							FILE_END_OF_FILE_INFORMATION,382							SMB2_O_INFO_FILE, 0,383							data, size);384			} else {385				rc = SMB2_set_info_init(tcon, server,386							&rqst[num_rqst],387							COMPOUND_FID,388							COMPOUND_FID,389							current->tgid,390							FILE_END_OF_FILE_INFORMATION,391							SMB2_O_INFO_FILE, 0,392							data, size);393			}394			if (!rc && (!cfile || num_rqst > 1)) {395				smb2_set_next_command(tcon, &rqst[num_rqst]);396				smb2_set_related(&rqst[num_rqst]);397			} else if (rc) {398				goto finished;399			}400			num_rqst++;401			trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);402			break;403		case SMB2_OP_SET_INFO:404			rqst[num_rqst].rq_iov = &vars->si_iov[0];405			rqst[num_rqst].rq_nvec = 1;406 407			size[0] = in_iov[i].iov_len;408			data[0] = in_iov[i].iov_base;409 410			if (cfile) {411				rc = SMB2_set_info_init(tcon, server,412							&rqst[num_rqst],413							cfile->fid.persistent_fid,414							cfile->fid.volatile_fid, current->tgid,415							FILE_BASIC_INFORMATION,416							SMB2_O_INFO_FILE, 0, data, size);417			} else {418				rc = SMB2_set_info_init(tcon, server,419							&rqst[num_rqst],420							COMPOUND_FID,421							COMPOUND_FID, current->tgid,422							FILE_BASIC_INFORMATION,423							SMB2_O_INFO_FILE, 0, data, size);424			}425			if (!rc && (!cfile || num_rqst > 1)) {426				smb2_set_next_command(tcon, &rqst[num_rqst]);427				smb2_set_related(&rqst[num_rqst]);428			} else if (rc) {429				goto finished;430			}431			num_rqst++;432			trace_smb3_set_info_compound_enter(xid, ses->Suid,433							   tcon->tid, full_path);434			break;435		case SMB2_OP_RENAME:436			rqst[num_rqst].rq_iov = &vars->si_iov[0];437			rqst[num_rqst].rq_nvec = 2;438 439			len = in_iov[i].iov_len;440 441			vars->rename_info.ReplaceIfExists = 1;442			vars->rename_info.RootDirectory = 0;443			vars->rename_info.FileNameLength = cpu_to_le32(len);444 445			size[0] = sizeof(struct smb2_file_rename_info);446			data[0] = &vars->rename_info;447 448			size[1] = len + 2 /* null */;449			data[1] = in_iov[i].iov_base;450 451			if (cfile) {452				rc = SMB2_set_info_init(tcon, server,453							&rqst[num_rqst],454							cfile->fid.persistent_fid,455							cfile->fid.volatile_fid,456							current->tgid, FILE_RENAME_INFORMATION,457							SMB2_O_INFO_FILE, 0, data, size);458			} else {459				rc = SMB2_set_info_init(tcon, server,460							&rqst[num_rqst],461							COMPOUND_FID, COMPOUND_FID,462							current->tgid, FILE_RENAME_INFORMATION,463							SMB2_O_INFO_FILE, 0, data, size);464			}465			if (!rc && (!cfile || num_rqst > 1)) {466				smb2_set_next_command(tcon, &rqst[num_rqst]);467				smb2_set_related(&rqst[num_rqst]);468			} else if (rc) {469				goto finished;470			}471			num_rqst++;472			trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);473			break;474		case SMB2_OP_HARDLINK:475			rqst[num_rqst].rq_iov = &vars->si_iov[0];476			rqst[num_rqst].rq_nvec = 2;477 478			len = in_iov[i].iov_len;479 480			vars->link_info.ReplaceIfExists = 0;481			vars->link_info.RootDirectory = 0;482			vars->link_info.FileNameLength = cpu_to_le32(len);483 484			size[0] = sizeof(struct smb2_file_link_info);485			data[0] = &vars->link_info;486 487			size[1] = len + 2 /* null */;488			data[1] = in_iov[i].iov_base;489 490			rc = SMB2_set_info_init(tcon, server,491						&rqst[num_rqst], COMPOUND_FID,492						COMPOUND_FID, current->tgid,493						FILE_LINK_INFORMATION,494						SMB2_O_INFO_FILE, 0, data, size);495			if (rc)496				goto finished;497			smb2_set_next_command(tcon, &rqst[num_rqst]);498			smb2_set_related(&rqst[num_rqst++]);499			trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);500			break;501		case SMB2_OP_SET_REPARSE:502			rqst[num_rqst].rq_iov = vars->io_iov;503			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);504 505			if (cfile) {506				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],507						     cfile->fid.persistent_fid,508						     cfile->fid.volatile_fid,509						     FSCTL_SET_REPARSE_POINT,510						     in_iov[i].iov_base,511						     in_iov[i].iov_len, 0);512			} else {513				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],514						     COMPOUND_FID, COMPOUND_FID,515						     FSCTL_SET_REPARSE_POINT,516						     in_iov[i].iov_base,517						     in_iov[i].iov_len, 0);518			}519			if (!rc && (!cfile || num_rqst > 1)) {520				smb2_set_next_command(tcon, &rqst[num_rqst]);521				smb2_set_related(&rqst[num_rqst]);522			} else if (rc) {523				goto finished;524			}525			num_rqst++;526			trace_smb3_set_reparse_compound_enter(xid, ses->Suid,527							      tcon->tid, full_path);528			break;529		case SMB2_OP_GET_REPARSE:530			rqst[num_rqst].rq_iov = vars->io_iov;531			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);532 533			if (cfile) {534				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],535						     cfile->fid.persistent_fid,536						     cfile->fid.volatile_fid,537						     FSCTL_GET_REPARSE_POINT,538						     NULL, 0, CIFSMaxBufSize);539			} else {540				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],541						     COMPOUND_FID, COMPOUND_FID,542						     FSCTL_GET_REPARSE_POINT,543						     NULL, 0, CIFSMaxBufSize);544			}545			if (!rc && (!cfile || num_rqst > 1)) {546				smb2_set_next_command(tcon, &rqst[num_rqst]);547				smb2_set_related(&rqst[num_rqst]);548			} else if (rc) {549				goto finished;550			}551			num_rqst++;552			trace_smb3_get_reparse_compound_enter(xid, ses->Suid,553							      tcon->tid, full_path);554			break;555		case SMB2_OP_QUERY_WSL_EA:556			rqst[num_rqst].rq_iov = &vars->ea_iov;557			rqst[num_rqst].rq_nvec = 1;558 559			if (cfile) {560				rc = SMB2_query_info_init(tcon, server,561							  &rqst[num_rqst],562							  cfile->fid.persistent_fid,563							  cfile->fid.volatile_fid,564							  FILE_FULL_EA_INFORMATION,565							  SMB2_O_INFO_FILE, 0,566							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,567							  sizeof(wsl_query_eas),568							  (void *)wsl_query_eas);569			} else {570				rc = SMB2_query_info_init(tcon, server,571							  &rqst[num_rqst],572							  COMPOUND_FID,573							  COMPOUND_FID,574							  FILE_FULL_EA_INFORMATION,575							  SMB2_O_INFO_FILE, 0,576							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,577							  sizeof(wsl_query_eas),578							  (void *)wsl_query_eas);579			}580			if (!rc && (!cfile || num_rqst > 1)) {581				smb2_set_next_command(tcon, &rqst[num_rqst]);582				smb2_set_related(&rqst[num_rqst]);583			} else if (rc) {584				goto finished;585			}586			num_rqst++;587			break;588		default:589			cifs_dbg(VFS, "Invalid command\n");590			rc = -EINVAL;591		}592	}593	if (rc)594		goto finished;595 596	/* We already have a handle so we can skip the close */597	if (cfile)598		goto after_close;599	/* Close */600	flags |= CIFS_CP_CREATE_CLOSE_OP;601	rqst[num_rqst].rq_iov = &vars->close_iov;602	rqst[num_rqst].rq_nvec = 1;603	rc = SMB2_close_init(tcon, server,604			     &rqst[num_rqst], COMPOUND_FID,605			     COMPOUND_FID, false);606	smb2_set_related(&rqst[num_rqst]);607	if (rc)608		goto finished;609 after_close:610	num_rqst++;611 612	if (cfile) {613		if (retries)614			for (i = 1; i < num_rqst - 2; i++)615				smb2_set_replay(server, &rqst[i]);616 617		rc = compound_send_recv(xid, ses, server,618					flags, num_rqst - 2,619					&rqst[1], &resp_buftype[1],620					&rsp_iov[1]);621	} else {622		if (retries)623			for (i = 0; i < num_rqst; i++)624				smb2_set_replay(server, &rqst[i]);625 626		rc = compound_send_recv(xid, ses, server,627					flags, num_rqst,628					rqst, resp_buftype,629					rsp_iov);630	}631 632finished:633	num_rqst = 0;634	SMB2_open_free(&rqst[num_rqst++]);635	if (rc == -EREMCHG) {636		pr_warn_once("server share %s deleted\n", tcon->tree_name);637		tcon->need_reconnect = true;638	}639 640	for (i = 0; i < num_cmds; i++) {641		switch (cmds[i]) {642		case SMB2_OP_QUERY_INFO:643			idata = in_iov[i].iov_base;644			if (rc == 0 && cfile && cfile->symlink_target) {645				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);646				if (!idata->symlink_target)647					rc = -ENOMEM;648			}649			if (rc == 0) {650				qi_rsp = (struct smb2_query_info_rsp *)651					rsp_iov[i + 1].iov_base;652				rc = smb2_validate_and_copy_iov(653					le16_to_cpu(qi_rsp->OutputBufferOffset),654					le32_to_cpu(qi_rsp->OutputBufferLength),655					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);656			}657			SMB2_query_info_free(&rqst[num_rqst++]);658			if (rc)659				trace_smb3_query_info_compound_err(xid,  ses->Suid,660								   tcon->tid, rc);661			else662				trace_smb3_query_info_compound_done(xid, ses->Suid,663								    tcon->tid);664			break;665		case SMB2_OP_POSIX_QUERY_INFO:666			idata = in_iov[i].iov_base;667			if (rc == 0 && cfile && cfile->symlink_target) {668				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);669				if (!idata->symlink_target)670					rc = -ENOMEM;671			}672			if (rc == 0) {673				qi_rsp = (struct smb2_query_info_rsp *)674					rsp_iov[i + 1].iov_base;675				rc = smb2_validate_and_copy_iov(676					le16_to_cpu(qi_rsp->OutputBufferOffset),677					le32_to_cpu(qi_rsp->OutputBufferLength),678					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,679					(char *)&idata->posix_fi);680			}681			if (rc == 0)682				rc = parse_posix_sids(idata, &rsp_iov[i + 1]);683 684			SMB2_query_info_free(&rqst[num_rqst++]);685			if (rc)686				trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,687									 tcon->tid, rc);688			else689				trace_smb3_posix_query_info_compound_done(xid, ses->Suid,690									  tcon->tid);691			break;692		case SMB2_OP_DELETE:693			if (rc)694				trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);695			else {696				/*697				 * If dentry (hence, inode) is NULL, lease break is going to698				 * take care of degrading leases on handles for deleted files.699				 */700				if (inode)701					cifs_mark_open_handles_for_deleted_file(inode, full_path);702				trace_smb3_delete_done(xid, ses->Suid, tcon->tid);703			}704			break;705		case SMB2_OP_MKDIR:706			if (rc)707				trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);708			else709				trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);710			break;711		case SMB2_OP_HARDLINK:712			if (rc)713				trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);714			else715				trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);716			SMB2_set_info_free(&rqst[num_rqst++]);717			break;718		case SMB2_OP_RENAME:719			if (rc)720				trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);721			else722				trace_smb3_rename_done(xid, ses->Suid, tcon->tid);723			SMB2_set_info_free(&rqst[num_rqst++]);724			break;725		case SMB2_OP_RMDIR:726			if (rc)727				trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);728			else729				trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);730			SMB2_set_info_free(&rqst[num_rqst++]);731			break;732		case SMB2_OP_SET_EOF:733			if (rc)734				trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);735			else736				trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);737			SMB2_set_info_free(&rqst[num_rqst++]);738			break;739		case SMB2_OP_SET_INFO:740			if (rc)741				trace_smb3_set_info_compound_err(xid,  ses->Suid,742								 tcon->tid, rc);743			else744				trace_smb3_set_info_compound_done(xid, ses->Suid,745								  tcon->tid);746			SMB2_set_info_free(&rqst[num_rqst++]);747			break;748		case SMB2_OP_SET_REPARSE:749			if (rc) {750				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,751								    tcon->tid, rc);752			} else {753				trace_smb3_set_reparse_compound_done(xid, ses->Suid,754								     tcon->tid);755			}756			SMB2_ioctl_free(&rqst[num_rqst++]);757			break;758		case SMB2_OP_GET_REPARSE:759			if (!rc) {760				iov = &rsp_iov[i + 1];761				idata = in_iov[i].iov_base;762				idata->reparse.io.iov = *iov;763				idata->reparse.io.buftype = resp_buftype[i + 1];764				rbuf = reparse_buf_ptr(iov);765				if (IS_ERR(rbuf)) {766					rc = PTR_ERR(rbuf);767					trace_smb3_set_reparse_compound_err(xid,  ses->Suid,768									    tcon->tid, rc);769				} else {770					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);771					trace_smb3_set_reparse_compound_done(xid, ses->Suid,772									     tcon->tid);773				}774				memset(iov, 0, sizeof(*iov));775				resp_buftype[i + 1] = CIFS_NO_BUFFER;776			} else {777				trace_smb3_set_reparse_compound_err(xid, ses->Suid,778								    tcon->tid, rc);779			}780			SMB2_ioctl_free(&rqst[num_rqst++]);781			break;782		case SMB2_OP_QUERY_WSL_EA:783			if (!rc) {784				idata = in_iov[i].iov_base;785				qi_rsp = rsp_iov[i + 1].iov_base;786				data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);787				size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);788				rc = check_wsl_eas(&rsp_iov[i + 1]);789				if (!rc) {790					memcpy(idata->wsl.eas, data[0], size[0]);791					idata->wsl.eas_len = size[0];792				}793			}794			if (!rc) {795				trace_smb3_query_wsl_ea_compound_done(xid, ses->Suid,796								      tcon->tid);797			} else {798				trace_smb3_query_wsl_ea_compound_err(xid, ses->Suid,799								     tcon->tid, rc);800			}801			SMB2_query_info_free(&rqst[num_rqst++]);802			break;803		}804	}805	SMB2_close_free(&rqst[num_rqst]);806 807	num_cmds += 2;808	if (out_iov && out_buftype) {809		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));810		memcpy(out_buftype, resp_buftype,811		       num_cmds * sizeof(*out_buftype));812	} else {813		for (i = 0; i < num_cmds; i++)814			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);815	}816	num_cmds -= 2; /* correct num_cmds as there could be a retry */817	kfree(vars);818 819	if (is_replayable_error(rc) &&820	    smb2_should_replay(tcon, &retries, &cur_sleep))821		goto replay_again;822 823	if (cfile)824		cifsFileInfo_put(cfile);825 826	return rc;827}828 829static int parse_create_response(struct cifs_open_info_data *data,830				 struct cifs_sb_info *cifs_sb,831				 const struct kvec *iov)832{833	struct smb2_create_rsp *rsp = iov->iov_base;834	bool reparse_point = false;835	u32 tag = 0;836	int rc = 0;837 838	switch (rsp->hdr.Status) {839	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:840		reparse_point = true;841		break;842	case STATUS_STOPPED_ON_SYMLINK:843		rc = smb2_parse_symlink_response(cifs_sb, iov,844						 &data->symlink_target);845		if (rc)846			return rc;847		tag = IO_REPARSE_TAG_SYMLINK;848		reparse_point = true;849		break;850	case STATUS_SUCCESS:851		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);852		break;853	}854	data->reparse_point = reparse_point;855	data->reparse.tag = tag;856	return rc;857}858 859int smb2_query_path_info(const unsigned int xid,860			 struct cifs_tcon *tcon,861			 struct cifs_sb_info *cifs_sb,862			 const char *full_path,863			 struct cifs_open_info_data *data)864{865	struct cifs_open_parms oparms;866	__u32 create_options = 0;867	struct cifsFileInfo *cfile;868	struct cached_fid *cfid = NULL;869	struct smb2_hdr *hdr;870	struct kvec in_iov[3], out_iov[3] = {};871	int out_buftype[3] = {};872	int cmds[3];873	bool islink;874	int i, num_cmds = 0;875	int rc, rc2;876 877	data->adjust_tz = false;878	data->reparse_point = false;879 880	/*881	 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.882	 * Create SMB2_query_posix_info worker function to do non-compounded883	 * query when we already have an open file handle for this. For now this884	 * is fast enough (always using the compounded version).885	 */886	if (!tcon->posix_extensions) {887		if (*full_path) {888			rc = -ENOENT;889		} else {890			rc = open_cached_dir(xid, tcon, full_path,891					     cifs_sb, false, &cfid);892		}893		/* If it is a root and its handle is cached then use it */894		if (!rc) {895			if (cfid->file_all_info_is_valid) {896				memcpy(&data->fi, &cfid->file_all_info,897				       sizeof(data->fi));898			} else {899				rc = SMB2_query_info(xid, tcon,900						     cfid->fid.persistent_fid,901						     cfid->fid.volatile_fid,902						     &data->fi);903			}904			close_cached_dir(cfid);905			return rc;906		}907		cmds[num_cmds++] = SMB2_OP_QUERY_INFO;908	} else {909		cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;910	}911 912	in_iov[0].iov_base = data;913	in_iov[0].iov_len = sizeof(*data);914	in_iov[1] = in_iov[0];915	in_iov[2] = in_iov[0];916 917	cifs_get_readable_path(tcon, full_path, &cfile);918	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,919			     FILE_OPEN, create_options, ACL_NO_MODE);920	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,921			      &oparms, in_iov, cmds, num_cmds,922			      cfile, out_iov, out_buftype, NULL);923	hdr = out_iov[0].iov_base;924	/*925	 * If first iov is unset, then SMB session was dropped or we've got a926	 * cached open file (@cfile).927	 */928	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)929		goto out;930 931	switch (rc) {932	case 0:933		rc = parse_create_response(data, cifs_sb, &out_iov[0]);934		break;935	case -EOPNOTSUPP:936		/*937		 * BB TODO: When support for special files added to Samba938		 * re-verify this path.939		 */940		rc = parse_create_response(data, cifs_sb, &out_iov[0]);941		if (rc || !data->reparse_point)942			goto out;943 944		cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;945		/*946		 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create947		 * response.948		 */949		if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)950			cmds[num_cmds++] = SMB2_OP_GET_REPARSE;951 952		oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,953				     FILE_READ_ATTRIBUTES |954				     FILE_READ_EA | SYNCHRONIZE,955				     FILE_OPEN, create_options |956				     OPEN_REPARSE_POINT, ACL_NO_MODE);957		cifs_get_readable_path(tcon, full_path, &cfile);958		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,959				      &oparms, in_iov, cmds, num_cmds,960				      cfile, NULL, NULL, NULL);961		break;962	case -EREMOTE:963		break;964	default:965		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)966			break;967		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,968						     full_path, &islink);969		if (rc2) {970			rc = rc2;971			goto out;972		}973		if (islink)974			rc = -EREMOTE;975	}976 977out:978	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)979		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);980	return rc;981}982 983int984smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,985	   struct cifs_tcon *tcon, const char *name,986	   struct cifs_sb_info *cifs_sb)987{988	struct cifs_open_parms oparms;989 990	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,991			     FILE_CREATE, CREATE_NOT_FILE, mode);992	return smb2_compound_op(xid, tcon, cifs_sb,993				name, &oparms, NULL,994				&(int){SMB2_OP_MKDIR}, 1,995				NULL, NULL, NULL, NULL);996}997 998void999smb2_mkdir_setinfo(struct inode *inode, const char *name,1000		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,1001		   const unsigned int xid)1002{1003	struct cifs_open_parms oparms;1004	FILE_BASIC_INFO data = {};1005	struct cifsInodeInfo *cifs_i;1006	struct cifsFileInfo *cfile;1007	struct kvec in_iov;1008	u32 dosattrs;1009	int tmprc;1010 1011	in_iov.iov_base = &data;1012	in_iov.iov_len = sizeof(data);1013	cifs_i = CIFS_I(inode);1014	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;1015	data.Attributes = cpu_to_le32(dosattrs);1016	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);1017	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,1018			     FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);1019	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,1020				 &oparms, &in_iov,1021				 &(int){SMB2_OP_SET_INFO}, 1,1022				 cfile, NULL, NULL, NULL);1023	if (tmprc == 0)1024		cifs_i->cifsAttrs = dosattrs;1025}1026 1027int1028smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,1029	   struct cifs_sb_info *cifs_sb)1030{1031	struct cifs_open_parms oparms;1032 1033	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);1034	oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,1035			     FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);1036	return smb2_compound_op(xid, tcon, cifs_sb,1037				name, &oparms, NULL,1038				&(int){SMB2_OP_RMDIR}, 1,1039				NULL, NULL, NULL, NULL);1040}1041 1042int1043smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,1044	    struct cifs_sb_info *cifs_sb, struct dentry *dentry)1045{1046	struct cifs_open_parms oparms;1047 1048	oparms = CIFS_OPARMS(cifs_sb, tcon, name,1049			     DELETE, FILE_OPEN,1050			     CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,1051			     ACL_NO_MODE);1052	int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,1053				  NULL, &(int){SMB2_OP_DELETE}, 1,1054				  NULL, NULL, NULL, dentry);1055	if (rc == -EINVAL) {1056		cifs_dbg(FYI, "invalid lease key, resending request without lease");1057		rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,1058				      NULL, &(int){SMB2_OP_DELETE}, 1,1059				      NULL, NULL, NULL, NULL);1060	}1061	return rc;1062}1063 1064static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,1065			      const char *from_name, const char *to_name,1066			      struct cifs_sb_info *cifs_sb,1067			      __u32 create_options, __u32 access,1068			      int command, struct cifsFileInfo *cfile,1069				  struct dentry *dentry)1070{1071	struct cifs_open_parms oparms;1072	struct kvec in_iov;1073	__le16 *smb2_to_name = NULL;1074	int rc;1075 1076	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);1077	if (smb2_to_name == NULL) {1078		rc = -ENOMEM;1079		goto smb2_rename_path;1080	}1081	in_iov.iov_base = smb2_to_name;1082	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);1083	oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,1084			     create_options, ACL_NO_MODE);1085	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,1086			      &oparms, &in_iov, &command, 1,1087			      cfile, NULL, NULL, dentry);1088smb2_rename_path:1089	kfree(smb2_to_name);1090	return rc;1091}1092 1093int smb2_rename_path(const unsigned int xid,1094		     struct cifs_tcon *tcon,1095		     struct dentry *source_dentry,1096		     const char *from_name, const char *to_name,1097		     struct cifs_sb_info *cifs_sb)1098{1099	struct cifsFileInfo *cfile;1100	__u32 co = file_create_options(source_dentry);1101 1102	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);1103	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);1104 1105	int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,1106				  co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);1107	if (rc == -EINVAL) {1108		cifs_dbg(FYI, "invalid lease key, resending request without lease");1109		cifs_get_writable_path(tcon, from_name,1110				       FIND_WR_WITH_DELETE, &cfile);1111		rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,1112				  co, DELETE, SMB2_OP_RENAME, cfile, NULL);1113	}1114	return rc;1115}1116 1117int smb2_create_hardlink(const unsigned int xid,1118			 struct cifs_tcon *tcon,1119			 struct dentry *source_dentry,1120			 const char *from_name, const char *to_name,1121			 struct cifs_sb_info *cifs_sb)1122{1123	__u32 co = file_create_options(source_dentry);1124 1125	return smb2_set_path_attr(xid, tcon, from_name, to_name,1126				  cifs_sb, co, FILE_READ_ATTRIBUTES,1127				  SMB2_OP_HARDLINK, NULL, NULL);1128}1129 1130int1131smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,1132		   const char *full_path, __u64 size,1133		   struct cifs_sb_info *cifs_sb, bool set_alloc,1134		   struct dentry *dentry)1135{1136	struct cifs_open_parms oparms;1137	struct cifsFileInfo *cfile;1138	struct kvec in_iov;1139	__le64 eof = cpu_to_le64(size);1140	int rc;1141 1142	in_iov.iov_base = &eof;1143	in_iov.iov_len = sizeof(eof);1144	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);1145 1146	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,1147			     FILE_OPEN, 0, ACL_NO_MODE);1148	rc = smb2_compound_op(xid, tcon, cifs_sb,1149			      full_path, &oparms, &in_iov,1150			      &(int){SMB2_OP_SET_EOF}, 1,1151			      cfile, NULL, NULL, dentry);1152	if (rc == -EINVAL) {1153		cifs_dbg(FYI, "invalid lease key, resending request without lease");1154		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);1155		rc = smb2_compound_op(xid, tcon, cifs_sb,1156				      full_path, &oparms, &in_iov,1157				      &(int){SMB2_OP_SET_EOF}, 1,1158				      cfile, NULL, NULL, NULL);1159	}1160	return rc;1161}1162 1163int1164smb2_set_file_info(struct inode *inode, const char *full_path,1165		   FILE_BASIC_INFO *buf, const unsigned int xid)1166{1167	struct cifs_open_parms oparms;1168	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);1169	struct tcon_link *tlink;1170	struct cifs_tcon *tcon;1171	struct cifsFileInfo *cfile;1172	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };1173	int rc;1174 1175	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&1176	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&1177	    (buf->Attributes == 0))1178		return 0; /* would be a no op, no sense sending this */1179 1180	tlink = cifs_sb_tlink(cifs_sb);1181	if (IS_ERR(tlink))1182		return PTR_ERR(tlink);1183	tcon = tlink_tcon(tlink);1184 1185	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);1186	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,1187			     FILE_OPEN, 0, ACL_NO_MODE);1188	rc = smb2_compound_op(xid, tcon, cifs_sb,1189			      full_path, &oparms, &in_iov,1190			      &(int){SMB2_OP_SET_INFO}, 1,1191			      cfile, NULL, NULL, NULL);1192	cifs_put_tlink(tlink);1193	return rc;1194}1195 1196struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,1197				     struct super_block *sb,1198				     const unsigned int xid,1199				     struct cifs_tcon *tcon,1200				     const char *full_path,1201				     bool directory,1202				     struct kvec *reparse_iov,1203				     struct kvec *xattr_iov)1204{1205	struct cifs_open_parms oparms;1206	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);1207	struct cifsFileInfo *cfile;1208	struct inode *new = NULL;1209	int out_buftype[4] = {};1210	struct kvec out_iov[4] = {};1211	struct kvec in_iov[2];1212	int cmds[2];1213	int rc;1214	int i;1215 1216	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,1217			     SYNCHRONIZE | DELETE |1218			     FILE_READ_ATTRIBUTES |1219			     FILE_WRITE_ATTRIBUTES,1220			     FILE_CREATE,1221			     (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,1222			     ACL_NO_MODE);1223	if (xattr_iov)1224		oparms.ea_cctx = xattr_iov;1225 1226	cmds[0] = SMB2_OP_SET_REPARSE;1227	in_iov[0] = *reparse_iov;1228	in_iov[1].iov_base = data;1229	in_iov[1].iov_len = sizeof(*data);1230 1231	if (tcon->posix_extensions) {1232		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;1233		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);1234		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,1235				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);1236		if (!rc) {1237			rc = smb311_posix_get_inode_info(&new, full_path,1238							 data, sb, xid);1239		}1240	} else {1241		cmds[1] = SMB2_OP_QUERY_INFO;1242		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);1243		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,1244				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);1245		if (!rc) {1246			rc = cifs_get_inode_info(&new, full_path,1247						 data, sb, xid, NULL);1248		}1249	}1250 1251 1252	/*1253	 * If CREATE was successful but SMB2_OP_SET_REPARSE failed then1254	 * remove the intermediate object created by CREATE. Otherwise1255	 * empty object stay on the server when reparse call failed.1256	 */1257	if (rc &&1258	    out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&1259	    ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&1260	    (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||1261	     ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))1262		smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);1263 1264	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)1265		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);1266 1267	return rc ? ERR_PTR(rc) : new;1268}1269 1270int smb2_query_reparse_point(const unsigned int xid,1271			     struct cifs_tcon *tcon,1272			     struct cifs_sb_info *cifs_sb,1273			     const char *full_path,1274			     u32 *tag, struct kvec *rsp,1275			     int *rsp_buftype)1276{1277	struct cifs_open_parms oparms;1278	struct cifs_open_info_data data = {};1279	struct cifsFileInfo *cfile;1280	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };1281	int rc;1282 1283	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);1284 1285	cifs_get_readable_path(tcon, full_path, &cfile);1286	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,1287			     FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,1288			     FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);1289	rc = smb2_compound_op(xid, tcon, cifs_sb,1290			      full_path, &oparms, &in_iov,1291			      &(int){SMB2_OP_GET_REPARSE}, 1,1292			      cfile, NULL, NULL, NULL);1293	if (rc)1294		goto out;1295 1296	*tag = data.reparse.tag;1297	*rsp = data.reparse.io.iov;1298	*rsp_buftype = data.reparse.io.buftype;1299	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));1300	data.reparse.io.buftype = CIFS_NO_BUFFER;1301out:1302	cifs_free_open_info(&data);1303	return rc;1304}1305