xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_read.c (revision 8b01ef7edff13741f64ad808a21df17c08f198a8)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6a90cf9f2SGordon Ross  *
7a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross  */
11a90cf9f2SGordon Ross 
12a90cf9f2SGordon Ross /*
139c9612c4SGordon Ross  * Copyright 2015-2021 Tintri by DDN, Inc. All rights reserved.
14a90cf9f2SGordon Ross  */
15a90cf9f2SGordon Ross 
16a90cf9f2SGordon Ross /*
17a90cf9f2SGordon Ross  * Dispatch function for SMB2_READ
184d2aba2fSGordon Ross  * MS-SMB2 sec. 3.3.5.12
19a90cf9f2SGordon Ross  */
20a90cf9f2SGordon Ross 
21a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
22a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
23a90cf9f2SGordon Ross 
24dfa42fabSMatt Barden extern boolean_t smb_allow_unbuffered;
25dfa42fabSMatt Barden 
26*8b01ef7eSGordon Ross int smb2_read_zcopy = 1;
27*8b01ef7eSGordon Ross 
28*8b01ef7eSGordon Ross /*
29*8b01ef7eSGordon Ross  * Copy Reduction support.
30*8b01ef7eSGordon Ross  * xuio_t wrapper with additional private data.
31*8b01ef7eSGordon Ross  */
32*8b01ef7eSGordon Ross typedef struct smb_xuio {
33*8b01ef7eSGordon Ross 	xuio_t su_xuio;		// keep first!
34*8b01ef7eSGordon Ross 	smb_node_t *su_node;
35*8b01ef7eSGordon Ross 	uint_t su_ref;
36*8b01ef7eSGordon Ross } smb_xuio_t;
37*8b01ef7eSGordon Ross 
38*8b01ef7eSGordon Ross /*
39*8b01ef7eSGordon Ross  * Allocate an smb_xuio_t object.  This survives long enough
40*8b01ef7eSGordon Ross  * to keep track of buffers loaned to us from the VFS layer.
41*8b01ef7eSGordon Ross  * We'll construct mbufs with "external" buffers setup to
42*8b01ef7eSGordon Ross  * point to the loaned VFS buffers, incrementing the su_ref
43*8b01ef7eSGordon Ross  * count for each.  Each such message when free'd will call
44*8b01ef7eSGordon Ross  * the smb_xuio_free function below.
45*8b01ef7eSGordon Ross  */
46*8b01ef7eSGordon Ross smb_xuio_t *
smb_xuio_alloc(smb_node_t * node)47*8b01ef7eSGordon Ross smb_xuio_alloc(smb_node_t *node)
48*8b01ef7eSGordon Ross {
49*8b01ef7eSGordon Ross 	smb_xuio_t *su;
50*8b01ef7eSGordon Ross 
51*8b01ef7eSGordon Ross 	su = kmem_zalloc(sizeof (*su), KM_SLEEP);
52*8b01ef7eSGordon Ross 	su->su_node = node;
53*8b01ef7eSGordon Ross 	smb_node_ref(node);
54*8b01ef7eSGordon Ross 
55*8b01ef7eSGordon Ross 	/*
56*8b01ef7eSGordon Ross 	 * Initial ref count set to 1, later incremented
57*8b01ef7eSGordon Ross 	 * for the mbufs that refer to borrowed buffers
58*8b01ef7eSGordon Ross 	 * owned by this xuio.  See smb_xuio_to_mbuf().
59*8b01ef7eSGordon Ross 	 */
60*8b01ef7eSGordon Ross 	su->su_ref = 1;
61*8b01ef7eSGordon Ross 	su->su_xuio.xu_type = UIOTYPE_ZEROCOPY;
62*8b01ef7eSGordon Ross 
63*8b01ef7eSGordon Ross 	return (su);
64*8b01ef7eSGordon Ross }
65*8b01ef7eSGordon Ross 
66*8b01ef7eSGordon Ross /*
67*8b01ef7eSGordon Ross  * Callback function to return the loaned buffers.
68*8b01ef7eSGordon Ross  * Calls VOP_RETZCBUF() only after all messages with
69*8b01ef7eSGordon Ross  * references to this xuio are free'd.
70*8b01ef7eSGordon Ross  */
71*8b01ef7eSGordon Ross void
smb_xuio_free(void * varg)72*8b01ef7eSGordon Ross smb_xuio_free(void *varg)
73*8b01ef7eSGordon Ross {
74*8b01ef7eSGordon Ross 	uint_t ref;
75*8b01ef7eSGordon Ross 	smb_xuio_t *su = (smb_xuio_t *)varg;
76*8b01ef7eSGordon Ross 	xuio_t *xu = &su->su_xuio;
77*8b01ef7eSGordon Ross 
78*8b01ef7eSGordon Ross 	ref = atomic_dec_uint_nv(&su->su_ref);
79*8b01ef7eSGordon Ross 	if (ref != 0)
80*8b01ef7eSGordon Ross 		return;
81*8b01ef7eSGordon Ross 
82*8b01ef7eSGordon Ross 	/* The XUIO flag is set by VOP_REQZCBUF */
83*8b01ef7eSGordon Ross 	if (xu->xu_uio.uio_extflg & UIO_XUIO) {
84*8b01ef7eSGordon Ross 		(void) smb_fsop_retzcbuf(su->su_node, xu, CRED());
85*8b01ef7eSGordon Ross 	}
86*8b01ef7eSGordon Ross 
87*8b01ef7eSGordon Ross 	smb_node_release(su->su_node);
88*8b01ef7eSGordon Ross 	kmem_free(su, sizeof (*su));
89*8b01ef7eSGordon Ross }
90*8b01ef7eSGordon Ross 
91*8b01ef7eSGordon Ross /*
92*8b01ef7eSGordon Ross  * Wrapper for smb_mbuf_alloc_ext free function because the
93*8b01ef7eSGordon Ross  * free function is passed a pointer to the mbuf, not arg1.
94*8b01ef7eSGordon Ross  */
95*8b01ef7eSGordon Ross static void
smb_xuio_mbuf_free(mbuf_t * m)96*8b01ef7eSGordon Ross smb_xuio_mbuf_free(mbuf_t *m)
97*8b01ef7eSGordon Ross {
98*8b01ef7eSGordon Ross 	ASSERT((m->m_flags & M_EXT) != 0);
99*8b01ef7eSGordon Ross 	smb_xuio_free(m->m_ext.ext_arg1);
100*8b01ef7eSGordon Ross 	/* caller clears m_ext.ext_buf */
101*8b01ef7eSGordon Ross }
102*8b01ef7eSGordon Ross 
103*8b01ef7eSGordon Ross /*
104*8b01ef7eSGordon Ross  * Build list of mbufs pointing to the loaned xuio buffers.
105*8b01ef7eSGordon Ross  * Note these are not visible yet to other threads, so
106*8b01ef7eSGordon Ross  * not using atomics to adjust su_ref.
107*8b01ef7eSGordon Ross  */
108*8b01ef7eSGordon Ross static mbuf_t *
smb_xuio_to_mbuf(smb_xuio_t * su)109*8b01ef7eSGordon Ross smb_xuio_to_mbuf(smb_xuio_t *su)
110*8b01ef7eSGordon Ross {
111*8b01ef7eSGordon Ross 	uio_t *uiop;
112*8b01ef7eSGordon Ross 	struct iovec *iovp;
113*8b01ef7eSGordon Ross 	mbuf_t *mp, *mp1;
114*8b01ef7eSGordon Ross 	int i;
115*8b01ef7eSGordon Ross 
116*8b01ef7eSGordon Ross 	uiop = &su->su_xuio.xu_uio;
117*8b01ef7eSGordon Ross 	if (uiop->uio_iovcnt == 0)
118*8b01ef7eSGordon Ross 		return (NULL);
119*8b01ef7eSGordon Ross 
120*8b01ef7eSGordon Ross 	iovp = uiop->uio_iov;
121*8b01ef7eSGordon Ross 
122*8b01ef7eSGordon Ross 	mp = smb_mbuf_alloc_ext(iovp->iov_base, iovp->iov_len,
123*8b01ef7eSGordon Ross 	    smb_xuio_mbuf_free, su);
124*8b01ef7eSGordon Ross 	ASSERT(mp != NULL);
125*8b01ef7eSGordon Ross 	su->su_ref++;
126*8b01ef7eSGordon Ross 
127*8b01ef7eSGordon Ross 	mp1 = mp;
128*8b01ef7eSGordon Ross 	for (i = 1; i < uiop->uio_iovcnt; i++) {
129*8b01ef7eSGordon Ross 		iovp = (uiop->uio_iov + i);
130*8b01ef7eSGordon Ross 
131*8b01ef7eSGordon Ross 		mp1->m_next = smb_mbuf_alloc_ext(iovp->iov_base,
132*8b01ef7eSGordon Ross 		    iovp->iov_len, smb_xuio_mbuf_free, su);
133*8b01ef7eSGordon Ross 
134*8b01ef7eSGordon Ross 		mp1 = mp1->m_next;
135*8b01ef7eSGordon Ross 		ASSERT(mp1 != NULL);
136*8b01ef7eSGordon Ross 		su->su_ref++;
137*8b01ef7eSGordon Ross 	}
138*8b01ef7eSGordon Ross 
139*8b01ef7eSGordon Ross 	return (mp);
140*8b01ef7eSGordon Ross }
141*8b01ef7eSGordon Ross 
142a90cf9f2SGordon Ross smb_sdrc_t
smb2_read(smb_request_t * sr)143a90cf9f2SGordon Ross smb2_read(smb_request_t *sr)
144a90cf9f2SGordon Ross {
14593bc28dbSGordon Ross 	smb_rw_param_t *param = NULL;
146a90cf9f2SGordon Ross 	smb_ofile_t *of = NULL;
147a90cf9f2SGordon Ross 	smb_vdb_t *vdb = NULL;
148a90cf9f2SGordon Ross 	struct mbuf *m = NULL;
149*8b01ef7eSGordon Ross 	smb_xuio_t *su = NULL;
150*8b01ef7eSGordon Ross 	uio_t *uio = NULL;
151a90cf9f2SGordon Ross 	uint16_t StructSize;
152a90cf9f2SGordon Ross 	uint8_t Padding;
153dfa42fabSMatt Barden 	uint8_t Flags;
154a90cf9f2SGordon Ross 	uint8_t DataOff;
155a90cf9f2SGordon Ross 	uint32_t Length;
156a90cf9f2SGordon Ross 	uint64_t Offset;
157a90cf9f2SGordon Ross 	smb2fid_t smb2fid;
158a90cf9f2SGordon Ross 	uint32_t MinCount;
159a90cf9f2SGordon Ross 	uint32_t Channel;
160a90cf9f2SGordon Ross 	uint32_t Remaining;
161a90cf9f2SGordon Ross 	uint16_t ChanInfoOffset;
162a90cf9f2SGordon Ross 	uint16_t ChanInfoLength;
1639c9612c4SGordon Ross 	uint32_t XferCount = 0;
164a90cf9f2SGordon Ross 	uint32_t status;
165a90cf9f2SGordon Ross 	int rc = 0;
166dfa42fabSMatt Barden 	int ioflag = 0;
167*8b01ef7eSGordon Ross 	boolean_t unbuffered = B_FALSE;
168*8b01ef7eSGordon Ross 	boolean_t zcopy = B_FALSE;
169a90cf9f2SGordon Ross 
170a90cf9f2SGordon Ross 	/*
171a90cf9f2SGordon Ross 	 * SMB2 Read request
172a90cf9f2SGordon Ross 	 */
173a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
174a90cf9f2SGordon Ross 	    &sr->smb_data,
175dfa42fabSMatt Barden 	    "wbblqqqlllww",
176a90cf9f2SGordon Ross 	    &StructSize,		/* w */
177dfa42fabSMatt Barden 	    &Padding,			/* b */
178dfa42fabSMatt Barden 	    &Flags,			/* b */
179a90cf9f2SGordon Ross 	    &Length,			/* l */
180a90cf9f2SGordon Ross 	    &Offset,			/* q */
181a90cf9f2SGordon Ross 	    &smb2fid.persistent,	/* q */
182a90cf9f2SGordon Ross 	    &smb2fid.temporal,		/* q */
183a90cf9f2SGordon Ross 	    &MinCount,			/* l */
184a90cf9f2SGordon Ross 	    &Channel,			/* l */
185a90cf9f2SGordon Ross 	    &Remaining,			/* l */
186a90cf9f2SGordon Ross 	    &ChanInfoOffset,		/* w */
187a90cf9f2SGordon Ross 	    &ChanInfoLength);		/* w */
188a90cf9f2SGordon Ross 	if (rc)
189a90cf9f2SGordon Ross 		return (SDRC_ERROR);
190a90cf9f2SGordon Ross 	if (StructSize != 49)
191a90cf9f2SGordon Ross 		return (SDRC_ERROR);
192a90cf9f2SGordon Ross 
19393bc28dbSGordon Ross 	/*
19493bc28dbSGordon Ross 	 * Setup an smb_rw_param_t which contains the VDB we need.
19593bc28dbSGordon Ross 	 * This is automatically free'd.
19693bc28dbSGordon Ross 	 */
19793bc28dbSGordon Ross 	param = smb_srm_zalloc(sr, sizeof (*param));
19893bc28dbSGordon Ross 	param->rw_offset = Offset;
19993bc28dbSGordon Ross 	param->rw_count = Length;
20093bc28dbSGordon Ross 	/* Note that the dtrace provider uses sr->arg.rw */
20193bc28dbSGordon Ross 	sr->arg.rw = param;
20293bc28dbSGordon Ross 
20393bc28dbSGordon Ross 	/*
20493bc28dbSGordon Ross 	 * Want FID lookup before the start probe.
20593bc28dbSGordon Ross 	 */
206a90cf9f2SGordon Ross 	status = smb2sr_lookup_fid(sr, &smb2fid);
207a90cf9f2SGordon Ross 	of = sr->fid_ofile;
208a90cf9f2SGordon Ross 
20993bc28dbSGordon Ross 	DTRACE_SMB2_START(op__Read, smb_request_t *, sr); /* arg.rw */
21093bc28dbSGordon Ross 
2119c9612c4SGordon Ross 	if (status != 0)
2129c9612c4SGordon Ross 		goto done; /* Bad FID */
2139c9612c4SGordon Ross 
2149c9612c4SGordon Ross 	/*
2159c9612c4SGordon Ross 	 * Short-circuit zero-byte read, otherwise could panic
2169c9612c4SGordon Ross 	 * setting up buffers in smb_mbuf_allocate etc.
2179c9612c4SGordon Ross 	 */
2189c9612c4SGordon Ross 	if (Length == 0)
2199c9612c4SGordon Ross 		goto done;
22093bc28dbSGordon Ross 
221a90cf9f2SGordon Ross 	if (Length > smb2_max_rwsize) {
22293bc28dbSGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
2239c9612c4SGordon Ross 		goto done;
224a90cf9f2SGordon Ross 	}
225a90cf9f2SGordon Ross 	if (MinCount > Length)
226a90cf9f2SGordon Ross 		MinCount = Length;
227a90cf9f2SGordon Ross 
22893bc28dbSGordon Ross 	vdb = &param->rw_vdb;
229a90cf9f2SGordon Ross 	vdb->vdb_tag = 0;
230a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
231a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
232a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_resid = Length;
233a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_loffset = (offset_t)Offset;
234a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
235a90cf9f2SGordon Ross 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
236a90cf9f2SGordon Ross 
237dfa42fabSMatt Barden 	/*
238dfa42fabSMatt Barden 	 * Unbuffered refers to the MS-FSA Read argument by the same name.
239dfa42fabSMatt Barden 	 * It indicates that the cache for this range should be flushed to disk,
240dfa42fabSMatt Barden 	 * and data read directly from disk, bypassing the cache.
241dfa42fabSMatt Barden 	 * We don't allow that degree of cache management.
242dfa42fabSMatt Barden 	 * Translate this directly as FRSYNC,
243dfa42fabSMatt Barden 	 * which should at least flush the cache first.
244dfa42fabSMatt Barden 	 */
245dfa42fabSMatt Barden 
246dfa42fabSMatt Barden 	if (smb_allow_unbuffered &&
247dfa42fabSMatt Barden 	    (Flags & SMB2_READFLAG_READ_UNBUFFERED) != 0) {
248dfa42fabSMatt Barden 		unbuffered = B_TRUE;
249dfa42fabSMatt Barden 		ioflag = FRSYNC;
250dfa42fabSMatt Barden 	}
251dfa42fabSMatt Barden 
252a90cf9f2SGordon Ross 	switch (of->f_tree->t_res_type & STYPE_MASK) {
253a90cf9f2SGordon Ross 	case STYPE_DISKTREE:
254*8b01ef7eSGordon Ross 		if (smb_node_is_dir(of->f_node)) {
255*8b01ef7eSGordon Ross 			rc = EISDIR;
256*8b01ef7eSGordon Ross 			break;
257*8b01ef7eSGordon Ross 		}
258a90cf9f2SGordon Ross 		/* Check for conflicting locks. */
259a90cf9f2SGordon Ross 		rc = smb_lock_range_access(sr, of->f_node,
260a90cf9f2SGordon Ross 		    Offset, Length, B_FALSE);
261a90cf9f2SGordon Ross 		if (rc) {
262a90cf9f2SGordon Ross 			rc = ERANGE;
263a90cf9f2SGordon Ross 			break;
264a90cf9f2SGordon Ross 		}
265*8b01ef7eSGordon Ross 
266*8b01ef7eSGordon Ross 		zcopy = (smb2_read_zcopy != 0);
267*8b01ef7eSGordon Ross 		if (zcopy) {
268*8b01ef7eSGordon Ross 			su = smb_xuio_alloc(of->f_node);
269*8b01ef7eSGordon Ross 			uio = &su->su_xuio.xu_uio;
270*8b01ef7eSGordon Ross 			uio->uio_segflg = UIO_SYSSPACE;
271*8b01ef7eSGordon Ross 			uio->uio_loffset = (offset_t)Offset;
272*8b01ef7eSGordon Ross 			uio->uio_resid = Length;
273*8b01ef7eSGordon Ross 
274*8b01ef7eSGordon Ross 			rc = smb_fsop_reqzcbuf(of->f_node, &su->su_xuio,
275*8b01ef7eSGordon Ross 			    UIO_READ, of->f_cr);
276*8b01ef7eSGordon Ross 			if (rc == 0) {
277*8b01ef7eSGordon Ross 				ASSERT((uio->uio_extflg & UIO_XUIO) != 0);
278*8b01ef7eSGordon Ross 			} else {
279*8b01ef7eSGordon Ross 				ASSERT((uio->uio_extflg & UIO_XUIO) == 0);
280*8b01ef7eSGordon Ross 				smb_xuio_free(su);
281*8b01ef7eSGordon Ross 				su = NULL;
282*8b01ef7eSGordon Ross 				uio = NULL;
283*8b01ef7eSGordon Ross 				zcopy = B_FALSE;
284a90cf9f2SGordon Ross 			}
285*8b01ef7eSGordon Ross 		}
286*8b01ef7eSGordon Ross 		if (!zcopy) {
287*8b01ef7eSGordon Ross 			sr->raw_data.max_bytes = Length;
288*8b01ef7eSGordon Ross 			m = smb_mbuf_allocate(&vdb->vdb_uio);
289*8b01ef7eSGordon Ross 			uio = &vdb->vdb_uio;
290*8b01ef7eSGordon Ross 		}
291*8b01ef7eSGordon Ross 
292*8b01ef7eSGordon Ross 		rc = smb_fsop_read(sr, of->f_cr, of->f_node, of, uio, ioflag);
293*8b01ef7eSGordon Ross 		if (rc != 0) {
294*8b01ef7eSGordon Ross 			if (zcopy) {
295*8b01ef7eSGordon Ross 				smb_xuio_free(su);
296*8b01ef7eSGordon Ross 				su = NULL;
297*8b01ef7eSGordon Ross 				uio = NULL;
298*8b01ef7eSGordon Ross 			}
299*8b01ef7eSGordon Ross 			m_freem(m);
300*8b01ef7eSGordon Ross 			m = NULL;
301a90cf9f2SGordon Ross 			break;
302*8b01ef7eSGordon Ross 		}
303*8b01ef7eSGordon Ross 
304*8b01ef7eSGordon Ross 		/* How much data we moved. */
305*8b01ef7eSGordon Ross 		XferCount = Length - uio->uio_resid;
306*8b01ef7eSGordon Ross 
307*8b01ef7eSGordon Ross 		if (zcopy) {
308*8b01ef7eSGordon Ross 			/*
309*8b01ef7eSGordon Ross 			 * Build mblk chain of messages pointing to
310*8b01ef7eSGordon Ross 			 * the loaned buffers in su->su_xuio
311*8b01ef7eSGordon Ross 			 * Done with su (and uio) after this.
312*8b01ef7eSGordon Ross 			 * NB: uio points into su->su_xuio
313*8b01ef7eSGordon Ross 			 */
314*8b01ef7eSGordon Ross 			ASSERT(m == NULL);
315*8b01ef7eSGordon Ross 			m = smb_xuio_to_mbuf(su);
316*8b01ef7eSGordon Ross 			smb_xuio_free(su);
317*8b01ef7eSGordon Ross 			su = NULL;
318*8b01ef7eSGordon Ross 			uio = NULL;
319*8b01ef7eSGordon Ross 		}
320*8b01ef7eSGordon Ross 
321*8b01ef7eSGordon Ross 		sr->raw_data.max_bytes = XferCount;
322*8b01ef7eSGordon Ross 		smb_mbuf_trim(m, XferCount);
323*8b01ef7eSGordon Ross 		MBC_ATTACH_MBUF(&sr->raw_data, m);
324*8b01ef7eSGordon Ross 
325*8b01ef7eSGordon Ross 		break;
326*8b01ef7eSGordon Ross 
327a90cf9f2SGordon Ross 	case STYPE_IPC:
328*8b01ef7eSGordon Ross 		if (unbuffered) {
329dfa42fabSMatt Barden 			rc = EINVAL;
330a90cf9f2SGordon Ross 			break;
331*8b01ef7eSGordon Ross 		}
332*8b01ef7eSGordon Ross 		sr->raw_data.max_bytes = Length;
333*8b01ef7eSGordon Ross 		m = smb_mbuf_allocate(&vdb->vdb_uio);
334*8b01ef7eSGordon Ross 
335*8b01ef7eSGordon Ross 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
336*8b01ef7eSGordon Ross 
337*8b01ef7eSGordon Ross 		/* How much data we moved. */
338*8b01ef7eSGordon Ross 		XferCount = Length - vdb->vdb_uio.uio_resid;
339*8b01ef7eSGordon Ross 		sr->raw_data.max_bytes = XferCount;
340*8b01ef7eSGordon Ross 		smb_mbuf_trim(m, XferCount);
341*8b01ef7eSGordon Ross 		MBC_ATTACH_MBUF(&sr->raw_data, m);
342*8b01ef7eSGordon Ross 		break;
343*8b01ef7eSGordon Ross 
344a90cf9f2SGordon Ross 	default:
345a90cf9f2SGordon Ross 	case STYPE_PRINTQ:
346a90cf9f2SGordon Ross 		rc = EACCES;
347a90cf9f2SGordon Ross 		break;
348a90cf9f2SGordon Ross 	}
34993bc28dbSGordon Ross 	status = smb_errno2status(rc);
350a90cf9f2SGordon Ross 
351a90cf9f2SGordon Ross 	/*
3524d2aba2fSGordon Ross 	 * [MS-SMB2] If the read returns fewer bytes than specified by
3534d2aba2fSGordon Ross 	 * the MinimumCount field of the request, the server MUST fail
3544d2aba2fSGordon Ross 	 * the request with STATUS_END_OF_FILE
3554d2aba2fSGordon Ross 	 */
3564d2aba2fSGordon Ross 	if (status == 0 && XferCount < MinCount)
3574d2aba2fSGordon Ross 		status = NT_STATUS_END_OF_FILE;
3584d2aba2fSGordon Ross 
3594d2aba2fSGordon Ross 	/*
360a90cf9f2SGordon Ross 	 * Checking the error return _after_ dealing with
361a90cf9f2SGordon Ross 	 * the returned data so that if m was allocated,
362a90cf9f2SGordon Ross 	 * it will be free'd via sr->raw_data cleanup.
363a90cf9f2SGordon Ross 	 */
3649c9612c4SGordon Ross done:
36593bc28dbSGordon Ross 	sr->smb2_status = status;
36693bc28dbSGordon Ross 	DTRACE_SMB2_DONE(op__Read, smb_request_t *, sr); /* arg.rw */
36793bc28dbSGordon Ross 	if (status) {
36893bc28dbSGordon Ross 		smb2sr_put_error(sr, status);
369a90cf9f2SGordon Ross 		return (SDRC_SUCCESS);
370a90cf9f2SGordon Ross 	}
371a90cf9f2SGordon Ross 
372a90cf9f2SGordon Ross 	/*
373a90cf9f2SGordon Ross 	 * SMB2 Read reply
374a90cf9f2SGordon Ross 	 */
375a90cf9f2SGordon Ross 	DataOff = SMB2_HDR_SIZE + 16;
376a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
377a90cf9f2SGordon Ross 	    &sr->reply,
378a90cf9f2SGordon Ross 	    "wb.lllC",
379a90cf9f2SGordon Ross 	    17,	/* StructSize */	/* w */
380a90cf9f2SGordon Ross 	    DataOff,			/* b. */
381a90cf9f2SGordon Ross 	    XferCount,			/* l */
382a90cf9f2SGordon Ross 	    0, /* DataRemaining */	/* l */
383a90cf9f2SGordon Ross 	    0, /* reserved */		/* l */
384a90cf9f2SGordon Ross 	    &sr->raw_data);		/* C */
38593bc28dbSGordon Ross 	if (rc) {
38693bc28dbSGordon Ross 		sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
387a90cf9f2SGordon Ross 		return (SDRC_ERROR);
38893bc28dbSGordon Ross 	}
389a90cf9f2SGordon Ross 
390a90cf9f2SGordon Ross 	mutex_enter(&of->f_mutex);
391a90cf9f2SGordon Ross 	of->f_seek_pos = Offset + XferCount;
392a90cf9f2SGordon Ross 	mutex_exit(&of->f_mutex);
393a90cf9f2SGordon Ross 
394a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
395a90cf9f2SGordon Ross }
396