5899 panic on bad mutex in smb_event_wait()
[unleashed.git] / usr / src / uts / common / fs / smbsrv / smb_write_raw.c
blob0f3506674ea38799a064514a458c4f04bedc7982
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
26 * SMB: write_raw
27 * 5.27 WRITE_RAW: Write Raw Bytes
29 * The Write Block Raw protocol is used to maximize the performance of
30 * writing a large block of data from the client to the server. The Write
31 * Block Raw command's scope includes files, Named Pipes, and spooled
32 * output (can be used in place COM_WRITE_PRINT_FILE ).
34 * Client Request Description
35 * ========================== =========================================
37 * UCHAR WordCount; Count of parameter words = 12
38 * USHORT Fid; File handle
39 * USHORT Count; Total bytes, including this buffer
40 * USHORT Reserved;
41 * ULONG Offset; Offset in file to begin write
42 * ULONG Timeout;
43 * USHORT WriteMode; Write mode:
44 * bit 0 - complete write to disk and send
45 * final result response
46 * bit 1 - return Remaining (pipe/dev)
47 * (see WriteAndX for #defines)
48 * ULONG Reserved2;
49 * USHORT DataLength; Number of data bytes this buffer
50 * USHORT DataOffset; Offset (from header start) to data
51 * USHORT ByteCount; Count of data bytes
52 * UCHAR Pad[]; Pad to SHORT or LONG
53 * UCHAR Data[]; Data (# = DataLength)
55 * First Server Response Description
56 * ============================== =====================================
58 * UCHAR WordCount; Count of parameter words = 1
59 * USHORT Remaining; Bytes remaining to be read if pipe
60 * USHORT ByteCount; Count of data bytes = 0
62 * Final Server Response Description
63 * ================================== =================================
65 * UCHAR Command (in SMB header) SMB_COM_WRITE_COMPLETE
67 * UCHAR WordCount; Count of parameter words = 1
68 * USHORT Count; Total number of bytes written
69 * USHORT ByteCount; Count of data bytes = 0
71 * The first response format will be that of the final server response in
72 * the case where the server gets an error while writing the data sent
73 * along with the request. Thus Count is the number of bytes which did get
74 * written any time an error is returned. If an error occurs after the
75 * first response has been sent allowing the client to send the remaining
76 * data, the final response should not be sent unless write through is set.
77 * Rather the server should return this "write behind" error on the next
78 * access to the Fid.
80 * The client must guarantee that there is (and will be) no other request
81 * on the connection for the duration of this request. The server will
82 * reserve enough resources to receive the data and respond with a response
83 * SMB as defined above. The client then sends the raw data in one send.
84 * Thus the server is able to receive up to 65,535 bytes of data directly
85 * into the server buffer. The amount of data transferred is expected to
86 * be larger than the negotiated buffer size for this protocol.
88 * The reason that no other requests can be active on the connection for
89 * the duration of the request is that if other receives are present on the
90 * connection, there is normally no way to guarantee that the data will be
91 * received into the correct server buffer, rather the data may fill one
92 * (or more) of the other buffers. Also if the client is sending other
93 * requests on the connection, a request may land in the buffer that the
94 * server has allocated for the this SMB's data.
96 * Whether or not SMB_COM_WRITE_RAW is supported is returned in the
97 * response to SMB_COM_NEGOTIATE. SMB_COM_WRITE_RAW is not supported for
98 * connectionless clients.
100 * When write through is not specified ((WriteMode & 01) == 0) this SMB is
101 * assumed to be a form of write behind. The transport layer guarantees
102 * delivery of all secondary requests from the client. Thus no "got the
103 * data you sent" SMB is needed. If an error should occur at the server
104 * end, all bytes must be received and thrown away. If an error occurs
105 * while writing data to disk such as disk full, the next access of the
106 * file handle (another write, close, read, etc.) will return the fact that
107 * the error occurred.
109 * If write through is specified ((WriteMode & 01) != 0), the server will
110 * receive the data, write it to disk and then send a final response
111 * indicating the result of the write. The total number of bytes written
112 * is also returned in this response in the Count field.
114 * The flow for the SMB_COM_WRITE_RAW SMB is:
116 * client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
117 * client <------------------< OK send (more) data <---------------- server
118 * client ----------------------> raw data >----------------------> server
119 * client <---< data on disk or error (write through only) <------- server
121 * This protocol is set up such that the SMB_COM_WRITE_RAW request may also
122 * carry data. This is an optimization in that up to the server's buffer
123 * size (MaxCount from SMB_COM_NEGOTIATE response), minus the size of the
124 * SMB_COM_WRITE_RAW SMB request, may be sent along with the request. Thus
125 * if the server is busy and unable to support the raw write of the
126 * remaining data, the data sent along with the request has been delivered
127 * and need not be sent again. The server will write any data sent in the
128 * request (and wait for it to be on the disk or device if write through is
129 * set), prior to sending the response.
131 * The specific responses error class ERRSRV, error codes ERRusempx and
132 * ERRusestd, indicate that the server is temporarily out of the resources
134 * needed to support the raw write of the remaining data, but that any data
135 * sent along with the request has been successfully written. The client
136 * should then write the remaining data using a different type of SMB write
137 * request, or delay and retry using SMB_COM_WRITE_RAW. If a write error
138 * occurs writing the initial data, it will be returned and the write raw
139 * request is implicitly denied.
141 * The return field Remaining is returned for named pipes only. It is used
142 * to return the number of bytes currently available in the pipe. This
143 * information can then be used by the client to know when a subsequent
144 * (non blocking) read of the pipe may return some data. Of course when
145 * the read request is actually received by the server there may be more or
146 * less actual data in the pipe (more data has been written to the pipe /
147 * device or another reader drained it). If the information is currently
148 * not available or the request is NOT for a pipe or the server does not
149 * support this feature, a -1 value should be returned.
151 * If the negotiated dialect is NT LM 0.12 or later, and the response to
152 * the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the Capabilities
153 * field, an additional request format is allowed which accommodates very
154 * large files having 64 bit offsets:
156 * Client Request Description
157 * ================================== =================================
158 * UCHAR WordCount; Count of parameter words = 14
159 * USHORT Fid; File handle
160 * USHORT Count; Total bytes, including this
161 * buffer
162 * USHORT Reserved;
163 * ULONG Offset; Offset in file to begin write
164 * ULONG Timeout;
165 * USHORT WriteMode; Write mode:
166 * bit 0 - complete write to disk
167 * and send final result response
168 * bit 1 - return Remaining
169 * (pipe/dev)
170 * ULONG Reserved2;
171 * USHORT DataLength; Number of data bytes this buffer
172 * USHORT DataOffset; Offset (from header start) to
173 * data
174 * ULONG OffsetHigh; Upper 32 bits of offset
175 * USHORT ByteCount; Count of data bytes
176 * UCHAR Pad[]; Pad to SHORT or LONG
177 * UCHAR Data[]; Data (# = DataLength)
179 * In this case the final offset in the file is formed by combining
180 * OffsetHigh and Offset, the resulting offset must not be negative.
183 #include <sys/sdt.h>
184 #include <smbsrv/smb_kproto.h>
185 #include <smbsrv/smb_fsops.h>
186 #include <smbsrv/netbios.h>
188 extern uint32_t smb_keep_alive;
190 static int smb_transfer_write_raw_data(smb_request_t *, smb_rw_param_t *);
192 smb_sdrc_t
193 smb_pre_write_raw(smb_request_t *sr)
195 smb_rw_param_t *param;
196 uint32_t off_low;
197 uint32_t timeout;
198 uint32_t off_high;
199 uint16_t datalen;
200 uint16_t total;
201 int rc;
203 param = smb_srm_zalloc(sr, sizeof (smb_rw_param_t));
204 sr->arg.rw = param;
205 param->rw_magic = SMB_RW_MAGIC;
207 if (sr->smb_wct == 12) {
208 rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &total,
209 &off_low, &timeout, &param->rw_mode, &datalen,
210 &param->rw_dsoff);
212 param->rw_offset = (uint64_t)off_low;
213 param->rw_dsoff -= 59;
214 } else {
215 rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &total,
216 &off_low, &timeout, &param->rw_mode, &datalen,
217 &param->rw_dsoff, &off_high);
219 param->rw_offset = ((uint64_t)off_high << 32) | off_low;
220 param->rw_dsoff -= 63;
223 param->rw_count = (uint32_t)datalen;
224 param->rw_total = (uint32_t)total;
225 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
227 DTRACE_SMB_2(op__WriteRaw__start, smb_request_t *, sr,
228 smb_rw_param_t *, sr->arg.rw);
230 smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
232 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
235 void
236 smb_post_write_raw(smb_request_t *sr)
238 DTRACE_SMB_2(op__WriteRaw__done, smb_request_t *, sr,
239 smb_rw_param_t *, sr->arg.rw);
241 smb_rwx_rwexit(&sr->session->s_lock);
244 smb_sdrc_t
245 smb_com_write_raw(struct smb_request *sr)
247 smb_rw_param_t *param = sr->arg.rw;
248 int rc = 0;
249 int session_send_rc = 0;
250 uint16_t addl_xfer_count;
251 offset_t addl_xfer_offset;
252 struct mbuf_chain reply;
253 smb_error_t err;
255 if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE)
256 return (SDRC_DROP_VC);
258 if (!smb_raw_mode) {
259 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
260 ERROR_NOT_SUPPORTED);
261 return (SDRC_ERROR);
264 smbsr_lookup_file(sr);
265 if (sr->fid_ofile == NULL) {
266 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
267 return (SDRC_ERROR);
270 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
273 * Send response if there is additional data to transfer.
274 * This will prompt the client to send the remaining data.
276 addl_xfer_count = param->rw_total - param->rw_count;
277 addl_xfer_offset = param->rw_count;
279 if (addl_xfer_count != 0) {
280 MBC_INIT(&reply, MLEN);
281 (void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT "bww",
282 sr->first_smb_com,
283 sr->smb_rcls,
284 sr->smb_reh,
285 sr->smb_err,
286 sr->smb_flg | SMB_FLAGS_REPLY,
287 sr->smb_flg2,
288 sr->smb_pid_high,
289 sr->smb_sig,
290 sr->smb_tid,
291 sr->smb_pid,
292 sr->smb_uid,
293 sr->smb_mid, 1, -1, 0);
295 if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
296 smb_sign_reply(sr, &reply);
298 session_send_rc = smb_session_send(sr->session, 0, &reply);
301 * If the response failed, force write-through and
302 * complete the write before dealing with the error.
304 if (session_send_rc != 0)
305 param->rw_mode = SMB_WRMODE_WRITE_THRU;
309 * While the response is in flight (and the data begins to arrive)
310 * write out the first data segment.
312 if (smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
313 &param->rw_vdb) != 0)
314 return (SDRC_ERROR);
316 if (param->rw_count > 0)
317 rc = smb_common_write(sr, param);
319 if (session_send_rc != 0) {
320 sr->smb_rcls = ERRSRV;
321 sr->smb_err = ERRusestd;
322 goto write_raw_transfer_failed;
326 * If we have more data to read then go get it
328 if (addl_xfer_count > 0) {
330 * This is the only place where a worker thread should
331 * directly read from the session socket. If the data
332 * is read successfully then the buffer (sr->sr_raw_data_buf)
333 * will need to be freed after the data is written.
335 param->rw_offset += addl_xfer_offset;
336 param->rw_vdb.vdb_uio.uio_loffset = param->rw_offset;
337 param->rw_vdb.vdb_iovec[0].iov_len = addl_xfer_count;
338 param->rw_vdb.vdb_uio.uio_resid = addl_xfer_count;
339 if (smb_transfer_write_raw_data(sr, param) != 0)
340 goto write_raw_transfer_failed;
344 * Wake up session daemon since we now have all of our data and
345 * it's safe for the session daemon to resume processing SMB's.
347 sr->session->s_write_raw_status = 0;
348 sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
351 * If we didn't write all the data from the first segment then
352 * there's not much point in continuing (we still wanted to
353 * read any additional data above since we don't necessarily
354 * want to drop the connection and we need to read through
355 * to the next SMB).
357 if (rc != 0)
358 goto notify_write_raw_complete;
361 * Write any additional data
363 if (addl_xfer_count > 0) {
364 rc = smb_common_write(sr, param);
365 addl_xfer_offset += param->rw_count;
369 * If we were called in "Write-behind" mode and the transfer was
370 * successful then we don't need to send any further response.
371 * If we were called in "Write-Through" mode or if the transfer
372 * failed we need to send a completion notification. The "count"
373 * value will indicate whether the transfer was successful.
375 if ((rc != 0) || SMB_WRMODE_IS_STABLE(param->rw_mode))
376 goto notify_write_raw_complete;
378 (void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
379 return (SDRC_NO_REPLY);
381 write_raw_transfer_failed:
383 * Raw data transfer failed, wake up session daemon
385 sr->session->s_write_raw_status = 20;
386 sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
388 notify_write_raw_complete:
390 * If we had an error fill in the appropriate error code
392 if (rc != 0) {
393 smbsr_map_errno(rc, &err);
394 smbsr_set_error(sr, &err);
397 sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
398 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, addl_xfer_offset, 0);
399 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
403 * smb_handle_write_raw
405 * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
406 * Dispatches the command to the worker thread and waits until the worker
407 * has completed processing the command.
409 * Returns 0 for success, non-zero for failure
412 smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
414 int drop_reason = 0;
417 * Set flag to indicate that we are waiting for raw data. The
418 * worker thread will actually retrieve the raw data directly
419 * from the socket. This should be the only case when a worker
420 * thread reads from the session socket. When the data is read
421 * the worker will clear the flag.
423 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
424 switch (session->s_state) {
425 case SMB_SESSION_STATE_NEGOTIATED:
426 case SMB_SESSION_STATE_OPLOCK_BREAKING:
427 session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
428 smb_rwx_rwexit(&session->s_lock);
429 smb_srqueue_waitq_enter(session->s_srqueue);
430 sr->sr_state = SMB_REQ_STATE_SUBMITTED;
431 (void) taskq_dispatch(session->s_server->sv_worker_pool,
432 smb_session_worker, sr, TQ_SLEEP);
433 smb_rwx_rwenter(&session->s_lock, RW_READER);
434 while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
435 (void) smb_rwx_rwwait(&session->s_lock, -1);
437 drop_reason = session->s_write_raw_status;
438 break;
439 default:
440 drop_reason = 21;
441 break;
443 smb_rwx_rwexit(&session->s_lock);
444 return (drop_reason);
448 * smb_transfer_write_raw_data
450 * Handles the second transfer phase of SMB_COM_WRITE_RAW. smb_com_write_raw()
451 * will process the parameters and data from the SMB and send the initial
452 * SMB response. This function reads the remaining data from the socket
453 * as it arrives from the client.
455 * Clients may send KEEP_ALIVE messages (when using NBT) between the first
456 * and second parts of write raw requests. The only session transport
457 * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
459 * Returns 0 for success, non-zero for failure
462 smb_transfer_write_raw_data(smb_request_t *sr, smb_rw_param_t *param)
464 smb_session_t *session = sr->session;
465 smb_xprt_t hdr;
466 void *pbuf;
468 do {
469 if (smb_session_xprt_gethdr(session, &hdr) != 0)
470 return (-1);
472 if ((hdr.xh_type == SESSION_MESSAGE) ||
473 (hdr.xh_type == SESSION_KEEP_ALIVE)) {
474 session->keep_alive = smb_keep_alive;
475 } else {
476 return (-1);
478 } while (hdr.xh_type == SESSION_KEEP_ALIVE);
480 if (hdr.xh_length < param->rw_vdb.vdb_uio.uio_resid)
481 return (-1); /* Less data than we were expecting. */
483 pbuf = smb_srm_alloc(sr, hdr.xh_length);
484 if (smb_sorecv(session->sock, pbuf, hdr.xh_length) != 0)
485 return (-1);
487 param->rw_vdb.vdb_iovec[0].iov_base = pbuf;
488 param->rw_vdb.vdb_uio.uio_iovcnt = 1;
489 param->rw_vdb.vdb_uio.uio_segflg = UIO_SYSSPACE;
490 param->rw_vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
491 return (0);