1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Dispatch function for SMB2_READ 18 */ 19 20 #include <smbsrv/smb2_kproto.h> 21 #include <smbsrv/smb_fsops.h> 22 23 extern boolean_t smb_allow_unbuffered; 24 25 smb_sdrc_t 26 smb2_read(smb_request_t *sr) 27 { 28 smb_rw_param_t *param = NULL; 29 smb_ofile_t *of = NULL; 30 smb_vdb_t *vdb = NULL; 31 struct mbuf *m = NULL; 32 uint16_t StructSize; 33 uint8_t Padding; 34 uint8_t Flags; 35 uint8_t DataOff; 36 uint32_t Length; 37 uint64_t Offset; 38 smb2fid_t smb2fid; 39 uint32_t MinCount; 40 uint32_t Channel; 41 uint32_t Remaining; 42 uint16_t ChanInfoOffset; 43 uint16_t ChanInfoLength; 44 uint32_t XferCount; 45 uint32_t status; 46 int rc = 0; 47 boolean_t unbuffered = B_FALSE; 48 int ioflag = 0; 49 50 /* 51 * SMB2 Read request 52 */ 53 rc = smb_mbc_decodef( 54 &sr->smb_data, 55 "wbblqqqlllww", 56 &StructSize, /* w */ 57 &Padding, /* b */ 58 &Flags, /* b */ 59 &Length, /* l */ 60 &Offset, /* q */ 61 &smb2fid.persistent, /* q */ 62 &smb2fid.temporal, /* q */ 63 &MinCount, /* l */ 64 &Channel, /* l */ 65 &Remaining, /* l */ 66 &ChanInfoOffset, /* w */ 67 &ChanInfoLength); /* w */ 68 if (rc) 69 return (SDRC_ERROR); 70 if (StructSize != 49) 71 return (SDRC_ERROR); 72 73 /* 74 * Setup an smb_rw_param_t which contains the VDB we need. 75 * This is automatically free'd. 76 */ 77 param = smb_srm_zalloc(sr, sizeof (*param)); 78 param->rw_offset = Offset; 79 param->rw_count = Length; 80 /* Note that the dtrace provider uses sr->arg.rw */ 81 sr->arg.rw = param; 82 83 /* 84 * Want FID lookup before the start probe. 85 */ 86 status = smb2sr_lookup_fid(sr, &smb2fid); 87 of = sr->fid_ofile; 88 89 DTRACE_SMB2_START(op__Read, smb_request_t *, sr); /* arg.rw */ 90 91 if (status) 92 goto errout; /* Bad FID */ 93 94 if (Length > smb2_max_rwsize) { 95 status = NT_STATUS_INVALID_PARAMETER; 96 goto errout; 97 } 98 if (MinCount > Length) 99 MinCount = Length; 100 101 vdb = ¶m->rw_vdb; 102 vdb->vdb_tag = 0; 103 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 104 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 105 vdb->vdb_uio.uio_resid = Length; 106 vdb->vdb_uio.uio_loffset = (offset_t)Offset; 107 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 108 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 109 110 sr->raw_data.max_bytes = Length; 111 m = smb_mbuf_allocate(&vdb->vdb_uio); 112 113 /* 114 * Unbuffered refers to the MS-FSA Read argument by the same name. 115 * It indicates that the cache for this range should be flushed to disk, 116 * and data read directly from disk, bypassing the cache. 117 * We don't allow that degree of cache management. 118 * Translate this directly as FRSYNC, 119 * which should at least flush the cache first. 120 */ 121 122 if (smb_allow_unbuffered && 123 (Flags & SMB2_READFLAG_READ_UNBUFFERED) != 0) { 124 unbuffered = B_TRUE; 125 ioflag = FRSYNC; 126 } 127 128 switch (of->f_tree->t_res_type & STYPE_MASK) { 129 case STYPE_DISKTREE: 130 if (!smb_node_is_dir(of->f_node)) { 131 /* Check for conflicting locks. */ 132 rc = smb_lock_range_access(sr, of->f_node, 133 Offset, Length, B_FALSE); 134 if (rc) { 135 rc = ERANGE; 136 break; 137 } 138 } 139 rc = smb_fsop_read(sr, of->f_cr, of->f_node, of, 140 &vdb->vdb_uio, ioflag); 141 break; 142 case STYPE_IPC: 143 if (unbuffered) 144 rc = EINVAL; 145 else 146 rc = smb_opipe_read(sr, &vdb->vdb_uio); 147 break; 148 default: 149 case STYPE_PRINTQ: 150 rc = EACCES; 151 break; 152 } 153 status = smb_errno2status(rc); 154 155 /* How much data we moved. */ 156 XferCount = Length - vdb->vdb_uio.uio_resid; 157 158 sr->raw_data.max_bytes = XferCount; 159 smb_mbuf_trim(m, XferCount); 160 MBC_ATTACH_MBUF(&sr->raw_data, m); 161 162 /* 163 * Checking the error return _after_ dealing with 164 * the returned data so that if m was allocated, 165 * it will be free'd via sr->raw_data cleanup. 166 */ 167 errout: 168 sr->smb2_status = status; 169 DTRACE_SMB2_DONE(op__Read, smb_request_t *, sr); /* arg.rw */ 170 if (status) { 171 smb2sr_put_error(sr, status); 172 return (SDRC_SUCCESS); 173 } 174 175 /* 176 * SMB2 Read reply 177 */ 178 DataOff = SMB2_HDR_SIZE + 16; 179 rc = smb_mbc_encodef( 180 &sr->reply, 181 "wb.lllC", 182 17, /* StructSize */ /* w */ 183 DataOff, /* b. */ 184 XferCount, /* l */ 185 0, /* DataRemaining */ /* l */ 186 0, /* reserved */ /* l */ 187 &sr->raw_data); /* C */ 188 if (rc) { 189 sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 190 return (SDRC_ERROR); 191 } 192 193 mutex_enter(&of->f_mutex); 194 of->f_seek_pos = Offset + XferCount; 195 mutex_exit(&of->f_mutex); 196 197 return (SDRC_SUCCESS); 198 } 199