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 = ¶m->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