1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/ioctl.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <netdb.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include "ndmpd_common.h"
56 #include "ndmpd.h"
57 #include <sys/mtio.h>
58
59 /*
60 * Maximum mover record size
61 */
62 #define MAX_MOVER_RECSIZE (512*KILOBYTE)
63
64 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
65 ushort_t *port);
66 static int tape_read(ndmpd_session_t *session, char *data);
67 static int change_tape(ndmpd_session_t *session);
68 static int discard_data(ndmpd_session_t *session, ulong_t length);
69 static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
70 static int mover_socket_write_one_buf(ndmpd_session_t *session,
71 tlm_buffer_t *buf);
72 static int start_mover_for_restore(ndmpd_session_t *session);
73 static int mover_socket_read_one_buf(ndmpd_session_t *session,
74 tlm_buffer_t *buf, long read_size);
75 static int mover_tape_write_one_buf(ndmpd_session_t *session,
76 tlm_buffer_t *buf);
77 static int start_mover_for_backup(ndmpd_session_t *session);
78 static boolean_t is_writer_running_v3(ndmpd_session_t *session);
79 static int mover_pause_v3(ndmpd_session_t *session,
80 ndmp_mover_pause_reason reason);
81 static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
82 ssize_t length);
83 static int mover_tape_flush_v3(ndmpd_session_t *session);
84 static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
85 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
86 ushort_t *port);
87 static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
88 static void accept_connection(void *cookie, int fd, ulong_t mode);
89 static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
90 static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
91 static ndmp_error mover_connect_sock(ndmpd_session_t *session,
92 ndmp_mover_mode mode, ulong_t addr, ushort_t port);
93 static boolean_t is_writer_running(ndmpd_session_t *session);
94 static int set_socket_nonblock(int sock);
95
96
97 int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
98
99 #define TAPE_READ_ERR -1
100 #define TAPE_NO_WRITER_ERR -2
101
102 /*
103 * Set non-blocking mode for socket.
104 */
105 static int
set_socket_nonblock(int sock)106 set_socket_nonblock(int sock)
107 {
108 int flags;
109
110 flags = fcntl(sock, F_GETFL, 0);
111 if (flags < 0)
112 return (0);
113 return (fcntl(sock, F_SETFL, flags|O_NONBLOCK) == 0);
114 }
115
116 /*
117 * ************************************************************************
118 * NDMP V2 HANDLERS
119 * ************************************************************************
120 */
121
122 /*
123 * ndmpd_mover_get_state_v2
124 *
125 * This handler handles the mover_get_state request.
126 * Status information for the mover state machine is returned.
127 *
128 * Parameters:
129 * connection (input) - connection handle.
130 * body (input) - request message body.
131 *
132 * Returns:
133 * void
134 */
135 /*ARGSUSED*/
136 void
ndmpd_mover_get_state_v2(ndmp_connection_t * connection,void * body)137 ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
138 {
139 ndmp_mover_get_state_reply_v2 reply;
140 ndmpd_session_t *session = ndmp_get_client_data(connection);
141
142 reply.error = NDMP_NO_ERR;
143 reply.state = session->ns_mover.md_state;
144 reply.pause_reason = session->ns_mover.md_pause_reason;
145 reply.halt_reason = session->ns_mover.md_halt_reason;
146 reply.record_size = session->ns_mover.md_record_size;
147 reply.record_num = session->ns_mover.md_record_num;
148 reply.data_written =
149 long_long_to_quad(session->ns_mover.md_data_written);
150 reply.seek_position =
151 long_long_to_quad(session->ns_mover.md_seek_position);
152 reply.bytes_left_to_read =
153 long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
154 reply.window_offset =
155 long_long_to_quad(session->ns_mover.md_window_offset);
156 reply.window_length =
157 long_long_to_quad(session->ns_mover.md_window_length);
158
159 ndmp_send_reply(connection, (void *) &reply,
160 "sending tape_get_state reply");
161 }
162
163
164 /*
165 * ndmpd_mover_listen_v2
166 *
167 * This handler handles mover_listen requests.
168 *
169 * Parameters:
170 * connection (input) - connection handle.
171 * body (input) - request message body.
172 *
173 * Returns:
174 * void
175 */
176 void
ndmpd_mover_listen_v2(ndmp_connection_t * connection,void * body)177 ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
178 {
179 ndmp_mover_listen_request_v2 *request;
180 ndmp_mover_listen_reply_v2 reply;
181 ndmpd_session_t *session = ndmp_get_client_data(connection);
182 ulong_t addr;
183 ushort_t port;
184
185 request = (ndmp_mover_listen_request_v2 *)body;
186
187 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
188 session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
189 NDMP_LOG(LOG_DEBUG, "Invalid state");
190 reply.error = NDMP_ILLEGAL_STATE_ERR;
191 ndmp_send_reply(connection, (void *) &reply,
192 "sending mover_listen reply");
193 return;
194 }
195 session->ns_mover.md_mode = request->mode;
196
197 if (request->addr_type == NDMP_ADDR_LOCAL) {
198 reply.mover.addr_type = NDMP_ADDR_LOCAL;
199 } else {
200 if (create_listen_socket_v2(session, &addr, &port) < 0) {
201 reply.error = NDMP_IO_ERR;
202 ndmp_send_reply(connection, (void *) &reply,
203 "sending mover_listen reply");
204 return;
205 }
206 reply.mover.addr_type = NDMP_ADDR_TCP;
207 reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
208 reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
209 }
210
211 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
212
213 /*
214 * ndmp window should always set by client during restore
215 */
216
217 /* Set the default window. */
218 session->ns_mover.md_window_offset = 0;
219 session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
220 session->ns_mover.md_position = 0;
221
222 reply.error = NDMP_NO_ERR;
223 ndmp_send_reply(connection, (void *) &reply,
224 "sending mover_listen reply");
225 }
226
227
228 /*
229 * ndmpd_mover_continue_v2
230 *
231 * This handler handles mover_continue requests.
232 *
233 * Parameters:
234 * connection (input) - connection handle.
235 * body (input) - request message body.
236 *
237 * Returns:
238 * void
239 */
240 /*ARGSUSED*/
241 void
ndmpd_mover_continue_v2(ndmp_connection_t * connection,void * body)242 ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
243 {
244 ndmp_mover_continue_reply reply;
245 ndmpd_session_t *session = ndmp_get_client_data(connection);
246
247 if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
248 NDMP_LOG(LOG_DEBUG, "Invalid state");
249
250 reply.error = NDMP_ILLEGAL_STATE_ERR;
251 ndmp_send_reply(connection, (void *) &reply,
252 "sending mover_continue reply");
253 return;
254 }
255 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
256 reply.error = NDMP_NO_ERR;
257 ndmp_send_reply(connection, (void *) &reply,
258 "sending mover_continue reply");
259 }
260
261
262 /*
263 * ndmpd_mover_abort_v2
264 *
265 * This handler handles mover_abort requests.
266 *
267 * Parameters:
268 * connection (input) - connection handle.
269 * body (input) - request message body.
270 *
271 * Returns:
272 * void
273 */
274 /*ARGSUSED*/
275 void
ndmpd_mover_abort_v2(ndmp_connection_t * connection,void * body)276 ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
277 {
278 ndmp_mover_abort_reply reply;
279 ndmpd_session_t *session = ndmp_get_client_data(connection);
280
281 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
282 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
283 NDMP_LOG(LOG_DEBUG, "Invalid state");
284
285 reply.error = NDMP_ILLEGAL_STATE_ERR;
286 ndmp_send_reply(connection, (void *) &reply,
287 "sending mover_abort reply");
288 return;
289 }
290
291 reply.error = NDMP_NO_ERR;
292 ndmp_send_reply(connection, (void *) &reply,
293 "sending mover_abort reply");
294
295 ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
296 ndmp_stop_buffer_worker(session);
297 }
298
299
300 /*
301 * ndmpd_mover_stop_v2
302 *
303 * This handler handles mover_stop requests.
304 *
305 * Parameters:
306 * connection (input) - connection handle.
307 * body (input) - request message body.
308 *
309 * Returns:
310 * void
311 */
312 /*ARGSUSED*/
313 void
ndmpd_mover_stop_v2(ndmp_connection_t * connection,void * body)314 ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
315 {
316 ndmp_mover_stop_reply reply;
317 ndmpd_session_t *session = ndmp_get_client_data(connection);
318
319 if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
320 NDMP_LOG(LOG_DEBUG, "Invalid state");
321
322 reply.error = NDMP_ILLEGAL_STATE_ERR;
323 ndmp_send_reply(connection, (void *) &reply,
324 "sending mover_stop reply");
325 return;
326 }
327
328 ndmp_waitfor_op(session);
329 reply.error = NDMP_NO_ERR;
330 ndmp_send_reply(connection, (void *) &reply,
331 "sending mover_stop reply");
332
333 ndmp_lbr_cleanup(session);
334 ndmpd_mover_cleanup(session);
335 (void) ndmpd_mover_init(session);
336 (void) ndmp_lbr_init(session);
337 }
338
339
340 /*
341 * ndmpd_mover_set_window_v2
342 *
343 * This handler handles mover_set_window requests.
344 *
345 *
346 * Parameters:
347 * connection (input) - connection handle.
348 * body (input) - request message body.
349 *
350 * Returns:
351 * void
352 */
353 void
ndmpd_mover_set_window_v2(ndmp_connection_t * connection,void * body)354 ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
355 {
356 ndmp_mover_set_window_request *request;
357 ndmp_mover_set_window_reply reply;
358 ndmpd_session_t *session = ndmp_get_client_data(connection);
359
360 request = (ndmp_mover_set_window_request *) body;
361
362 /*
363 * The NDMPv2 specification states that "a window can be set only
364 * when in the listen or paused state."
365 *
366 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
367 * allowing it in the idle state as well.
368 */
369 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
370 session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
371 session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
372 reply.error = NDMP_ILLEGAL_STATE_ERR;
373 NDMP_LOG(LOG_DEBUG, "Invalid state %d",
374 session->ns_mover.md_state);
375 } else {
376 if (quad_to_long_long(request->length) == 0) {
377 reply.error = NDMP_ILLEGAL_ARGS_ERR;
378 NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
379 quad_to_long_long(request->length));
380 } else {
381 reply.error = NDMP_NO_ERR;
382 session->ns_mover.md_window_offset =
383 quad_to_long_long(request->offset);
384 session->ns_mover.md_window_length =
385 quad_to_long_long(request->length);
386 session->ns_mover.md_position =
387 session->ns_mover.md_window_offset;
388 }
389 }
390
391 ndmp_send_reply(connection, (void *) &reply,
392 "sending mover_set_window reply");
393 }
394
395
396 /*
397 * ndmpd_mover_read_v2
398 *
399 * This handler handles mover_read requests. If the requested offset is
400 * outside of the current window, the mover is paused and a notify_mover_paused
401 * request is sent notifying the client that a seek is required. If the
402 * requested offest is within the window but not within the current record,
403 * then the tape is positioned to the record containing the requested offest.
404 * The requested amount of data is then read from the tape device and written
405 * to the data connection.
406 *
407 * Parameters:
408 * connection (input) - connection handle.
409 * body (input) - request message body.
410 *
411 * Returns:
412 * void
413 */
414 void
ndmpd_mover_read_v2(ndmp_connection_t * connection,void * body)415 ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
416 {
417 ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
418 ndmp_mover_read_reply reply;
419 ndmpd_session_t *session = ndmp_get_client_data(connection);
420 int err;
421
422 if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
423 session->ns_mover.md_bytes_left_to_read != 0 ||
424 session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
425 NDMP_LOG(LOG_DEBUG, "Invalid state");
426 reply.error = NDMP_ILLEGAL_STATE_ERR;
427 ndmp_send_reply(connection, &reply,
428 "sending mover_read reply");
429 return;
430 }
431 if (session->ns_tape.td_fd == -1) {
432 NDMP_LOG(LOG_DEBUG, "Tape device is not open");
433 reply.error = NDMP_DEV_NOT_OPEN_ERR;
434 ndmp_send_reply(connection, &reply,
435 "sending mover_read reply");
436 return;
437 }
438
439 reply.error = NDMP_NO_ERR;
440 ndmp_send_reply(connection, &reply, "sending mover_read reply");
441
442 err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
443 quad_to_long_long(request->length));
444 if (err < 0) {
445 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
446 return;
447 }
448 /*
449 * Just return if we are waiting for the NDMP client to
450 * complete the seek.
451 */
452 if (err == 1)
453 return;
454
455 /*
456 * Start the mover for restore in the 3-way backups.
457 */
458 if (start_mover_for_restore(session) < 0)
459 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
460 }
461
462
463 /*
464 * ndmpd_mover_close_v2
465 *
466 * This handler handles mover_close requests.
467 *
468 * Parameters:
469 * connection (input) - connection handle.
470 * body (input) - request message body.
471 *
472 * Returns:
473 * void
474 */
475 /*ARGSUSED*/
476 void
ndmpd_mover_close_v2(ndmp_connection_t * connection,void * body)477 ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
478 {
479 ndmp_mover_close_reply reply;
480 ndmpd_session_t *session = ndmp_get_client_data(connection);
481
482 if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
483 NDMP_LOG(LOG_DEBUG, "Invalid state");
484
485 reply.error = NDMP_ILLEGAL_STATE_ERR;
486 ndmp_send_reply(connection, &reply,
487 "sending mover_close reply");
488 return;
489 }
490 free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
491
492 reply.error = NDMP_NO_ERR;
493 ndmp_send_reply(connection, &reply, "sending mover_close reply");
494
495 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
496 }
497
498
499 /*
500 * ndmpd_mover_set_record_size_v2
501 *
502 * This handler handles mover_set_record_size requests.
503 *
504 * Parameters:
505 * connection (input) - connection handle.
506 * body (input) - request message body.
507 *
508 * Returns:
509 * void
510 */
511 void
ndmpd_mover_set_record_size_v2(ndmp_connection_t * connection,void * body)512 ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
513 {
514 ndmp_mover_set_record_size_request *request;
515 ndmp_mover_set_record_size_reply reply;
516 ndmpd_session_t *session = ndmp_get_client_data(connection);
517
518 request = (ndmp_mover_set_record_size_request *) body;
519
520 session->ns_mover.md_record_size = request->len;
521 session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
522 request->len);
523
524 reply.error = NDMP_NO_ERR;
525 ndmp_send_reply(connection, &reply,
526 "sending mover_set_record_size reply");
527 }
528
529
530 /*
531 * ************************************************************************
532 * NDMP V3 HANDLERS
533 * ************************************************************************
534 */
535
536 /*
537 * ndmpd_mover_get_state_v3
538 *
539 * This handler handles the ndmp_mover_get_state_request.
540 * Status information for the mover state machine is returned.
541 *
542 * Parameters:
543 * connection (input) - connection handle.
544 * body (input) - request message body.
545 *
546 * Returns:
547 * void
548 */
549 /*ARGSUSED*/
550 void
ndmpd_mover_get_state_v3(ndmp_connection_t * connection,void * body)551 ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
552 {
553 ndmp_mover_get_state_reply_v3 reply;
554 ndmpd_session_t *session = ndmp_get_client_data(connection);
555
556 (void) memset((void*)&reply, 0, sizeof (reply));
557
558 reply.error = NDMP_NO_ERR;
559 reply.state = session->ns_mover.md_state;
560 reply.pause_reason = session->ns_mover.md_pause_reason;
561 reply.halt_reason = session->ns_mover.md_halt_reason;
562 reply.record_size = session->ns_mover.md_record_size;
563 reply.record_num = session->ns_mover.md_record_num;
564 reply.data_written =
565 long_long_to_quad(session->ns_mover.md_data_written);
566 reply.seek_position =
567 long_long_to_quad(session->ns_mover.md_seek_position);
568 reply.bytes_left_to_read =
569 long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
570 reply.window_offset =
571 long_long_to_quad(session->ns_mover.md_window_offset);
572 reply.window_length =
573 long_long_to_quad(session->ns_mover.md_window_length);
574 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
575 ndmp_copy_addr_v3(&reply.data_connection_addr,
576 &session->ns_mover.md_data_addr);
577
578 ndmp_send_reply(connection, &reply,
579 "sending ndmp_mover_get_state reply");
580 }
581
582
583 /*
584 * ndmpd_mover_listen_v3
585 *
586 * This handler handles ndmp_mover_listen_requests.
587 * A TCP/IP socket is created that is used to listen for
588 * and accept data connections initiated by a remote
589 * data server.
590 *
591 * Parameters:
592 * connection (input) - connection handle.
593 * body (input) - request message body.
594 *
595 * Returns:
596 * void
597 */
598 void
ndmpd_mover_listen_v3(ndmp_connection_t * connection,void * body)599 ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
600 {
601 ndmp_mover_listen_request_v3 *request;
602 ndmp_mover_listen_reply_v3 reply;
603 ndmpd_session_t *session = ndmp_get_client_data(connection);
604 ulong_t addr;
605 ushort_t port;
606
607 request = (ndmp_mover_listen_request_v3 *)body;
608
609 (void) memset((void*)&reply, 0, sizeof (reply));
610 reply.error = NDMP_NO_ERR;
611
612 if (request->mode != NDMP_MOVER_MODE_READ &&
613 request->mode != NDMP_MOVER_MODE_WRITE) {
614 reply.error = NDMP_ILLEGAL_ARGS_ERR;
615 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
616 } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
617 reply.error = NDMP_ILLEGAL_ARGS_ERR;
618 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
619 request->addr_type);
620 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
621 reply.error = NDMP_ILLEGAL_STATE_ERR;
622 NDMP_LOG(LOG_DEBUG,
623 "Invalid mover state to process listen request");
624 } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
625 reply.error = NDMP_ILLEGAL_STATE_ERR;
626 NDMP_LOG(LOG_DEBUG,
627 "Invalid data state to process listen request");
628 } else if (session->ns_tape.td_fd == -1) {
629 reply.error = NDMP_DEV_NOT_OPEN_ERR;
630 NDMP_LOG(LOG_DEBUG, "No tape device open");
631 } else if (request->mode == NDMP_MOVER_MODE_READ &&
632 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
633 reply.error = NDMP_PERMISSION_ERR;
634 NDMP_LOG(LOG_ERR, "Write protected device.");
635 }
636
637 if (reply.error != NDMP_NO_ERR) {
638 ndmp_send_reply(connection, &reply,
639 "error sending ndmp_mover_listen reply");
640 return;
641 }
642
643 switch (request->addr_type) {
644 case NDMP_ADDR_LOCAL:
645 reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
646 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
647 reply.error = NDMP_NO_ERR;
648 break;
649 case NDMP_ADDR_TCP:
650 if (create_listen_socket_v3(session, &addr, &port) < 0) {
651 reply.error = NDMP_IO_ERR;
652 break;
653 }
654 reply.error = NDMP_NO_ERR;
655 reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
656 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
657 reply.data_connection_addr.tcp_port_v3 = htons(port);
658 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
659 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
660 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
661 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
662 session->ns_mover.md_listen_sock);
663 break;
664 default:
665 reply.error = NDMP_ILLEGAL_ARGS_ERR;
666 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
667 request->addr_type);
668 }
669
670 if (reply.error == NDMP_NO_ERR) {
671 session->ns_mover.md_mode = request->mode;
672 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
673 }
674
675 ndmp_send_reply(connection, &reply,
676 "error sending ndmp_mover_listen reply");
677 }
678
679
680 /*
681 * ndmpd_mover_continue_v3
682 *
683 * This handler handles ndmp_mover_continue_requests.
684 *
685 * Parameters:
686 * connection (input) - connection handle.
687 * body (input) - request message body.
688 *
689 * Returns:
690 * void
691 */
692 /*ARGSUSED*/
693 void
ndmpd_mover_continue_v3(ndmp_connection_t * connection,void * body)694 ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
695 {
696 ndmp_mover_continue_reply reply;
697 ndmpd_session_t *session = ndmp_get_client_data(connection);
698 ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
699 int ret;
700
701 (void) memset((void*)&reply, 0, sizeof (reply));
702
703 if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
704 NDMP_LOG(LOG_DEBUG, "Invalid state");
705 reply.error = NDMP_ILLEGAL_STATE_ERR;
706 ndmp_send_reply(connection, (void *) &reply,
707 "sending mover_continue reply");
708 return;
709 }
710
711 if (session->ns_protocol_version == NDMPV4 &&
712 !session->ns_mover.md_pre_cond) {
713 NDMP_LOG(LOG_DEBUG, "Precondition check");
714 reply.error = NDMP_PRECONDITION_ERR;
715 ndmp_send_reply(connection, (void *) &reply,
716 "sending mover_continue reply");
717 return;
718 }
719 /*
720 * Restore the file handler if the mover is remote to the data
721 * server and the handler was removed pending the continuation of a
722 * seek request. The handler is removed in mover_data_write().
723 */
724 if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
725 session->ns_mover.md_sock != -1) {
726 /*
727 * If we are here, it means that we needed DMA interference
728 * for seek. We should be on the right window, so we do not
729 * need the DMA interference anymore.
730 * We do another seek inside the Window to move to the
731 * exact position on the tape.
732 * If the resore is running without DAR the pause reason should
733 * not be seek.
734 */
735 ret = ndmpd_mover_seek(session,
736 session->ns_mover.md_seek_position,
737 session->ns_mover.md_bytes_left_to_read);
738 if (ret < 0) {
739 ndmpd_mover_error(session,
740 NDMP_MOVER_HALT_INTERNAL_ERROR);
741 return;
742 }
743
744 if (!ret) {
745 if (ndmpd_add_file_handler(session, (void*) session,
746 session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
747 HC_MOVER, mover_data_write_v3) < 0)
748 ndmpd_mover_error(session,
749 NDMP_MOVER_HALT_INTERNAL_ERROR);
750 } else {
751 /*
752 * This should not happen because we should be in the
753 * right window. This means that DMA does not follow
754 * the V3 spec.
755 */
756 NDMP_LOG(LOG_DEBUG, "DMA Error.");
757 ndmpd_mover_error(session,
758 NDMP_MOVER_HALT_INTERNAL_ERROR);
759 return;
760 }
761 }
762
763 (void) mutex_lock(&nlp->nlp_mtx);
764 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
765 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
766 /* The tape has been likely exchanged, reset tape block counter */
767 session->ns_tape.td_record_count = 0;
768 (void) cond_broadcast(&nlp->nlp_cv);
769 (void) mutex_unlock(&nlp->nlp_mtx);
770
771 reply.error = NDMP_NO_ERR;
772 ndmp_send_reply(connection, (void *) &reply,
773 "sending mover_continue reply");
774 }
775
776
777 /*
778 * ndmpd_mover_abort_v3
779 *
780 * This handler handles mover_abort requests.
781 *
782 * Parameters:
783 * connection (input) - connection handle.
784 * body (input) - request message body.
785 *
786 * Returns:
787 * void
788 */
789 /*ARGSUSED*/
790 void
ndmpd_mover_abort_v3(ndmp_connection_t * connection,void * body)791 ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
792 {
793 ndmp_mover_abort_reply reply;
794 ndmpd_session_t *session = ndmp_get_client_data(connection);
795
796 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
797 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
798 NDMP_LOG(LOG_DEBUG, "Invalid state");
799
800 reply.error = NDMP_ILLEGAL_STATE_ERR;
801 ndmp_send_reply(connection, (void *) &reply,
802 "sending mover_abort reply");
803 return;
804 }
805
806 reply.error = NDMP_NO_ERR;
807 ndmp_send_reply(connection, (void *) &reply,
808 "sending mover_abort reply");
809
810 ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
811 }
812
813
814 /*
815 * ndmpd_mover_set_window_v3
816 *
817 * This handler handles mover_set_window requests.
818 *
819 *
820 * Parameters:
821 * connection (input) - connection handle.
822 * body (input) - request message body.
823 *
824 * Returns:
825 * void
826 */
827 void
ndmpd_mover_set_window_v3(ndmp_connection_t * connection,void * body)828 ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
829 {
830 ndmp_mover_set_window_request *request;
831 ndmp_mover_set_window_reply reply;
832 ndmpd_session_t *session = ndmp_get_client_data(connection);
833
834 request = (ndmp_mover_set_window_request *) body;
835
836 /*
837 * Note: The spec says that the window can be set only in the listen
838 * and paused states. We let this happen when mover is in the idle
839 * state as well. I can't rememebr which NDMP client (net_backup 4.5
840 * or net_worker 6.1.1) forced us to do this!
841 */
842 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
843 session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
844 session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
845 reply.error = NDMP_ILLEGAL_STATE_ERR;
846 NDMP_LOG(LOG_DEBUG, "Invalid state %d",
847 session->ns_mover.md_state);
848 } else if (session->ns_mover.md_record_size == 0) {
849 if (session->ns_protocol_version == NDMPV4)
850 reply.error = NDMP_PRECONDITION_ERR;
851 else
852 reply.error = NDMP_ILLEGAL_ARGS_ERR;
853 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
854 } else
855 reply.error = NDMP_NO_ERR;
856
857 if (quad_to_long_long(request->length) == 0) {
858 reply.error = NDMP_ILLEGAL_ARGS_ERR;
859 NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
860 quad_to_long_long(request->length));
861 }
862
863 if (reply.error != NDMP_NO_ERR) {
864 ndmp_send_reply(connection, (void *) &reply,
865 "sending mover_set_window_v3 reply");
866 return;
867 }
868
869 session->ns_mover.md_pre_cond = TRUE;
870 session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
871 session->ns_mover.md_window_length = quad_to_long_long(request->length);
872
873 /*
874 * We have to update the position for DAR. DAR needs this
875 * information to position to the right index on tape,
876 * especially when we span the tapes.
877 */
878 #ifdef NO_POSITION_CHANGE
879 /*
880 * Do not change the mover position if we are reading from
881 * the tape. In this way, we can use the position+window_length
882 * to know how much we can write to a tape before pausing with
883 * EOW reason.
884 */
885 if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
886 #endif /* NO_POSITION_CHANGE */
887 session->ns_mover.md_position =
888 session->ns_mover.md_window_offset;
889
890 ndmp_send_reply(connection, (void *) &reply,
891 "sending mover_set_window_v3 reply");
892 }
893
894
895 /*
896 * ndmpd_mover_read_v3
897 *
898 * This handler handles ndmp_mover_read_requests.
899 * If the requested offset is outside of the current window, the mover
900 * is paused and a notify_mover_paused request is sent notifying the
901 * client that a seek is required. If the requested offest is within
902 * the window but not within the current record, then the tape is
903 * positioned to the record containing the requested offest. The requested
904 * amount of data is then read from the tape device and written to the
905 * data connection.
906 *
907 * Parameters:
908 * connection (input) - connection handle.
909 * body (input) - request message body.
910 *
911 * Returns:
912 * void
913 */
914 void
ndmpd_mover_read_v3(ndmp_connection_t * connection,void * body)915 ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
916 {
917 ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
918 ndmp_mover_read_reply reply;
919 ndmpd_session_t *session = ndmp_get_client_data(connection);
920 int err;
921
922 (void) memset((void*)&reply, 0, sizeof (reply));
923
924 if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
925 session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
926 reply.error = NDMP_ILLEGAL_STATE_ERR;
927 NDMP_LOG(LOG_DEBUG, "Invalid state");
928 } else if (session->ns_mover.md_bytes_left_to_read != 0) {
929 reply.error = NDMP_READ_IN_PROGRESS_ERR;
930 NDMP_LOG(LOG_DEBUG, "In progress");
931 } else if (session->ns_tape.td_fd == -1) {
932 reply.error = NDMP_DEV_NOT_OPEN_ERR;
933 NDMP_LOG(LOG_DEBUG, "Tape device is not open");
934 } else if (quad_to_long_long(request->length) == 0 ||
935 (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
936 quad_to_long_long(request->offset) != 0)) {
937 reply.error = NDMP_ILLEGAL_ARGS_ERR;
938 NDMP_LOG(LOG_DEBUG, "Illegal args");
939 } else {
940 reply.error = NDMP_NO_ERR;
941 }
942
943 ndmp_send_reply(connection, (void *) &reply,
944 "sending ndmp_mover_read_reply");
945 if (reply.error != NDMP_NO_ERR)
946 return;
947
948 err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
949 quad_to_long_long(request->length));
950 if (err < 0) {
951 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
952 return;
953 }
954
955 /*
956 * Just return if we are waiting for the DMA to complete the seek.
957 */
958 if (err == 1)
959 return;
960
961 /*
962 * Setup a handler function that will be called when
963 * data can be written to the data connection without blocking.
964 */
965 if (ndmpd_add_file_handler(session, (void*)session,
966 session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
967 mover_data_write_v3) < 0) {
968 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
969 return;
970 }
971 }
972
973
974 /*
975 * ndmpd_mover_set_record_size_v3
976 *
977 * This handler handles mover_set_record_size requests.
978 *
979 * Parameters:
980 * connection (input) - connection handle.
981 * body (input) - request message body.
982 *
983 * Returns:
984 * void
985 */
986 void
ndmpd_mover_set_record_size_v3(ndmp_connection_t * connection,void * body)987 ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
988 {
989 ndmp_mover_set_record_size_request *request;
990 ndmp_mover_set_record_size_reply reply;
991 ndmpd_session_t *session = ndmp_get_client_data(connection);
992 char *cp;
993
994 request = (ndmp_mover_set_record_size_request *) body;
995
996 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
997 reply.error = NDMP_ILLEGAL_STATE_ERR;
998 NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
999 session->ns_mover.md_state);
1000 } else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
1001 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1002 NDMP_LOG(LOG_DEBUG,
1003 "Invalid argument %d, should be > 0 and <= %d",
1004 request->len, ndmp_max_mover_recsize);
1005 } else if (request->len == session->ns_mover.md_record_size)
1006 reply.error = NDMP_NO_ERR;
1007 else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
1008 reply.error = NDMP_NO_MEM_ERR;
1009 } else {
1010 reply.error = NDMP_NO_ERR;
1011 session->ns_mover.md_buf = cp;
1012 session->ns_mover.md_record_size = request->len;
1013 session->ns_mover.md_window_offset = 0;
1014 session->ns_mover.md_window_length = 0;
1015 }
1016
1017 ndmp_send_reply(connection, (void *) &reply,
1018 "sending mover_set_record_size reply");
1019 }
1020
1021
1022 /*
1023 * ndmpd_mover_connect_v3
1024 * Request handler. Connects the mover to either a local
1025 * or remote data server.
1026 *
1027 * Parameters:
1028 * connection (input) - connection handle.
1029 * body (input) - request message body.
1030 *
1031 * Returns:
1032 * void
1033 */
1034 void
ndmpd_mover_connect_v3(ndmp_connection_t * connection,void * body)1035 ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1036 {
1037 ndmp_mover_connect_request_v3 *request;
1038 ndmp_mover_connect_reply_v3 reply;
1039 ndmpd_session_t *session = ndmp_get_client_data(connection);
1040
1041 request = (ndmp_mover_connect_request_v3*)body;
1042
1043 (void) memset((void*)&reply, 0, sizeof (reply));
1044
1045 if (request->mode != NDMP_MOVER_MODE_READ &&
1046 request->mode != NDMP_MOVER_MODE_WRITE) {
1047 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1048 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1049 } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1050 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1051 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1052 request->addr.addr_type);
1053 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1054 reply.error = NDMP_ILLEGAL_STATE_ERR;
1055 NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1056 session->ns_mover.md_state);
1057 } else if (session->ns_tape.td_fd == -1) {
1058 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1059 NDMP_LOG(LOG_DEBUG, "No tape device open");
1060 } else if (request->mode == NDMP_MOVER_MODE_READ &&
1061 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1062 reply.error = NDMP_WRITE_PROTECT_ERR;
1063 NDMP_LOG(LOG_ERR, "Write protected device.");
1064 } else
1065 reply.error = NDMP_NO_ERR;
1066
1067 if (reply.error != NDMP_NO_ERR) {
1068 ndmp_send_reply(connection, (void *) &reply,
1069 "sending ndmp_mover_connect reply");
1070 return;
1071 }
1072
1073 switch (request->addr.addr_type) {
1074 case NDMP_ADDR_LOCAL:
1075 /*
1076 * Verify that the data server is listening for a
1077 * local connection.
1078 */
1079 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1080 session->ns_data.dd_listen_sock != -1) {
1081 NDMP_LOG(LOG_DEBUG,
1082 "Data server is not in local listen state");
1083 reply.error = NDMP_ILLEGAL_STATE_ERR;
1084 } else
1085 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1086 break;
1087
1088 case NDMP_ADDR_TCP:
1089 reply.error = mover_connect_sock(session, request->mode,
1090 request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1091 break;
1092
1093 default:
1094 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1095 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1096 request->addr.addr_type);
1097 }
1098
1099 if (reply.error == NDMP_NO_ERR) {
1100 session->ns_mover.md_data_addr.addr_type =
1101 request->addr.addr_type;
1102 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1103 session->ns_mover.md_mode = request->mode;
1104 }
1105
1106 ndmp_send_reply(connection, (void *) &reply,
1107 "sending ndmp_mover_connect reply");
1108 }
1109
1110
1111 /*
1112 * ************************************************************************
1113 * NDMP V4 HANDLERS
1114 * ************************************************************************
1115 */
1116
1117 /*
1118 * ndmpd_mover_get_state_v4
1119 *
1120 * This handler handles the ndmp_mover_get_state_request.
1121 * Status information for the mover state machine is returned.
1122 *
1123 * Parameters:
1124 * connection (input) - connection handle.
1125 * body (input) - request message body.
1126 *
1127 * Returns:
1128 * void
1129 */
1130 /*ARGSUSED*/
1131 void
ndmpd_mover_get_state_v4(ndmp_connection_t * connection,void * body)1132 ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
1133 {
1134 ndmp_mover_get_state_reply_v4 reply;
1135 ndmpd_session_t *session = ndmp_get_client_data(connection);
1136
1137 (void) memset((void*)&reply, 0, sizeof (reply));
1138
1139 reply.error = NDMP_NO_ERR;
1140 reply.state = session->ns_mover.md_state;
1141 reply.mode = session->ns_mover.md_mode;
1142 reply.pause_reason = session->ns_mover.md_pause_reason;
1143 reply.halt_reason = session->ns_mover.md_halt_reason;
1144 reply.record_size = session->ns_mover.md_record_size;
1145 reply.record_num = session->ns_mover.md_record_num;
1146 reply.bytes_moved =
1147 long_long_to_quad(session->ns_mover.md_data_written);
1148 reply.seek_position =
1149 long_long_to_quad(session->ns_mover.md_seek_position);
1150 reply.bytes_left_to_read =
1151 long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1152 reply.window_offset =
1153 long_long_to_quad(session->ns_mover.md_window_offset);
1154 reply.window_length =
1155 long_long_to_quad(session->ns_mover.md_window_length);
1156 if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
1157 ndmp_copy_addr_v4(&reply.data_connection_addr,
1158 &session->ns_mover.md_data_addr_v4);
1159
1160 ndmp_send_reply(connection, (void *) &reply,
1161 "sending ndmp_mover_get_state reply");
1162 free(reply.data_connection_addr.tcp_addr_v4);
1163 }
1164
1165
1166 /*
1167 * ndmpd_mover_listen_v4
1168 *
1169 * This handler handles ndmp_mover_listen_requests.
1170 * A TCP/IP socket is created that is used to listen for
1171 * and accept data connections initiated by a remote
1172 * data server.
1173 *
1174 * Parameters:
1175 * connection (input) - connection handle.
1176 * body (input) - request message body.
1177 *
1178 * Returns:
1179 * void
1180 */
1181 void
ndmpd_mover_listen_v4(ndmp_connection_t * connection,void * body)1182 ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1183 {
1184 ndmp_mover_listen_request_v4 *request;
1185
1186 ndmp_mover_listen_reply_v4 reply;
1187 ndmpd_session_t *session = ndmp_get_client_data(connection);
1188 ulong_t addr;
1189 ushort_t port;
1190
1191 request = (ndmp_mover_listen_request_v4 *)body;
1192
1193 (void) memset((void*)&reply, 0, sizeof (reply));
1194 reply.error = NDMP_NO_ERR;
1195
1196 if (request->mode != NDMP_MOVER_MODE_READ &&
1197 request->mode != NDMP_MOVER_MODE_WRITE) {
1198 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1199 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1200 } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1201 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1202 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1203 request->addr_type);
1204 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1205 reply.error = NDMP_ILLEGAL_STATE_ERR;
1206 NDMP_LOG(LOG_DEBUG,
1207 "Invalid mover state to process listen request");
1208 } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1209 reply.error = NDMP_ILLEGAL_STATE_ERR;
1210 NDMP_LOG(LOG_DEBUG,
1211 "Invalid data state to process listen request");
1212 } else if (session->ns_tape.td_fd == -1) {
1213 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1214 NDMP_LOG(LOG_DEBUG, "No tape device open");
1215 } else if (session->ns_mover.md_record_size == 0) {
1216 reply.error = NDMP_PRECONDITION_ERR;
1217 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1218 } else if (request->mode == NDMP_MOVER_MODE_READ &&
1219 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1220 reply.error = NDMP_PERMISSION_ERR;
1221 NDMP_LOG(LOG_ERR, "Write protected device.");
1222 }
1223
1224 if (reply.error != NDMP_NO_ERR) {
1225 ndmp_send_reply(connection, (void *) &reply,
1226 "error sending ndmp_mover_listen reply");
1227 return;
1228 }
1229
1230 switch (request->addr_type) {
1231 case NDMP_ADDR_LOCAL:
1232 reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1233 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1234 reply.error = NDMP_NO_ERR;
1235 break;
1236 case NDMP_ADDR_TCP:
1237 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1238 reply.error = NDMP_IO_ERR;
1239 break;
1240 }
1241 reply.error = NDMP_NO_ERR;
1242
1243 session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1244 session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1245 session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1246 ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1247
1248 session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1249 session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1250
1251 ndmp_copy_addr_v4(&reply.connect_addr,
1252 &session->ns_mover.md_data_addr_v4);
1253
1254 /* For compatibility with V3 */
1255 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1256 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1257 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1258 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1259 session->ns_mover.md_listen_sock);
1260 break;
1261 default:
1262 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1263 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1264 request->addr_type);
1265 }
1266
1267 if (reply.error == NDMP_NO_ERR) {
1268 session->ns_mover.md_mode = request->mode;
1269 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1270 }
1271
1272 ndmp_send_reply(connection, (void *) &reply,
1273 "error sending ndmp_mover_listen reply");
1274 free(reply.connect_addr.tcp_addr_v4);
1275 }
1276
1277 /*
1278 * ndmpd_mover_connect_v4
1279 * Request handler. Connects the mover to either a local
1280 * or remote data server.
1281 *
1282 * Parameters:
1283 * connection (input) - connection handle.
1284 * body (input) - request message body.
1285 *
1286 * Returns:
1287 * void
1288 */
1289 void
ndmpd_mover_connect_v4(ndmp_connection_t * connection,void * body)1290 ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1291 {
1292 ndmp_mover_connect_request_v4 *request;
1293 ndmp_mover_connect_reply_v4 reply;
1294 ndmpd_session_t *session = ndmp_get_client_data(connection);
1295
1296 request = (ndmp_mover_connect_request_v4 *)body;
1297 (void) memset((void*)&reply, 0, sizeof (reply));
1298
1299 if (request->mode != NDMP_MOVER_MODE_READ &&
1300 request->mode != NDMP_MOVER_MODE_WRITE) {
1301 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1302 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1303 } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1304 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1305 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1306 request->addr.addr_type);
1307 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1308 reply.error = NDMP_ILLEGAL_STATE_ERR;
1309 NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1310 session->ns_mover.md_state);
1311 } else if (session->ns_tape.td_fd == -1) {
1312 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1313 NDMP_LOG(LOG_DEBUG, "No tape device open");
1314 } else if (request->mode == NDMP_MOVER_MODE_READ &&
1315 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1316 reply.error = NDMP_PERMISSION_ERR;
1317 NDMP_LOG(LOG_ERR, "Write protected device.");
1318 } else if (session->ns_mover.md_record_size == 0) {
1319 reply.error = NDMP_PRECONDITION_ERR;
1320 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1321 } else
1322 reply.error = NDMP_NO_ERR;
1323
1324 if (reply.error != NDMP_NO_ERR) {
1325 ndmp_send_reply(connection, (void *) &reply,
1326 "sending ndmp_mover_connect reply");
1327 return;
1328 }
1329
1330 switch (request->addr.addr_type) {
1331 case NDMP_ADDR_LOCAL:
1332 /*
1333 * Verify that the data server is listening for a
1334 * local connection.
1335 */
1336 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1337 session->ns_data.dd_listen_sock != -1) {
1338 NDMP_LOG(LOG_DEBUG,
1339 "Data server is not in local listen state");
1340 reply.error = NDMP_ILLEGAL_STATE_ERR;
1341 } else
1342 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1343 break;
1344
1345 case NDMP_ADDR_TCP:
1346 reply.error = mover_connect_sock(session, request->mode,
1347 request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1348 break;
1349
1350 default:
1351 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1352 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1353 request->addr.addr_type);
1354 }
1355
1356 if (reply.error == NDMP_NO_ERR) {
1357 session->ns_mover.md_data_addr.addr_type =
1358 request->addr.addr_type;
1359 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1360 session->ns_mover.md_mode = request->mode;
1361 }
1362
1363 ndmp_send_reply(connection, (void *) &reply,
1364 "sending ndmp_mover_connect reply");
1365 }
1366
1367
1368
1369 /*
1370 * ************************************************************************
1371 * LOCALS
1372 * ************************************************************************
1373 */
1374
1375 /*
1376 * ndmpd_local_write
1377 *
1378 * Writes data to the mover.
1379 * Buffers and write data to the tape device.
1380 * A full tape record is buffered before being written.
1381 *
1382 * Parameters:
1383 * session (input) - session pointer.
1384 * data (input) - data to be written.
1385 * length (input) - data length.
1386 *
1387 * Returns:
1388 * 0 - data successfully written.
1389 * -1 - error.
1390 */
1391 int
ndmpd_local_write(ndmpd_session_t * session,char * data,ulong_t length)1392 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1393 {
1394 ulong_t count = 0;
1395 ssize_t n;
1396 ulong_t len;
1397
1398 /*
1399 * A length of 0 indicates that any buffered data should be
1400 * flushed to tape.
1401 */
1402 if (length == 0) {
1403 if (session->ns_mover.md_w_index == 0)
1404 return (0);
1405
1406 (void) memset(
1407 &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1408 0, session->ns_mover.md_record_size -
1409 session->ns_mover.md_w_index);
1410
1411 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
1412 session->ns_mover.md_record_size);
1413 if (n <= 0) {
1414 ndmpd_mover_error(session,
1415 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1416 NDMP_MOVER_HALT_INTERNAL_ERROR));
1417 return (-1);
1418 }
1419 session->ns_mover.md_position += n;
1420 session->ns_mover.md_data_written +=
1421 session->ns_mover.md_w_index;
1422 session->ns_mover.md_record_num++;
1423 session->ns_mover.md_w_index = 0;
1424 return (0);
1425 }
1426 /* Break the data into records. */
1427 while (count < length) {
1428 /*
1429 * Determine if data needs to be buffered or
1430 * can be written directly from user supplied location.
1431 * We can fast path the write if there is no pending
1432 * buffered data and there is at least a full record's worth
1433 * of data to be written.
1434 */
1435 if (session->ns_mover.md_w_index == 0 &&
1436 length - count >= session->ns_mover.md_record_size) {
1437 n = mover_tape_write_v3(session, &data[count],
1438 session->ns_mover.md_record_size);
1439 if (n <= 0) {
1440 ndmpd_mover_error(session,
1441 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1442 NDMP_MOVER_HALT_INTERNAL_ERROR));
1443 return (-1);
1444 }
1445 session->ns_mover.md_position += n;
1446 session->ns_mover.md_data_written += n;
1447 session->ns_mover.md_record_num++;
1448 count += n;
1449 continue;
1450 }
1451 /* Buffer the data */
1452 len = length - count;
1453 if (len > session->ns_mover.md_record_size -
1454 session->ns_mover.md_w_index)
1455 len = session->ns_mover.md_record_size -
1456 session->ns_mover.md_w_index;
1457
1458 (void) memcpy(
1459 &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1460 &data[count], len);
1461 session->ns_mover.md_w_index += len;
1462 count += len;
1463
1464 /* Write the buffer if its full */
1465 if (session->ns_mover.md_w_index ==
1466 session->ns_mover.md_record_size) {
1467 n = mover_tape_write_v3(session,
1468 session->ns_mover.md_buf,
1469 session->ns_mover.md_record_size);
1470 if (n <= 0) {
1471 ndmpd_mover_error(session,
1472 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1473 NDMP_MOVER_HALT_INTERNAL_ERROR));
1474 return (-1);
1475 }
1476 session->ns_mover.md_position += n;
1477 session->ns_mover.md_data_written += n;
1478 session->ns_mover.md_record_num++;
1479 session->ns_mover.md_w_index = 0;
1480 }
1481 }
1482
1483 return (0);
1484 }
1485
1486
1487 /*
1488 * ndmpd_remote_write
1489 *
1490 * Writes data to the remote mover.
1491 *
1492 * Parameters:
1493 * session (input) - session pointer.
1494 * data (input) - data to be written.
1495 * length (input) - data length.
1496 *
1497 * Returns:
1498 * 0 - data successfully written.
1499 * -1 - error.
1500 */
1501 int
ndmpd_remote_write(ndmpd_session_t * session,char * data,ulong_t length)1502 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1503 {
1504 ssize_t n;
1505 ulong_t count = 0;
1506
1507 while (count < length) {
1508 if (session->ns_eof == TRUE ||
1509 session->ns_data.dd_abort == TRUE)
1510 return (-1);
1511
1512 if ((n = write(session->ns_data.dd_sock, &data[count],
1513 length - count)) < 0) {
1514 NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1515 return (-1);
1516 }
1517 count += n;
1518 }
1519
1520 return (0);
1521 }
1522
1523 /*
1524 * ndmpd_local_read
1525 *
1526 * Reads data from the local tape device.
1527 * Full tape records are read and buffered.
1528 *
1529 * Parameters:
1530 * session (input) - session pointer.
1531 * data (input) - location to store data.
1532 * length (input) - data length.
1533 *
1534 * Returns:
1535 * 0 - data successfully read.
1536 * -1 - error.
1537 * 1 - session terminated or operation aborted.
1538 */
1539 int
ndmpd_local_read(ndmpd_session_t * session,char * data,ulong_t length)1540 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1541 {
1542 ulong_t count = 0;
1543 ssize_t n;
1544 ulong_t len;
1545 ndmp_notify_mover_paused_request pause_request;
1546
1547 /*
1548 * Automatically increase the seek window if necessary.
1549 * This is needed in the event the module attempts to read
1550 * past a seek window set via a prior call to ndmpd_seek() or
1551 * the module has not issued a seek. If no seek was issued then
1552 * pretend that a seek was issued to read the entire tape.
1553 */
1554 if (length > session->ns_mover.md_bytes_left_to_read) {
1555 /* ndmpd_seek() never called? */
1556 if (session->ns_data.dd_read_length == 0) {
1557 session->ns_mover.md_bytes_left_to_read = ~0LL;
1558 session->ns_data.dd_read_offset = 0LL;
1559 session->ns_data.dd_read_length = ~0LL;
1560 } else {
1561 session->ns_mover.md_bytes_left_to_read = length;
1562 session->ns_data.dd_read_offset =
1563 session->ns_mover.md_position;
1564 session->ns_data.dd_read_length = length;
1565 }
1566 }
1567 /*
1568 * Read as many records as necessary to satisfy the request.
1569 */
1570 while (count < length) {
1571 /*
1572 * If the end of the mover window has been reached,
1573 * then notify the client that a new data window is needed.
1574 */
1575 if (session->ns_mover.md_position >=
1576 session->ns_mover.md_window_offset +
1577 session->ns_mover.md_window_length) {
1578
1579 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1580 session->ns_mover.md_pause_reason =
1581 NDMP_MOVER_PAUSE_SEEK;
1582 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1583 pause_request.seek_position =
1584 long_long_to_quad(session->ns_mover.md_position);
1585
1586 if (ndmp_send_request(session->ns_connection,
1587 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1588 (void *) &pause_request, 0) < 0) {
1589 NDMP_LOG(LOG_DEBUG,
1590 "Sending notify_mover_paused request");
1591 ndmpd_mover_error(session,
1592 NDMP_MOVER_HALT_INTERNAL_ERROR);
1593 return (-1);
1594 }
1595 /*
1596 * Wait until the state is changed by
1597 * an abort or continue request.
1598 */
1599 if (ndmp_wait_for_mover(session) != 0)
1600 return (1);
1601 }
1602 len = length - count;
1603
1604 /*
1605 * Prevent reading past the end of the window.
1606 */
1607 if (len >
1608 session->ns_mover.md_window_offset +
1609 session->ns_mover.md_window_length -
1610 session->ns_mover.md_position)
1611 len = session->ns_mover.md_window_offset +
1612 session->ns_mover.md_window_length -
1613 session->ns_mover.md_position;
1614
1615 /*
1616 * Copy from the data buffer first.
1617 */
1618 if (session->ns_mover.md_w_index -
1619 session->ns_mover.md_r_index != 0) {
1620 /*
1621 * Limit the copy to the amount of data in the buffer.
1622 */
1623 if (len > session->ns_mover.md_w_index -
1624 session->ns_mover.md_r_index)
1625 len = session->ns_mover.md_w_index
1626 - session->ns_mover.md_r_index;
1627
1628 (void) memcpy((void *) &data[count],
1629 &session->ns_mover.md_buf[session->
1630 ns_mover.md_r_index], len);
1631 count += len;
1632 session->ns_mover.md_r_index += len;
1633 session->ns_mover.md_bytes_left_to_read -= len;
1634 session->ns_mover.md_position += len;
1635 continue;
1636 }
1637 /*
1638 * Determine if data needs to be buffered or
1639 * can be read directly to user supplied location.
1640 * We can fast path the read if at least a full record
1641 * needs to be read and there is no seek pending.
1642 * This is done to eliminate a buffer copy.
1643 */
1644 if (len >= session->ns_mover.md_record_size &&
1645 session->ns_mover.md_position >=
1646 session->ns_mover.md_seek_position) {
1647 n = tape_read(session, &data[count]);
1648 if (n <= 0) {
1649 if (n == TAPE_NO_WRITER_ERR)
1650 return (1);
1651
1652 ndmpd_mover_error(session,
1653 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1654 NDMP_MOVER_HALT_INTERNAL_ERROR));
1655 return (n == 0) ? (1) : (-1);
1656 }
1657 count += n;
1658 session->ns_mover.md_bytes_left_to_read -= n;
1659 session->ns_mover.md_position += n;
1660 continue;
1661 }
1662 /* Read the next record into the buffer. */
1663 n = tape_read(session, session->ns_mover.md_buf);
1664 if (n <= 0) {
1665 if (n == TAPE_NO_WRITER_ERR)
1666 return (1);
1667
1668 ndmpd_mover_error(session,
1669 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1670 NDMP_MOVER_HALT_INTERNAL_ERROR));
1671 return (n == 0) ? (1) : (-1);
1672 }
1673 session->ns_mover.md_w_index = n;
1674 session->ns_mover.md_r_index = 0;
1675
1676 NDMP_LOG(LOG_DEBUG, "n: %d", n);
1677
1678 /*
1679 * Discard data if the current data stream position is
1680 * prior to the seek position. This is necessary if a seek
1681 * request set the seek pointer to a position that is not a
1682 * record boundary. The seek request handler can only position
1683 * to the start of a record.
1684 */
1685 if (session->ns_mover.md_position <
1686 session->ns_mover.md_seek_position) {
1687 session->ns_mover.md_r_index =
1688 session->ns_mover.md_seek_position -
1689 session->ns_mover.md_position;
1690 session->ns_mover.md_position =
1691 session->ns_mover.md_seek_position;
1692 }
1693 }
1694
1695 return (0);
1696 }
1697
1698
1699 /*
1700 * ndmpd_remote_read
1701 *
1702 * Reads data from the remote mover.
1703 *
1704 * Parameters:
1705 * session (input) - session pointer.
1706 * data (input) - data to be written.
1707 * length (input) - data length.
1708 *
1709 * Returns:
1710 * 0 - data successfully read.
1711 * -1 - error.
1712 * 1 - session terminated or operation aborted.
1713 */
1714 int
ndmpd_remote_read(ndmpd_session_t * session,char * data,ulong_t length)1715 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1716 {
1717 ulong_t count = 0;
1718 ssize_t n;
1719 ulong_t len;
1720 ndmp_notify_data_read_request request;
1721
1722 while (count < length) {
1723 len = length - count;
1724
1725 /*
1726 * If the end of the seek window has been reached then
1727 * send an ndmp_read request to the client.
1728 * The NDMP client will then send a mover_data_read request to
1729 * the remote mover and the mover will send more data.
1730 * This condition can occur if the module attempts to read past
1731 * a seek window set via a prior call to ndmpd_seek() or
1732 * the module has not issued a seek. If no seek was issued then
1733 * pretend that a seek was issued to read the entire tape.
1734 */
1735 if (session->ns_mover.md_bytes_left_to_read == 0) {
1736 /* ndmpd_seek() never called? */
1737 if (session->ns_data.dd_read_length == 0) {
1738 session->ns_mover.md_bytes_left_to_read = ~0LL;
1739 session->ns_data.dd_read_offset = 0LL;
1740 session->ns_data.dd_read_length = ~0LL;
1741 } else {
1742 session->ns_mover.md_bytes_left_to_read = len;
1743 session->ns_data.dd_read_offset =
1744 session->ns_mover.md_position;
1745 session->ns_data.dd_read_length = len;
1746 }
1747
1748 request.offset =
1749 long_long_to_quad(session->ns_data.dd_read_offset);
1750 request.length =
1751 long_long_to_quad(session->ns_data.dd_read_length);
1752
1753 if (ndmp_send_request_lock(session->ns_connection,
1754 NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1755 (void *) &request, 0) < 0) {
1756 NDMP_LOG(LOG_DEBUG,
1757 "Sending notify_data_read request");
1758 return (-1);
1759 }
1760 }
1761 if (session->ns_eof == TRUE ||
1762 session->ns_data.dd_abort == TRUE)
1763 return (1);
1764
1765 /*
1766 * If the module called ndmpd_seek() prior to reading all of the
1767 * data that the remote mover was requested to send, then the
1768 * excess data from the seek has to be discardd.
1769 */
1770 if (session->ns_mover.md_discard_length != 0) {
1771 n = discard_data(session,
1772 (ulong_t)session->ns_mover.md_discard_length);
1773 if (n < 0)
1774 return (-1);
1775 session->ns_mover.md_discard_length -= n;
1776 continue;
1777 }
1778 /*
1779 * Don't attempt to read more data than the remote is sending.
1780 */
1781 if (len > session->ns_mover.md_bytes_left_to_read)
1782 len = session->ns_mover.md_bytes_left_to_read;
1783
1784 NDMP_LOG(LOG_DEBUG, "len: %u", len);
1785
1786 if ((n = read(session->ns_data.dd_sock, &data[count],
1787 len)) < 0) {
1788 NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1789 return (-1);
1790 }
1791 /* read returns 0 if the connection was closed */
1792 if (n == 0)
1793 return (-1);
1794
1795 count += n;
1796 session->ns_mover.md_bytes_left_to_read -= n;
1797 session->ns_mover.md_position += n;
1798 }
1799
1800 return (0);
1801 }
1802
1803 /* *** ndmpd internal functions ***************************************** */
1804
1805 /*
1806 * ndmpd_mover_init
1807 *
1808 * Initialize mover specific session variables.
1809 * Don't initialize variables such as record_size that need to
1810 * persist across data operations. A client may open a connection and
1811 * do multiple backups after setting the record_size.
1812 *
1813 * Parameters:
1814 * session (input) - session pointer.
1815 *
1816 * Returns:
1817 * 0 - success.
1818 * -1 - error.
1819 */
1820 int
ndmpd_mover_init(ndmpd_session_t * session)1821 ndmpd_mover_init(ndmpd_session_t *session)
1822 {
1823 session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1824 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1825 session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1826 session->ns_mover.md_data_written = 0LL;
1827 session->ns_mover.md_seek_position = 0LL;
1828 session->ns_mover.md_bytes_left_to_read = 0LL;
1829 session->ns_mover.md_window_offset = 0LL;
1830 session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1831 session->ns_mover.md_position = 0LL;
1832 session->ns_mover.md_discard_length = 0;
1833 session->ns_mover.md_record_num = 0;
1834 session->ns_mover.md_record_size = 0;
1835 session->ns_mover.md_listen_sock = -1;
1836 session->ns_mover.md_pre_cond = FALSE;
1837 session->ns_mover.md_sock = -1;
1838 session->ns_mover.md_r_index = 0;
1839 session->ns_mover.md_w_index = 0;
1840 session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1841 if (!session->ns_mover.md_buf)
1842 return (-1);
1843
1844 if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1845 session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1846 (void) memset(&session->ns_mover.md_data_addr, 0,
1847 sizeof (ndmp_addr_v3));
1848 }
1849 return (0);
1850 }
1851
1852
1853 /*
1854 * ndmpd_mover_shut_down
1855 *
1856 * Shutdown the mover. It closes all the sockets.
1857 *
1858 * Parameters:
1859 * session (input) - session pointer.
1860 *
1861 * Returns:
1862 * void
1863 */
1864 void
ndmpd_mover_shut_down(ndmpd_session_t * session)1865 ndmpd_mover_shut_down(ndmpd_session_t *session)
1866 {
1867 ndmp_lbr_params_t *nlp;
1868
1869 if ((nlp = ndmp_get_nlp(session)) == NULL)
1870 return;
1871
1872 (void) mutex_lock(&nlp->nlp_mtx);
1873 if (session->ns_mover.md_listen_sock != -1) {
1874 NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1875 session->ns_mover.md_listen_sock);
1876 (void) ndmpd_remove_file_handler(session,
1877 session->ns_mover.md_listen_sock);
1878 (void) close(session->ns_mover.md_listen_sock);
1879 session->ns_mover.md_listen_sock = -1;
1880 }
1881 if (session->ns_mover.md_sock != -1) {
1882 NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1883 session->ns_mover.md_sock);
1884 (void) ndmpd_remove_file_handler(session,
1885 session->ns_mover.md_sock);
1886 (void) close(session->ns_mover.md_sock);
1887 session->ns_mover.md_sock = -1;
1888 }
1889 (void) cond_broadcast(&nlp->nlp_cv);
1890 (void) mutex_unlock(&nlp->nlp_mtx);
1891 }
1892
1893
1894 /*
1895 * ndmpd_mover_cleanup
1896 *
1897 * Parameters:
1898 * session (input) - session pointer.
1899 *
1900 * Returns:
1901 * void
1902 */
1903 void
ndmpd_mover_cleanup(ndmpd_session_t * session)1904 ndmpd_mover_cleanup(ndmpd_session_t *session)
1905 {
1906 NDMP_FREE(session->ns_mover.md_buf);
1907 }
1908
1909
1910 /*
1911 * ndmpd_mover_connect
1912 * Create a connection to the specified mover.
1913 *
1914 * Parameters:
1915 * session (input) - session pointer
1916 *
1917 * Returns:
1918 * error code.
1919 */
1920 ndmp_error
ndmpd_mover_connect(ndmpd_session_t * session,ndmp_mover_mode mover_mode)1921 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1922 {
1923 ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1924 struct sockaddr_in sin;
1925 int sock = -1;
1926
1927 if (mover->addr_type == NDMP_ADDR_TCP) {
1928 if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1929 (void) memset((void *) &sin, 0, sizeof (sin));
1930 sin.sin_family = AF_INET;
1931 sin.sin_addr.s_addr =
1932 htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1933 sin.sin_port =
1934 htons(mover->ndmp_mover_addr_u.addr.port);
1935
1936 /*
1937 * If the address type is TCP but both the address and
1938 * the port number are zero, we have to use a different
1939 * socket than the mover socket. This can happen when
1940 * using NDMP disk to disk copy (AKA D2D copy).
1941 * The NDMPCopy client will send a zero address to
1942 * direct the server to use the mover socket as the
1943 * data socket to receive the recovery data.
1944 */
1945 if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1946 session->ns_data.dd_sock =
1947 session->ns_mover.md_sock;
1948 return (NDMP_NO_ERR);
1949 }
1950
1951 NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1952 mover->ndmp_mover_addr_u.addr.ip_addr,
1953 (ulong_t)sin.sin_port);
1954
1955 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1956 NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1957 return (NDMP_IO_ERR);
1958 }
1959 if (connect(sock, (struct sockaddr *)&sin,
1960 sizeof (sin)) < 0) {
1961 NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1962 (void) close(sock);
1963 return (NDMP_IO_ERR);
1964 }
1965 set_socket_options(sock);
1966 } else {
1967 if ((session->ns_mover.md_state !=
1968 NDMP_MOVER_STATE_ACTIVE) ||
1969 (session->ns_mover.md_sock == -1)) {
1970
1971 NDMP_LOG(LOG_DEBUG,
1972 "Not in active state mover"
1973 " state = %d or Invalid mover sock=%d",
1974 session->ns_mover.md_state,
1975 session->ns_mover.md_sock);
1976 return (NDMP_ILLEGAL_STATE_ERR);
1977 }
1978
1979 sock = session->ns_mover.md_sock;
1980 NDMP_LOG(LOG_DEBUG,
1981 "session: 0x%x setting data sock fd: %d to be"
1982 " same as listen_sock", session, sock);
1983 }
1984
1985 NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
1986
1987 session->ns_data.dd_sock = sock;
1988
1989 NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
1990
1991 return (NDMP_NO_ERR);
1992 }
1993 /* Local mover connection. */
1994
1995 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
1996 NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
1997 return (NDMP_ILLEGAL_STATE_ERR);
1998 }
1999 if (session->ns_tape.td_fd == -1) {
2000 NDMP_LOG(LOG_DEBUG, "Tape device not open");
2001 return (NDMP_DEV_NOT_OPEN_ERR);
2002 }
2003 if (mover_mode == NDMP_MOVER_MODE_READ &&
2004 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
2005 NDMP_LOG(LOG_ERR, "Write protected device.");
2006 return (NDMP_WRITE_PROTECT_ERR);
2007 }
2008 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2009 session->ns_mover.md_mode = mover_mode;
2010
2011 return (NDMP_NO_ERR);
2012 }
2013
2014
2015
2016 /*
2017 * ndmpd_mover_seek
2018 *
2019 * Seek to the requested data stream position.
2020 * If the requested offset is outside of the current window,
2021 * the mover is paused and a notify_mover_paused request is sent
2022 * notifying the client that a seek is required.
2023 * If the requested offest is within the window but not within the
2024 * current record, then the tape is positioned to the record containing
2025 * the requested offest.
2026 * The requested amount of data is then read from the tape device and
2027 * written to the data connection.
2028 *
2029 * Parameters:
2030 * session (input) - session pointer.
2031 * offset (input) - data stream position to seek to.
2032 * length (input) - amount of data that will be read.
2033 *
2034 * Returns:
2035 * 1 - seek pending completion by the NDMP client.
2036 * 0 - seek successfully completed.
2037 * -1 - error.
2038 */
2039 int
ndmpd_mover_seek(ndmpd_session_t * session,u_longlong_t offset,u_longlong_t length)2040 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2041 u_longlong_t length)
2042 {
2043 int ctlcmd;
2044 int ctlcnt;
2045 u_longlong_t tape_position;
2046 u_longlong_t buf_position;
2047 ndmp_notify_mover_paused_request pause_request;
2048
2049 session->ns_mover.md_seek_position = offset;
2050 session->ns_mover.md_bytes_left_to_read = length;
2051
2052 /*
2053 * If the requested position is outside of the window,
2054 * notify the client that a seek is required.
2055 */
2056 if (session->ns_mover.md_seek_position <
2057 session->ns_mover.md_window_offset ||
2058 session->ns_mover.md_seek_position >=
2059 session->ns_mover.md_window_offset +
2060 session->ns_mover.md_window_length) {
2061 NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2062 session->ns_mover.md_seek_position);
2063
2064 session->ns_mover.md_w_index = 0;
2065 session->ns_mover.md_r_index = 0;
2066
2067 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2068 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2069 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2070 pause_request.seek_position = long_long_to_quad(offset);
2071
2072 if (ndmp_send_request(session->ns_connection,
2073 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2074 (void *) &pause_request, 0) < 0) {
2075 NDMP_LOG(LOG_DEBUG,
2076 "Sending notify_mover_paused request");
2077 return (-1);
2078 }
2079 return (1);
2080 }
2081 /*
2082 * Determine the data stream position of the first byte in the
2083 * data buffer.
2084 */
2085 buf_position = session->ns_mover.md_position -
2086 (session->ns_mover.md_position % session->ns_mover.md_record_size);
2087
2088 /*
2089 * Determine the data stream position of the next byte that
2090 * will be read from tape.
2091 */
2092 tape_position = buf_position;
2093 if (session->ns_mover.md_w_index != 0)
2094 tape_position += session->ns_mover.md_record_size;
2095
2096 /*
2097 * Check if requested position is for data that has been read and is
2098 * in the buffer.
2099 */
2100 if (offset >= buf_position && offset < tape_position) {
2101 session->ns_mover.md_position = offset;
2102 session->ns_mover.md_r_index = session->ns_mover.md_position -
2103 buf_position;
2104
2105 NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2106 session->ns_mover.md_position,
2107 session->ns_mover.md_r_index);
2108
2109 return (0);
2110 }
2111
2112 ctlcmd = 0;
2113 if (tape_position > session->ns_mover.md_seek_position) {
2114 /* Need to seek backward. */
2115 ctlcmd = MTBSR;
2116 ctlcnt = (int)((tape_position - offset - 1)
2117 / session->ns_mover.md_record_size) + 1;
2118 tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2119 session->ns_mover.md_record_size) + 1) *
2120 (u_longlong_t)session->ns_mover.md_record_size);
2121
2122 } else if (offset >= tape_position + session->ns_mover.md_record_size) {
2123 /* Need to seek forward. */
2124 ctlcmd = MTFSR;
2125 ctlcnt = (int)((offset - tape_position)
2126 / session->ns_mover.md_record_size);
2127 tape_position += ((u_longlong_t)(((offset - tape_position) /
2128 session->ns_mover.md_record_size)) *
2129 (u_longlong_t)session->ns_mover.md_record_size);
2130 }
2131 /* Reposition the tape if necessary. */
2132 if (ctlcmd) {
2133 NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2134 ctlcmd, ctlcnt);
2135 (void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2136 }
2137
2138 session->ns_mover.md_position = tape_position;
2139 session->ns_mover.md_r_index = 0;
2140 session->ns_mover.md_w_index = 0;
2141
2142 NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2143
2144 return (0);
2145 }
2146
2147
2148 /* ** static functions ************************************************** */
2149
2150 /*
2151 * create_listen_socket_v2
2152 *
2153 * Creates a socket for listening for accepting data connections.
2154 *
2155 * Parameters:
2156 * session (input) - session pointer.
2157 * addr (output) - location to store address of socket.
2158 * port (output) - location to store port of socket.
2159 *
2160 * Returns:
2161 * 0 - success.
2162 * -1 - error.
2163 */
2164 static int
create_listen_socket_v2(ndmpd_session_t * session,ulong_t * addr,ushort_t * port)2165 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2166 {
2167 session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2168 if (session->ns_mover.md_listen_sock < 0)
2169 return (-1);
2170
2171 /*
2172 * Add a file handler for the listen socket.
2173 * ndmpd_select will call accept_connection when a
2174 * connection is ready to be accepted.
2175 */
2176 if (ndmpd_add_file_handler(session, (void *) session,
2177 session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2178 accept_connection) < 0) {
2179 (void) close(session->ns_mover.md_listen_sock);
2180 session->ns_mover.md_listen_sock = -1;
2181 return (-1);
2182 }
2183
2184 NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2185 return (0);
2186 }
2187
2188 /*
2189 * accept_connection
2190 *
2191 * Accept a data connection from a data server.
2192 * Called by ndmpd_select when a connection is pending on
2193 * the mover listen socket.
2194 *
2195 * Parameters:
2196 * cookie (input) - session pointer.
2197 * fd (input) - file descriptor.
2198 * mode (input) - select mode.
2199 *
2200 * Returns:
2201 * void.
2202 */
2203 /*ARGSUSED*/
2204 static void
accept_connection(void * cookie,int fd,ulong_t mode)2205 accept_connection(void *cookie, int fd, ulong_t mode)
2206 {
2207 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2208 struct sockaddr_in from;
2209 int from_len;
2210
2211 from_len = sizeof (from);
2212 session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2213 &from_len);
2214
2215 (void) ndmpd_remove_file_handler(session, fd);
2216 (void) close(session->ns_mover.md_listen_sock);
2217 session->ns_mover.md_listen_sock = -1;
2218
2219 if (session->ns_mover.md_sock < 0) {
2220 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2221 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2222 return;
2223 }
2224 set_socket_options(session->ns_mover.md_sock);
2225
2226 NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2227
2228 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2229 if (start_mover_for_backup(session) < 0) {
2230 ndmpd_mover_error(session,
2231 NDMP_MOVER_HALT_INTERNAL_ERROR);
2232 return;
2233 }
2234 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2235 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2236 ntohs(from.sin_port));
2237 } else {
2238 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2239 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2240 ntohs(from.sin_port));
2241 }
2242
2243 NDMP_LOG(LOG_DEBUG, "Received connection");
2244
2245 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2246 }
2247
2248 /*
2249 * tape_read
2250 *
2251 * Reads a data record from tape. Detects and handles EOT conditions.
2252 *
2253 * Parameters:
2254 * session (input) - session pointer.
2255 * data (input) - location to read data to.
2256 *
2257 * Returns:
2258 * 0 - operation aborted.
2259 * -1 - tape read error.
2260 * otherwise - number of bytes read.
2261 */
2262 static int
tape_read(ndmpd_session_t * session,char * data)2263 tape_read(ndmpd_session_t *session, char *data)
2264 {
2265 ssize_t n;
2266 int err;
2267 int count = session->ns_mover.md_record_size;
2268
2269 for (; ; ) {
2270 n = read(session->ns_tape.td_fd, data, count);
2271 if (n < 0) {
2272 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2273 return (TAPE_READ_ERR);
2274 }
2275 NS_ADD(rtape, n);
2276
2277 if (n == 0) {
2278 if (!is_writer_running(session))
2279 return (TAPE_NO_WRITER_ERR);
2280
2281 /*
2282 * End of media reached.
2283 * Notify client and wait for the client to
2284 * either abort the data operation or continue the
2285 * operation after changing the tape.
2286 */
2287 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2288 ++ndmp_log_msg_id,
2289 "End of tape reached. Load next tape");
2290
2291 NDMP_LOG(LOG_DEBUG,
2292 "End of tape reached. Load next tape");
2293
2294 err = change_tape(session);
2295
2296 /* Operation aborted or connection terminated? */
2297 if (err < 0) {
2298 /*
2299 * K.L. Go back one record if it is read
2300 * but not used.
2301 */
2302
2303 if (count != session->ns_mover.md_record_size) {
2304 (void) ndmp_mtioctl(
2305 session->ns_tape.td_fd, MTBSR, 1);
2306 }
2307 return (0);
2308 }
2309 /* Retry the read from the new tape. */
2310 continue;
2311 }
2312
2313 /* Change to pass Veritas Netbackup prequal test. */
2314 data += n;
2315 count -= n;
2316 if (count <= 0) {
2317 session->ns_mover.md_record_num++;
2318 session->ns_tape.td_record_count++;
2319 return (n);
2320 }
2321 }
2322 }
2323
2324 /*
2325 * change_tape
2326 *
2327 * Send a notify_pause request (protocol version 1) or
2328 * notify_mover_pause request (protocol version 2) to the
2329 * NDMP client to inform
2330 * the client that a tape volume change is required.
2331 * Process messages until the data/mover operation is either aborted
2332 * or continued.
2333 *
2334 * Parameters:
2335 * client_data (input) - session pointer.
2336 *
2337 * Returns:
2338 * 0 - operation has been continued.
2339 * -1 - operation has been aborted.
2340 */
2341 static int
change_tape(ndmpd_session_t * session)2342 change_tape(ndmpd_session_t *session)
2343 {
2344 ndmp_notify_mover_paused_request request;
2345
2346 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2347
2348 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2349 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2350 else
2351 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2352
2353 request.reason = session->ns_mover.md_pause_reason;
2354 request.seek_position = long_long_to_quad(0LL);
2355
2356 NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2357 session->ns_mover.md_pause_reason);
2358
2359 if (ndmp_send_request(session->ns_connection,
2360 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2361 (void *) &request, 0) < 0) {
2362 NDMP_LOG(LOG_DEBUG,
2363 "Sending notify_mover_paused request");
2364 return (-1);
2365 }
2366 /*
2367 * Wait for until the state is changed by
2368 * an abort or continue request.
2369 */
2370 return (ndmp_wait_for_mover(session));
2371 }
2372
2373
2374 /*
2375 * discard_data
2376 *
2377 * Read and discard data from the data connection.
2378 * Called when a module has called ndmpd_seek() prior to
2379 * reading all of the data from the previous seek.
2380 *
2381 * Parameters:
2382 * session (input) - session pointer.
2383 *
2384 * Returns:
2385 * number of bytes read and discarded.
2386 * -1 - error.
2387 */
2388 static int
discard_data(ndmpd_session_t * session,ulong_t length)2389 discard_data(ndmpd_session_t *session, ulong_t length)
2390 {
2391 int n;
2392 char *addr;
2393
2394 if ((addr = ndmp_malloc(length)) == NULL)
2395 return (-1);
2396
2397 /* Read and discard the data. */
2398 n = read(session->ns_mover.md_sock, addr, length);
2399 if (n < 0) {
2400 NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2401 free(addr);
2402 return (-1);
2403 }
2404
2405 free(addr);
2406 return (n);
2407 }
2408
2409
2410 /*
2411 * mover_tape_read_one_buf
2412 *
2413 * Read one buffer from the tape. This is used by mover_tape_reader
2414 *
2415 * Parameters:
2416 * session (input) - session pointer.
2417 * buf (input) - buffer read
2418 *
2419 * Returns:
2420 * 0: on success
2421 * -1: otherwise
2422 */
2423 static int
mover_tape_read_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)2424 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2425 {
2426 int n;
2427
2428 tlm_buffer_mark_empty(buf);
2429
2430 /*
2431 * If the end of the mover window has been reached,
2432 * then notify the client that a seek is needed.
2433 * Remove the file handler to prevent this function from
2434 * being called. The handler will be reinstalled in
2435 * ndmpd_mover_continue.
2436 */
2437
2438 if (session->ns_mover.md_position >=
2439 session->ns_mover.md_window_offset +
2440 session->ns_mover.md_window_length) {
2441 ndmp_notify_mover_paused_request pause_request;
2442
2443 NDMP_LOG(LOG_DEBUG, "end of mover window");
2444
2445 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2446 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2447 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2448 pause_request.seek_position =
2449 long_long_to_quad(session->ns_mover.md_position);
2450
2451 if (ndmp_send_request(session->ns_connection,
2452 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2453 (void *) &pause_request, 0) < 0) {
2454 NDMP_LOG(LOG_DEBUG,
2455 "Sending notify_mover_paused request");
2456 ndmpd_mover_error(session,
2457 NDMP_MOVER_HALT_INTERNAL_ERROR);
2458 }
2459 buf->tb_errno = EIO;
2460 return (TAPE_READ_ERR);
2461 }
2462
2463 n = tape_read(session, buf->tb_buffer_data);
2464
2465 NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2466
2467 if (n <= 0) {
2468 if (n < 0)
2469 ndmpd_mover_error(session,
2470 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2471 NDMP_MOVER_HALT_INTERNAL_ERROR));
2472 return (TAPE_READ_ERR);
2473 }
2474
2475 buf->tb_full = TRUE;
2476 buf->tb_buffer_size = session->ns_mover.md_record_size;
2477
2478 /*
2479 * Discard data if the current data stream position is
2480 * prior to the seek position. This is necessary if a seek
2481 * request set the seek pointer to a position that is not a
2482 * record boundary. The seek request handler can only position
2483 * to the start of a record.
2484 */
2485 if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2486 session->ns_mover.md_position =
2487 session->ns_mover.md_seek_position;
2488
2489 return (0);
2490 }
2491
2492
2493 /*
2494 * mover_tape_reader
2495 *
2496 * Mover tape reader thread. It is launched when the mover is started
2497 * for restore.
2498 *
2499 * Parameters:
2500 * session (input) - session pointer.
2501 *
2502 * Returns:
2503 * 0: on success
2504 * -1: otherwise
2505 */
2506 void *
mover_tape_reader(void * ptr)2507 mover_tape_reader(void *ptr)
2508 {
2509 int bidx; /* buffer index */
2510 int rv;
2511 ndmp_lbr_params_t *nlp;
2512 tlm_buffer_t *buf;
2513 tlm_buffers_t *bufs;
2514 tlm_cmd_t *lcmd; /* Local command */
2515 tlm_commands_t *cmds; /* Commands structure */
2516 ndmpd_session_t *session = ptr;
2517
2518 if ((nlp = ndmp_get_nlp(session)) == NULL) {
2519 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2520 return ((void *)(uintptr_t)-1);
2521 }
2522
2523 cmds = &nlp->nlp_cmds;
2524 lcmd = cmds->tcs_command;
2525 bufs = lcmd->tc_buffers;
2526
2527 lcmd->tc_ref++;
2528 cmds->tcs_reader_count++;
2529
2530 /*
2531 * Let our parent thread know that we are running.
2532 */
2533 tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2534
2535 buf = tlm_buffer_in_buf(bufs, &bidx);
2536 while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2537 lcmd->tc_reader == TLM_RESTORE_RUN) {
2538 buf = tlm_buffer_in_buf(bufs, NULL);
2539
2540 if (buf->tb_full) {
2541 NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2542 /*
2543 * The buffer is still full, wait for the consumer
2544 * thread to use it.
2545 */
2546 tlm_buffer_out_buf_timed_wait(bufs, 100);
2547
2548 } else {
2549 NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2550
2551 rv = mover_tape_read_one_buf(session, buf);
2552 /*
2553 * If there was an error while reading, such as
2554 * end of stream.
2555 */
2556 if (rv < 0) {
2557 NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2558 break;
2559 }
2560
2561 /*
2562 * Can we do more buffering?
2563 */
2564 if (is_buffer_erroneous(buf)) {
2565 NDMP_LOG(LOG_DEBUG,
2566 "Exiting, errno: %d, eot: %d, eof: %d",
2567 buf->tb_errno, buf->tb_eot, buf->tb_eof);
2568 break;
2569 }
2570
2571 (void) tlm_buffer_advance_in_idx(bufs);
2572 tlm_buffer_release_in_buf(bufs);
2573 bidx = bufs->tbs_buffer_in;
2574 }
2575 }
2576
2577 /* If the consumer is waiting for us, wake it up. */
2578 tlm_buffer_release_in_buf(bufs);
2579
2580 /*
2581 * Clean up.
2582 */
2583 cmds->tcs_reader_count--;
2584 lcmd->tc_ref--;
2585 lcmd->tc_writer = TLM_STOP;
2586 return (NULL);
2587 }
2588
2589
2590 /*
2591 * mover_socket_write_one_buf
2592 *
2593 * Write one buffer to the network socket. This is used by mover_socket_writer
2594 *
2595 * Parameters:
2596 * session (input) - session pointer.
2597 * buf (input) - buffer read
2598 *
2599 * Returns:
2600 * 0: on success
2601 * -1: otherwise
2602 */
2603 static int
mover_socket_write_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)2604 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2605 {
2606 int n;
2607
2608 /* Write the data to the data connection. */
2609 errno = 0;
2610 n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2611 buf->tb_buffer_size);
2612
2613 NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2614
2615 if (n < 0) {
2616 NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2617 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2618 return (-1);
2619 }
2620
2621 session->ns_mover.md_position += n;
2622 session->ns_mover.md_bytes_left_to_read -= n;
2623 tlm_buffer_mark_empty(buf);
2624
2625 /*
2626 * If the read limit has been reached,
2627 * then remove the file handler to prevent this
2628 * function from getting called. The next mover_read request
2629 * will reinstall the handler.
2630 */
2631 if (session->ns_mover.md_bytes_left_to_read == 0) {
2632 NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2633 (void) ndmpd_remove_file_handler(session,
2634 session->ns_mover.md_sock);
2635 return (-1);
2636 }
2637
2638 return (0);
2639 }
2640
2641
2642
2643 /*
2644 * mover_socket_writer
2645 *
2646 * Mover's socket writer thread. This thread sends the read buffer
2647 * from the tape to the data server through the network socket.
2648 *
2649 * Parameters:
2650 * session (input) - session pointer.
2651 *
2652 * Returns:
2653 * 0: on success
2654 * -1: otherwise
2655 */
2656 void *
mover_socket_writer(void * ptr)2657 mover_socket_writer(void *ptr)
2658 {
2659 int bidx; /* buffer index */
2660 ndmp_lbr_params_t *nlp;
2661 tlm_buffer_t *buf;
2662 tlm_buffers_t *bufs;
2663 tlm_cmd_t *lcmd; /* Local command */
2664 tlm_commands_t *cmds; /* Commands structure */
2665 ndmpd_session_t *session = ptr;
2666
2667 if ((nlp = ndmp_get_nlp(session)) == NULL) {
2668 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2669 return ((void *)(uintptr_t)-1);
2670 }
2671
2672 cmds = &nlp->nlp_cmds;
2673 lcmd = cmds->tcs_command;
2674 bufs = lcmd->tc_buffers;
2675
2676 lcmd->tc_ref++;
2677 cmds->tcs_writer_count++;
2678
2679 /*
2680 * Let our parent thread know that we are running.
2681 */
2682 tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2683
2684 bidx = bufs->tbs_buffer_out;
2685 while (cmds->tcs_writer != (int)TLM_ABORT &&
2686 lcmd->tc_writer != (int)TLM_ABORT) {
2687 buf = &bufs->tbs_buffer[bidx];
2688
2689 if (buf->tb_full) {
2690 NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2691
2692 if (mover_socket_write_one_buf(session, buf) < 0) {
2693 NDMP_LOG(LOG_DEBUG,
2694 "mover_socket_write_one_buf() < 0");
2695 break;
2696 }
2697
2698 (void) tlm_buffer_advance_out_idx(bufs);
2699 tlm_buffer_release_out_buf(bufs);
2700 bidx = bufs->tbs_buffer_out;
2701 } else {
2702 if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2703 /* No more data is coming, time to exit */
2704 NDMP_LOG(LOG_DEBUG, "Time to exit");
2705 break;
2706 }
2707 NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2708 /*
2709 * The buffer is not full, wait for the producer
2710 * thread to fill it.
2711 */
2712 tlm_buffer_in_buf_timed_wait(bufs, 100);
2713 }
2714 }
2715
2716 if (cmds->tcs_writer == (int)TLM_ABORT)
2717 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2718 if (lcmd->tc_writer == (int)TLM_ABORT)
2719 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2720
2721 /* If the producer is waiting for us, wake it up. */
2722 tlm_buffer_release_out_buf(bufs);
2723
2724 /*
2725 * Clean up.
2726 */
2727 cmds->tcs_writer_count--;
2728 lcmd->tc_ref--;
2729 lcmd->tc_reader = TLM_STOP;
2730 return (NULL);
2731 }
2732
2733
2734 /*
2735 * start_mover_for_restore
2736 *
2737 * Creates the mover tape reader and network writer threads for
2738 * the mover to perform the 3-way restore.
2739 *
2740 * Parameters:
2741 * session (input) - session pointer.
2742 *
2743 * Returns:
2744 * 0: on success
2745 * -1: otherwise
2746 */
2747 static int
start_mover_for_restore(ndmpd_session_t * session)2748 start_mover_for_restore(ndmpd_session_t *session)
2749 {
2750 ndmp_lbr_params_t *nlp;
2751 tlm_commands_t *cmds;
2752 long xfer_size;
2753 int rc;
2754
2755 if ((nlp = ndmp_get_nlp(session)) == NULL) {
2756 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2757 return (-1);
2758 }
2759
2760 cmds = &nlp->nlp_cmds;
2761 (void) memset(cmds, 0, sizeof (*cmds));
2762 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2763 xfer_size = ndmp_buffer_get_size(session);
2764 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2765 if (cmds->tcs_command == NULL)
2766 return (-1);
2767
2768 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2769 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2770
2771 /*
2772 * We intentionnally don't wait for the threads to start since the
2773 * reply of the request (which resulted in calling this function)
2774 * must be sent to the client before probable errors are sent
2775 * to the client.
2776 */
2777 rc = pthread_create(NULL, NULL, mover_tape_reader, session);
2778 if (rc == 0) {
2779 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2780 } else {
2781 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2782 strerror(rc));
2783 return (-1);
2784 }
2785
2786 rc = pthread_create(NULL, NULL, mover_socket_writer, session);
2787 if (rc == 0) {
2788 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2789 } else {
2790 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2791 strerror(rc));
2792 return (-1);
2793 }
2794
2795 tlm_release_reader_writer_ipc(cmds->tcs_command);
2796 return (0);
2797 }
2798
2799
2800 /*
2801 * mover_socket_read_one_buf
2802 *
2803 * Read one buffer from the network socket for the mover. This is used
2804 * by mover_socket_reader
2805 *
2806 * Parameters:
2807 * session (input) - session pointer.
2808 * buf (input) - buffer read
2809 * read_size (input) - size to be read
2810 *
2811 * Returns:
2812 * 0: on success
2813 * -1: otherwise
2814 */
2815 static int
mover_socket_read_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf,long read_size)2816 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2817 long read_size)
2818 {
2819 int n, index;
2820 long toread;
2821
2822 tlm_buffer_mark_empty(buf);
2823 for (index = 0, toread = read_size; toread > 0; ) {
2824 errno = 0;
2825 NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2826
2827 n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2828 toread);
2829 if (n == 0) {
2830 NDMP_LOG(LOG_DEBUG, "n: %d", n);
2831 break;
2832 } else if (n > 0) {
2833 NDMP_LOG(LOG_DEBUG, "n: %d", n);
2834 index += n;
2835 toread -= n;
2836 } else {
2837 buf->tb_eof = TRUE;
2838 buf->tb_errno = errno;
2839 buf->tb_buffer_size = 0;
2840 NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2841 return (-1);
2842 }
2843 }
2844
2845 if (index > 0) {
2846 buf->tb_full = TRUE;
2847 buf->tb_buffer_size = read_size;
2848 if (read_size > 0)
2849 (void) memset(&buf->tb_buffer_data[index], 0,
2850 read_size - index);
2851 } else {
2852 buf->tb_eof = TRUE;
2853 buf->tb_buffer_size = 0;
2854 }
2855
2856 NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2857 " errno: %d, size: %d, data: 0x%x",
2858 buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2859 buf->tb_buffer_size, buf->tb_buffer_data);
2860
2861 return (0);
2862 }
2863
2864
2865
2866 /*
2867 * mover_socket_reader
2868 *
2869 * Mover socket reader thread. This is used when reading data from the
2870 * network socket for performing remote backups.
2871 *
2872 * Parameters:
2873 * session (input) - session pointer.
2874 *
2875 * Returns:
2876 * 0: on success
2877 * -1: otherwise
2878 */
2879 void *
mover_socket_reader(void * ptr)2880 mover_socket_reader(void *ptr)
2881 {
2882 int bidx; /* buffer index */
2883 ndmp_lbr_params_t *nlp;
2884 tlm_buffer_t *buf;
2885 tlm_buffers_t *bufs;
2886 tlm_cmd_t *lcmd; /* Local command */
2887 tlm_commands_t *cmds; /* Commands structure */
2888 ndmpd_session_t *session = ptr;
2889 static int nr = 0;
2890
2891 if ((nlp = ndmp_get_nlp(session)) == NULL) {
2892 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2893 return ((void *)(uintptr_t)-1);
2894 }
2895
2896 cmds = &nlp->nlp_cmds;
2897 lcmd = cmds->tcs_command;
2898 bufs = lcmd->tc_buffers;
2899
2900 lcmd->tc_ref++;
2901 cmds->tcs_reader_count++;
2902
2903 /*
2904 * Let our parent thread know that we are running.
2905 */
2906 tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2907
2908 bidx = bufs->tbs_buffer_in;
2909 while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2910 lcmd->tc_reader == TLM_BACKUP_RUN) {
2911 buf = &bufs->tbs_buffer[bidx];
2912
2913 if (buf->tb_full) {
2914 NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2915 /*
2916 * The buffer is still full, wait for the consumer
2917 * thread to use it.
2918 */
2919 tlm_buffer_out_buf_timed_wait(bufs, 100);
2920 } else {
2921 NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2922
2923 (void) mover_socket_read_one_buf(session, buf,
2924 bufs->tbs_data_transfer_size);
2925
2926 /*
2927 * Can we do more buffering?
2928 */
2929 if (is_buffer_erroneous(buf)) {
2930 NDMP_LOG(LOG_DEBUG,
2931 "Exiting, errno: %d, eot: %d, eof: %d",
2932 buf->tb_errno, buf->tb_eot, buf->tb_eof);
2933 break;
2934 }
2935
2936 (void) tlm_buffer_advance_in_idx(bufs);
2937 tlm_buffer_release_in_buf(bufs);
2938 bidx = bufs->tbs_buffer_in;
2939 }
2940 }
2941
2942 if (cmds->tcs_reader != TLM_BACKUP_RUN)
2943 NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2944 if (lcmd->tc_reader != TLM_BACKUP_RUN)
2945 NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2946 NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
2947
2948 /* If the consumer is waiting for us, wake it up. */
2949 tlm_buffer_release_in_buf(bufs);
2950
2951 /*
2952 * Clean up.
2953 */
2954 cmds->tcs_reader_count--;
2955 lcmd->tc_ref--;
2956 lcmd->tc_writer = TLM_STOP;
2957 return (NULL);
2958 }
2959
2960
2961 /*
2962 * mover_tape_writer_one_buf
2963 *
2964 * Write one buffer for the mover to the local tape device. This is
2965 * used by mover_tape_writer thread.
2966 *
2967 * Parameters:
2968 * session (input) - session pointer.
2969 * buf (input) - buffer read
2970 *
2971 * Returns:
2972 * 0: on success
2973 * -1: otherwise
2974 */
2975 static int
mover_tape_write_one_buf(ndmpd_session_t * session,tlm_buffer_t * buf)2976 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2977 {
2978 int n;
2979
2980 NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2981 " errno: %d, size: %d, data: 0x%x",
2982 buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2983 buf->tb_buffer_size, buf->tb_buffer_data);
2984
2985 n = mover_tape_write_v3(session, buf->tb_buffer_data,
2986 buf->tb_buffer_size);
2987
2988 NDMP_LOG(LOG_DEBUG, "n: %d", n);
2989
2990 if (n <= 0) {
2991 ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
2992 : NDMP_MOVER_HALT_INTERNAL_ERROR));
2993 return (-1);
2994 }
2995 session->ns_mover.md_position += n;
2996 session->ns_mover.md_data_written += n;
2997 session->ns_mover.md_record_num++;
2998
2999 NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
3000 tlm_buffer_mark_empty(buf);
3001
3002 return (0);
3003 }
3004
3005
3006 /*
3007 * mover_tape_writer
3008 *
3009 * Mover tape writer thread. This is used for performing remote backups
3010 * in a 3-way configuration. It writes the data from network socket to
3011 * the locally attached tape device.
3012 *
3013 * Parameters:
3014 * session (input) - session pointer.
3015 *
3016 * Returns:
3017 * 0: on success
3018 * -1: otherwise
3019 */
3020 void *
mover_tape_writer(void * ptr)3021 mover_tape_writer(void *ptr)
3022 {
3023 int bidx;
3024 ndmp_lbr_params_t *nlp;
3025 tlm_buffer_t *buf;
3026 tlm_buffers_t *bufs;
3027 tlm_cmd_t *lcmd;
3028 tlm_commands_t *cmds;
3029 ndmpd_session_t *session = ptr;
3030 static int nw = 0;
3031
3032 if ((nlp = ndmp_get_nlp(session)) == NULL) {
3033 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3034 return ((void *)(uintptr_t)-1);
3035 }
3036
3037 cmds = &nlp->nlp_cmds;
3038 lcmd = cmds->tcs_command;
3039 bufs = lcmd->tc_buffers;
3040
3041 lcmd->tc_ref++;
3042 cmds->tcs_writer_count++;
3043
3044 /*
3045 * Let our parent thread know that we are running.
3046 */
3047 tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3048
3049 bidx = bufs->tbs_buffer_out;
3050 buf = &bufs->tbs_buffer[bidx];
3051 while (cmds->tcs_writer != (int)TLM_ABORT &&
3052 lcmd->tc_writer != (int)TLM_ABORT) {
3053 if (buf->tb_full) {
3054 NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3055
3056 if (mover_tape_write_one_buf(session, buf) < 0) {
3057 NDMP_LOG(LOG_DEBUG,
3058 "mover_tape_write_one_buf() failed");
3059 break;
3060 }
3061
3062 (void) tlm_buffer_advance_out_idx(bufs);
3063 tlm_buffer_release_out_buf(bufs);
3064 bidx = bufs->tbs_buffer_out;
3065 buf = &bufs->tbs_buffer[bidx];
3066 } else {
3067 if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3068 /* No more data is coming, time to exit */
3069 NDMP_LOG(LOG_DEBUG, "Time to exit");
3070 break;
3071 }
3072 NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3073 /*
3074 * The buffer is not full, wait for the producer
3075 * thread to fill it.
3076 */
3077 tlm_buffer_in_buf_timed_wait(bufs, 100);
3078 }
3079 }
3080
3081 if (cmds->tcs_writer == (int)TLM_ABORT)
3082 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3083 if (lcmd->tc_writer == (int)TLM_ABORT)
3084 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3085 NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3086
3087 if (buf->tb_errno == 0) {
3088 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3089 } else {
3090 NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3091 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3092 }
3093
3094 /* If the producer is waiting for us, wake it up. */
3095 tlm_buffer_release_out_buf(bufs);
3096
3097 /*
3098 * Clean up.
3099 */
3100 cmds->tcs_writer_count--;
3101 lcmd->tc_ref--;
3102 lcmd->tc_reader = TLM_STOP;
3103 return (NULL);
3104 }
3105
3106
3107 /*
3108 * start_mover_for_backup
3109 *
3110 * Starts a remote backup by running socket reader and tape
3111 * writer threads. The mover runs a remote backup in a 3-way backup
3112 * configuration.
3113 *
3114 * Parameters:
3115 * session (input) - session pointer.
3116 *
3117 * Returns:
3118 * 0: on success
3119 * -1: otherwise
3120 */
3121 static int
start_mover_for_backup(ndmpd_session_t * session)3122 start_mover_for_backup(ndmpd_session_t *session)
3123 {
3124 ndmp_lbr_params_t *nlp;
3125 tlm_commands_t *cmds;
3126 int rc;
3127
3128 if ((nlp = ndmp_get_nlp(session)) == NULL) {
3129 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3130 return (-1);
3131 }
3132
3133 cmds = &nlp->nlp_cmds;
3134 (void) memset(cmds, 0, sizeof (*cmds));
3135 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3136 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3137 session->ns_mover.md_record_size);
3138 if (cmds->tcs_command == NULL)
3139 return (-1);
3140
3141 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3142 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3143
3144 /*
3145 * We intentionally don't wait for the threads to start since the
3146 * reply of the request (which resulted in calling this function)
3147 * must be sent to the client before probable errors are sent
3148 * to the client.
3149 */
3150 rc = pthread_create(NULL, NULL, mover_socket_reader, session);
3151 if (rc == 0) {
3152 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3153 } else {
3154 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3155 strerror(rc));
3156 return (-1);
3157 }
3158
3159 rc = pthread_create(NULL, NULL, mover_tape_writer, session);
3160 if (rc == 0) {
3161 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3162 } else {
3163 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3164 strerror(rc));
3165 return (-1);
3166 }
3167
3168 tlm_release_reader_writer_ipc(cmds->tcs_command);
3169 return (0);
3170 }
3171
3172
3173 /*
3174 * is_writer_running
3175 *
3176 * Find out if the writer thread has started or not.
3177 *
3178 * Parameters:
3179 * session (input) - session pointer.
3180 *
3181 * Returns:
3182 * 0: not started
3183 * non-zero: started
3184 * Note: non-zero is also returned if the backup type is
3185 * neither TAR nor DUMP. I.e. the is_writer_running()
3186 * check does not apply in this case and things should
3187 * appear successful.
3188 */
3189 static boolean_t
is_writer_running(ndmpd_session_t * session)3190 is_writer_running(ndmpd_session_t *session)
3191 {
3192 boolean_t rv;
3193 ndmp_lbr_params_t *nlp;
3194
3195 if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3196 return (1);
3197
3198 if (session == NULL)
3199 rv = 0;
3200 else if ((nlp = ndmp_get_nlp(session)) == NULL)
3201 rv = 0;
3202 else
3203 rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3204
3205 return (rv);
3206 }
3207
3208
3209 /*
3210 * is_writer_running_v3
3211 *
3212 * Find out if the writer thread has started or not.
3213 *
3214 * Parameters:
3215 * session (input) - session pointer.
3216 *
3217 * Returns:
3218 * 0: not started
3219 * non-zero: started
3220 * Note: non-zero is also returned if the backup type is
3221 * neither TAR nor DUMP. I.e. the is_writer_running()
3222 * check does not apply in this case and things should
3223 * appear successful.
3224 */
3225 static boolean_t
is_writer_running_v3(ndmpd_session_t * session)3226 is_writer_running_v3(ndmpd_session_t *session)
3227 {
3228 boolean_t rv;
3229 ndmp_lbr_params_t *nlp;
3230
3231 if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3232 return (1);
3233
3234 if (session == NULL)
3235 rv = 0;
3236 else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3237 rv = 1;
3238 else if ((nlp = ndmp_get_nlp(session)) == NULL)
3239 rv = 0;
3240 else
3241 rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3242
3243 return (rv);
3244 }
3245
3246
3247 /*
3248 * ndmpd_mover_error_send
3249 *
3250 * This function sends the notify message to the client.
3251 *
3252 * Parameters:
3253 * session (input) - session pointer.
3254 * reason (input) - halt reason.
3255 *
3256 * Returns:
3257 * Error code
3258 */
3259 int
ndmpd_mover_error_send(ndmpd_session_t * session,ndmp_mover_halt_reason reason)3260 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3261 {
3262 ndmp_notify_mover_halted_request req;
3263
3264 req.reason = reason;
3265 req.text_reason = "";
3266
3267 return (ndmp_send_request(session->ns_connection,
3268 NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3269 }
3270
3271
3272 /*
3273 * ndmpd_mover_error_send_v4
3274 *
3275 * This function sends the notify message to the client.
3276 *
3277 * Parameters:
3278 * session (input) - session pointer.
3279 * reason (input) - halt reason.
3280 *
3281 * Returns:
3282 * Error code
3283 */
3284 int
ndmpd_mover_error_send_v4(ndmpd_session_t * session,ndmp_mover_halt_reason reason)3285 ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3286 ndmp_mover_halt_reason reason)
3287 {
3288 ndmp_notify_mover_halted_request_v4 req;
3289
3290 req.reason = reason;
3291
3292 return (ndmp_send_request(session->ns_connection,
3293 NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3294 }
3295
3296
3297 /*
3298 * ndmpd_mover_error
3299 *
3300 * This function is called when an unrecoverable mover error
3301 * has been detected. A notify message is sent to the client and the
3302 * mover is placed into the halted state.
3303 *
3304 * Parameters:
3305 * session (input) - session pointer.
3306 * reason (input) - halt reason.
3307 *
3308 * Returns:
3309 * void.
3310 */
3311 void
ndmpd_mover_error(ndmpd_session_t * session,ndmp_mover_halt_reason reason)3312 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3313 {
3314 ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3315
3316 if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3317 (session->ns_protocol_version > NDMPV2 &&
3318 session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3319 return;
3320
3321 if (session->ns_protocol_version == NDMPV4) {
3322 if (ndmpd_mover_error_send_v4(session, reason) < 0)
3323 NDMP_LOG(LOG_DEBUG,
3324 "Error sending notify_mover_halted request");
3325 } else {
3326 /* No media error in V3 */
3327 if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3328 reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3329 if (ndmpd_mover_error_send(session, reason) < 0)
3330 NDMP_LOG(LOG_DEBUG,
3331 "Error sending notify_mover_halted request");
3332 }
3333
3334 (void) mutex_lock(&nlp->nlp_mtx);
3335 if (session->ns_mover.md_listen_sock != -1) {
3336 (void) ndmpd_remove_file_handler(session,
3337 session->ns_mover.md_listen_sock);
3338 (void) close(session->ns_mover.md_listen_sock);
3339 session->ns_mover.md_listen_sock = -1;
3340 }
3341 if (session->ns_mover.md_sock != -1) {
3342 (void) ndmpd_remove_file_handler(session,
3343 session->ns_mover.md_sock);
3344 (void) close(session->ns_mover.md_sock);
3345 session->ns_mover.md_sock = -1;
3346 }
3347
3348 session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3349 session->ns_mover.md_halt_reason = reason;
3350 (void) cond_broadcast(&nlp->nlp_cv);
3351 (void) mutex_unlock(&nlp->nlp_mtx);
3352 }
3353
3354
3355 /*
3356 * mover_pause_v3
3357 *
3358 * Send an ndmp_notify_mover_paused request to the
3359 * NDMP client to inform the client that its attention is required.
3360 * Process messages until the data/mover operation is either aborted
3361 * or continued.
3362 *
3363 * Parameters:
3364 * client_data (input) - session pointer.
3365 * reason (input) - pause reason.
3366 *
3367 * Returns:
3368 * 0 - operation has been continued.
3369 * -1 - operation has been aborted.
3370 */
3371 static int
mover_pause_v3(ndmpd_session_t * session,ndmp_mover_pause_reason reason)3372 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3373 {
3374 int rv;
3375 ndmp_notify_mover_paused_request request;
3376
3377 rv = 0;
3378 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3379 session->ns_mover.md_pause_reason = reason;
3380 session->ns_mover.md_pre_cond = FALSE;
3381
3382 request.reason = session->ns_mover.md_pause_reason;
3383 request.seek_position =
3384 long_long_to_quad(session->ns_mover.md_position);
3385
3386 if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3387 NDMP_NO_ERR, (void *)&request, 0) < 0) {
3388 NDMP_LOG(LOG_DEBUG,
3389 "Error sending notify_mover_paused_request");
3390 return (-1);
3391 }
3392
3393 /*
3394 * 3-way operations are single-thread. The same thread
3395 * should process the messages.
3396 *
3397 * 2-way operations are multi-thread. The main thread
3398 * processes the messages. We just need to wait and
3399 * see if the mover state changes or the operation aborts.
3400 */
3401 if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3402 /*
3403 * Process messages until the state is changed by
3404 * an abort, continue, or close request .
3405 */
3406 for (; ; ) {
3407 if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3408 return (-1);
3409
3410 if (session->ns_eof == TRUE)
3411 return (-1);
3412
3413 switch (session->ns_mover.md_state) {
3414 case NDMP_MOVER_STATE_ACTIVE:
3415 session->ns_tape.td_record_count = 0;
3416 return (0);
3417
3418 case NDMP_MOVER_STATE_PAUSED:
3419 continue;
3420
3421 default:
3422 return (-1);
3423 }
3424 }
3425
3426 } else {
3427 if (session->ns_mover.md_data_addr.addr_type ==
3428 NDMP_ADDR_LOCAL) {
3429 rv = ndmp_wait_for_mover(session);
3430 } else {
3431 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3432 session->ns_mover.md_data_addr.addr_type);
3433 rv = -1;
3434 }
3435 }
3436
3437 return (rv);
3438 }
3439
3440
3441 /*
3442 * mover_tape_write_v3
3443 *
3444 * Writes a data record to tape. Detects and handles EOT conditions.
3445 *
3446 * Parameters:
3447 * session (input) - session pointer.
3448 * data (input) - data to be written.
3449 * length (input) - length of data to be written.
3450 *
3451 * Returns:
3452 * 0 - operation aborted by client.
3453 * -1 - error.
3454 * otherwise - number of bytes written.
3455 */
3456 static int
mover_tape_write_v3(ndmpd_session_t * session,char * data,ssize_t length)3457 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3458 {
3459 ssize_t n;
3460 ssize_t count = length;
3461
3462 while (count > 0) {
3463 /*
3464 * Enforce mover window on write.
3465 */
3466 if (session->ns_mover.md_position >=
3467 session->ns_mover.md_window_offset +
3468 session->ns_mover.md_window_length) {
3469 NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3470
3471 if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3472 /* Operation aborted or connection terminated */
3473 return (-1);
3474
3475 }
3476
3477 n = write(session->ns_tape.td_fd, data, count);
3478 if (n < 0) {
3479 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3480 return (-1);
3481 } else if (n > 0) {
3482 NS_ADD(wtape, n);
3483 count -= n;
3484 data += n;
3485 session->ns_tape.td_record_count++;
3486 }
3487
3488 /* EOM handling */
3489 if (count > 0) {
3490 struct mtget mtstatus;
3491
3492 (void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3493 &mtstatus);
3494 NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
3495 "mover record %d, file #%d, block #%d)", n,
3496 session->ns_tape.td_record_count,
3497 mtstatus.mt_fileno, mtstatus.mt_blkno);
3498
3499 /*
3500 * Notify the client to either abort the operation
3501 * or change the tape.
3502 */
3503 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3504 ++ndmp_log_msg_id,
3505 "End of tape reached. Load next tape");
3506
3507 if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3508 /* Operation aborted or connection terminated */
3509 return (-1);
3510 }
3511 }
3512
3513 return (length);
3514 }
3515
3516
3517 /*
3518 * mover_tape_flush_v3
3519 *
3520 * Writes all remaining buffered data to tape. A partial record is
3521 * padded out to a full record with zeros.
3522 *
3523 * Parameters:
3524 * session (input) - session pointer.
3525 * data (input) - data to be written.
3526 * length (input) - length of data to be written.
3527 *
3528 * Returns:
3529 * -1 - error.
3530 * otherwise - number of bytes written.
3531 */
3532 static int
mover_tape_flush_v3(ndmpd_session_t * session)3533 mover_tape_flush_v3(ndmpd_session_t *session)
3534 {
3535 int n;
3536
3537 if (session->ns_mover.md_w_index == 0)
3538 return (0);
3539
3540 (void) memset((void*)&session->ns_mover.md_buf[session->
3541 ns_mover.md_w_index], 0,
3542 session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3543
3544 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3545 session->ns_mover.md_record_size);
3546 if (n < 0) {
3547 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3548 return (-1);
3549 }
3550
3551 session->ns_mover.md_w_index = 0;
3552 session->ns_mover.md_position += n;
3553 return (n);
3554 }
3555
3556
3557 /*
3558 * ndmpd_local_write_v3
3559 *
3560 * Buffers and writes data to the tape device.
3561 * A full tape record is buffered before being written.
3562 *
3563 * Parameters:
3564 * session (input) - session pointer.
3565 * data (input) - data to be written.
3566 * length (input) - data length.
3567 *
3568 * Returns:
3569 * 0 - data successfully written.
3570 * -1 - error.
3571 */
3572 int
ndmpd_local_write_v3(ndmpd_session_t * session,char * data,ulong_t length)3573 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3574 {
3575 ulong_t count = 0;
3576 ssize_t n;
3577 ulong_t len;
3578
3579 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3580 session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3581 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3582 NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3583 return (-1);
3584 }
3585
3586 /*
3587 * A length of 0 indicates that any buffered data should be
3588 * flushed to tape.
3589 */
3590 if (length == 0) {
3591 if (session->ns_mover.md_w_index == 0)
3592 return (0);
3593
3594 (void) memset((void*)&session->ns_mover.md_buf[session->
3595 ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3596 session->ns_mover.md_w_index);
3597
3598 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3599 session->ns_mover.md_record_size);
3600 if (n <= 0) {
3601 ndmpd_mover_error(session,
3602 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3603 NDMP_MOVER_HALT_MEDIA_ERROR));
3604 return (-1);
3605 }
3606
3607 session->ns_mover.md_position += n;
3608 session->ns_mover.md_data_written +=
3609 session->ns_mover.md_w_index;
3610 session->ns_mover.md_record_num++;
3611 session->ns_mover.md_w_index = 0;
3612 return (0);
3613 }
3614
3615 /* Break the data into records. */
3616 while (count < length) {
3617 /*
3618 * Determine if data needs to be buffered or
3619 * can be written directly from user supplied location.
3620 * We can fast path the write if there is no pending
3621 * buffered data and there is at least a full records worth
3622 * of data to be written.
3623 */
3624 if (session->ns_mover.md_w_index == 0 &&
3625 length - count >= session->ns_mover.md_record_size) {
3626 n = mover_tape_write_v3(session, &data[count],
3627 session->ns_mover.md_record_size);
3628 if (n <= 0) {
3629 ndmpd_mover_error(session,
3630 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3631 NDMP_MOVER_HALT_MEDIA_ERROR));
3632 return (-1);
3633 }
3634
3635 session->ns_mover.md_position += n;
3636 session->ns_mover.md_data_written += n;
3637 session->ns_mover.md_record_num++;
3638 count += n;
3639 continue;
3640 }
3641
3642 /* Buffer the data */
3643 len = length - count;
3644 if (len > session->ns_mover.md_record_size -
3645 session->ns_mover.md_w_index)
3646 len = session->ns_mover.md_record_size -
3647 session->ns_mover.md_w_index;
3648
3649 (void) memcpy(&session->ns_mover.md_buf[session->
3650 ns_mover.md_w_index], &data[count], len);
3651 session->ns_mover.md_w_index += len;
3652 count += len;
3653
3654 /* Write the buffer if its full */
3655 if (session->ns_mover.md_w_index ==
3656 session->ns_mover.md_record_size) {
3657 n = mover_tape_write_v3(session,
3658 session->ns_mover.md_buf,
3659 session->ns_mover.md_record_size);
3660 if (n <= 0) {
3661 ndmpd_mover_error(session,
3662 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3663 NDMP_MOVER_HALT_MEDIA_ERROR));
3664 return (-1);
3665 }
3666
3667 session->ns_mover.md_position += n;
3668 session->ns_mover.md_data_written += n;
3669 session->ns_mover.md_record_num++;
3670 session->ns_mover.md_w_index = 0;
3671 }
3672 }
3673
3674 return (0);
3675 }
3676
3677
3678 /*
3679 * mover_data_read_v3
3680 *
3681 * Reads backup data from the data connection and writes the
3682 * received data to the tape device.
3683 *
3684 * Parameters:
3685 * cookie (input) - session pointer.
3686 * fd (input) - file descriptor.
3687 * mode (input) - select mode.
3688 *
3689 * Returns:
3690 * void.
3691 */
3692 /*ARGSUSED*/
3693 static void
mover_data_read_v3(void * cookie,int fd,ulong_t mode)3694 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3695 {
3696 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3697 int n;
3698 ulong_t index;
3699
3700 n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3701 session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3702
3703 /*
3704 * Since this function is only called when select believes data
3705 * is available to be read, a return of zero indicates the
3706 * connection has been closed.
3707 */
3708 if (n <= 0) {
3709 if (n == 0) {
3710 NDMP_LOG(LOG_DEBUG, "Data connection closed");
3711 ndmpd_mover_error(session,
3712 NDMP_MOVER_HALT_CONNECT_CLOSED);
3713 } else {
3714 /* Socket is non-blocking, perhaps there are no data */
3715 if (errno == EAGAIN) {
3716 NDMP_LOG(LOG_ERR, "No data to read");
3717 return;
3718 }
3719
3720 NDMP_LOG(LOG_ERR, "Failed to read from socket: %m");
3721 ndmpd_mover_error(session,
3722 NDMP_MOVER_HALT_INTERNAL_ERROR);
3723 }
3724
3725 /* Save the index since mover_tape_flush_v3 resets it. */
3726 index = session->ns_mover.md_w_index;
3727
3728 /* Flush any buffered data to tape. */
3729 if (mover_tape_flush_v3(session) > 0) {
3730 session->ns_mover.md_data_written += index;
3731 session->ns_mover.md_record_num++;
3732 }
3733
3734 return;
3735 }
3736
3737 NDMP_LOG(LOG_DEBUG, "n %d", n);
3738
3739 session->ns_mover.md_w_index += n;
3740
3741 if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3742 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3743 session->ns_mover.md_record_size);
3744 if (n <= 0) {
3745 ndmpd_mover_error(session,
3746 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3747 NDMP_MOVER_HALT_MEDIA_ERROR));
3748 return;
3749 }
3750
3751 session->ns_mover.md_position += n;
3752 session->ns_mover.md_w_index = 0;
3753 session->ns_mover.md_data_written += n;
3754 session->ns_mover.md_record_num++;
3755 }
3756 }
3757
3758 /*
3759 * mover_tape_read_v3
3760 *
3761 * Reads a data record from tape. Detects and handles EOT conditions.
3762 *
3763 * Parameters:
3764 * session (input) - session pointer.
3765 * data (input) - location to read data to.
3766 *
3767 * Returns:
3768 * 0 - operation aborted.
3769 * TAPE_READ_ERR - tape read IO error.
3770 * TAPE_NO_WRITER_ERR - no writer is running during tape read
3771 * otherwise - number of bytes read.
3772 */
3773 static int
mover_tape_read_v3(ndmpd_session_t * session,char * data)3774 mover_tape_read_v3(ndmpd_session_t *session, char *data)
3775 {
3776 int pause_reason;
3777 ssize_t n;
3778 int err;
3779 int count;
3780
3781 count = session->ns_mover.md_record_size;
3782 while (count > 0) {
3783 pause_reason = NDMP_MOVER_PAUSE_NA;
3784
3785 n = read(session->ns_tape.td_fd, data, count);
3786 if (n < 0) {
3787 /*
3788 * If at beginning of file and read fails with EIO,
3789 * then it's repeated attempt to read at EOT.
3790 */
3791 if (errno == EIO && tape_is_at_bof(session)) {
3792 NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
3793 pause_reason = NDMP_MOVER_PAUSE_EOM;
3794 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3795 ++ndmp_log_msg_id,
3796 "End of tape reached. Load next tape");
3797 }
3798 /*
3799 * According to NDMPv4 spec preferred error code when
3800 * trying to read from blank tape is NDMP_EOM_ERR.
3801 */
3802 else if (errno == EIO && tape_is_at_bot(session)) {
3803 NDMP_LOG(LOG_ERR,
3804 "Blank tape detected, returning EOM");
3805 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3806 ++ndmp_log_msg_id,
3807 "Blank tape. Load another tape");
3808 pause_reason = NDMP_MOVER_PAUSE_EOM;
3809 } else {
3810 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
3811 return (TAPE_READ_ERR);
3812 }
3813 } else if (n > 0) {
3814 NS_ADD(rtape, n);
3815 data += n;
3816 count -= n;
3817 session->ns_tape.td_record_count++;
3818 } else {
3819 if (!is_writer_running_v3(session))
3820 return (TAPE_NO_WRITER_ERR);
3821
3822 /*
3823 * End of file or media reached. Notify client and
3824 * wait for the client to either abort the data
3825 * operation or continue the operation after changing
3826 * the tape.
3827 */
3828 if (tape_is_at_bof(session)) {
3829 NDMP_LOG(LOG_DEBUG, "EOT detected");
3830 pause_reason = NDMP_MOVER_PAUSE_EOM;
3831 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3832 ++ndmp_log_msg_id, "End of medium reached");
3833 } else {
3834 NDMP_LOG(LOG_DEBUG, "EOF detected");
3835 /* reposition the tape to BOT side of FM */
3836 fm_dance(session);
3837 pause_reason = NDMP_MOVER_PAUSE_EOF;
3838 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3839 ++ndmp_log_msg_id, "End of file reached.");
3840 }
3841 }
3842
3843 if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3844 err = mover_pause_v3(session, pause_reason);
3845
3846 /* Operation aborted or connection terminated? */
3847 if (err < 0) {
3848 return (0);
3849 }
3850 /* Retry the read from new location */
3851 }
3852 }
3853 return (session->ns_mover.md_record_size);
3854 }
3855
3856
3857 /*
3858 * mover_data_write_v3
3859 *
3860 * Reads backup data from the tape device and writes the
3861 * data to the data connection.
3862 * This function is called by ndmpd_select when the data connection
3863 * is ready for more data to be written.
3864 *
3865 * Parameters:
3866 * cookie (input) - session pointer.
3867 * fd (input) - file descriptor.
3868 * mode (input) - select mode.
3869 *
3870 * Returns:
3871 * void.
3872 */
3873 /*ARGSUSED*/
3874 static void
mover_data_write_v3(void * cookie,int fd,ulong_t mode)3875 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3876 {
3877 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3878 int n;
3879 ulong_t len;
3880 u_longlong_t wlen;
3881 ndmp_notify_mover_paused_request pause_request;
3882
3883 /*
3884 * If the end of the mover window has been reached,
3885 * then notify the client that a seek is needed.
3886 * Remove the file handler to prevent this function from
3887 * being called. The handler will be reinstalled in
3888 * ndmpd_mover_continue.
3889 */
3890 if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3891 + session->ns_mover.md_window_length) {
3892 NDMP_LOG(LOG_DEBUG,
3893 "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3894
3895 session->ns_mover.md_w_index = 0;
3896 session->ns_mover.md_r_index = 0;
3897
3898 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3899 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3900 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3901 pause_request.seek_position =
3902 long_long_to_quad(session->ns_mover.md_position);
3903 session->ns_mover.md_seek_position =
3904 session->ns_mover.md_position;
3905
3906 (void) ndmpd_remove_file_handler(session, fd);
3907
3908 if (ndmp_send_request(session->ns_connection,
3909 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
3910 (void *)&pause_request, 0) < 0) {
3911 NDMP_LOG(LOG_DEBUG,
3912 "Sending notify_mover_paused request");
3913 ndmpd_mover_error(session,
3914 NDMP_MOVER_HALT_INTERNAL_ERROR);
3915 }
3916 return;
3917 }
3918
3919 /*
3920 * Read more data into the tape buffer if the buffer is empty.
3921 */
3922 if (session->ns_mover.md_w_index == 0) {
3923 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
3924
3925 NDMP_LOG(LOG_DEBUG,
3926 "read %u bytes from tape", n);
3927
3928 if (n <= 0) {
3929 ndmpd_mover_error(session, (n == 0 ?
3930 NDMP_MOVER_HALT_ABORTED
3931 : NDMP_MOVER_HALT_MEDIA_ERROR));
3932 return;
3933 }
3934
3935 /*
3936 * Discard data if the current data stream position is
3937 * prior to the seek position. This is necessary if a seek
3938 * request set the seek pointer to a position that is not a
3939 * record boundary. The seek request handler can only position
3940 * to the start of a record.
3941 */
3942 if (session->ns_mover.md_position <
3943 session->ns_mover.md_seek_position) {
3944 session->ns_mover.md_r_index =
3945 session->ns_mover.md_seek_position -
3946 session->ns_mover.md_position;
3947 session->ns_mover.md_position =
3948 session->ns_mover.md_seek_position;
3949 }
3950
3951 session->ns_mover.md_w_index = n;
3952 session->ns_mover.md_record_num++;
3953 }
3954
3955 /*
3956 * The limit on the total amount of data to be sent can be
3957 * dictated by either the end of the mover window or the end of the
3958 * seek window.
3959 * First determine which window applies and then determine if the
3960 * send length needs to be less than a full record to avoid
3961 * exceeding the window.
3962 */
3963 if (session->ns_mover.md_position +
3964 session->ns_mover.md_bytes_left_to_read >
3965 session->ns_mover.md_window_offset +
3966 session->ns_mover.md_window_length)
3967 wlen = session->ns_mover.md_window_offset +
3968 session->ns_mover.md_window_length -
3969 session->ns_mover.md_position;
3970 else
3971 wlen = session->ns_mover.md_bytes_left_to_read;
3972
3973 NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
3974
3975 /*
3976 * Now limit the length to the amount of data in the buffer.
3977 */
3978 if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
3979 wlen = session->ns_mover.md_w_index -
3980 session->ns_mover.md_r_index;
3981
3982 len = wlen & 0xffffffff;
3983 NDMP_LOG(LOG_DEBUG,
3984 "buffer restrictions: wlen %llu len %u", wlen, len);
3985
3986 /*
3987 * Write the data to the data connection.
3988 */
3989 n = write(session->ns_mover.md_sock,
3990 &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
3991
3992 if (n < 0) {
3993 /* Socket is non-blocking, perhaps the write queue is full */
3994 if (errno == EAGAIN) {
3995 NDMP_LOG(LOG_ERR, "Cannot write to socket");
3996 return;
3997 }
3998 NDMP_LOG(LOG_ERR, "Failed to write to socket: %m");
3999 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4000 return;
4001 }
4002
4003 NDMP_LOG(LOG_DEBUG,
4004 "wrote %u of %u bytes to data connection position %llu r_index %lu",
4005 n, len, session->ns_mover.md_position,
4006 session->ns_mover.md_r_index);
4007
4008 session->ns_mover.md_r_index += n;
4009 session->ns_mover.md_position += n;
4010 session->ns_mover.md_bytes_left_to_read -= n;
4011
4012 /*
4013 * If all data in the buffer has been written,
4014 * zero the buffer indices. The next call to this function
4015 * will read more data from the tape device into the buffer.
4016 */
4017 if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4018 session->ns_mover.md_r_index = 0;
4019 session->ns_mover.md_w_index = 0;
4020 }
4021
4022 /*
4023 * If the read limit has been reached,
4024 * then remove the file handler to prevent this
4025 * function from getting called. The next mover_read request
4026 * will reinstall the handler.
4027 */
4028 if (session->ns_mover.md_bytes_left_to_read == 0)
4029 (void) ndmpd_remove_file_handler(session, fd);
4030 }
4031
4032
4033 /*
4034 * accept_connection_v3
4035 *
4036 * Accept a data connection from a data server.
4037 * Called by ndmpd_select when a connection is pending on
4038 * the mover listen socket.
4039 *
4040 * Parameters:
4041 * cookie (input) - session pointer.
4042 * fd (input) - file descriptor.
4043 * mode (input) - select mode.
4044 *
4045 * Returns:
4046 * void.
4047 */
4048 /*ARGSUSED*/
4049 static void
accept_connection_v3(void * cookie,int fd,ulong_t mode)4050 accept_connection_v3(void *cookie, int fd, ulong_t mode)
4051 {
4052 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4053 int from_len;
4054 struct sockaddr_in from;
4055
4056 from_len = sizeof (from);
4057 session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4058 &from_len);
4059
4060 NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4061 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4062
4063 (void) ndmpd_remove_file_handler(session, fd);
4064 (void) close(session->ns_mover.md_listen_sock);
4065 session->ns_mover.md_listen_sock = -1;
4066
4067 if (session->ns_mover.md_sock < 0) {
4068 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4069 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4070 return;
4071 }
4072
4073 /*
4074 * Save the peer address.
4075 */
4076 session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4077 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4078
4079 /* Set the parameter of the new socket */
4080 set_socket_options(session->ns_mover.md_sock);
4081
4082 /*
4083 * Backup/restore is handled by a callback called from main event loop,
4084 * which reads/writes data to md_sock socket. IO on socket must be
4085 * non-blocking, otherwise ndmpd would be unable to process other
4086 * incoming requests.
4087 */
4088 if (!set_socket_nonblock(session->ns_mover.md_sock)) {
4089 NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4090 "on socket: %m");
4091 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4092 return;
4093 }
4094
4095 NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4096
4097 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4098 if (ndmpd_add_file_handler(session, (void*)session,
4099 session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4100 HC_MOVER, mover_data_read_v3) < 0) {
4101 ndmpd_mover_error(session,
4102 NDMP_MOVER_HALT_INTERNAL_ERROR);
4103 return;
4104 }
4105 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4106 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4107 ntohs(from.sin_port));
4108 } else {
4109 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4110 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4111 ntohs(from.sin_port));
4112 }
4113
4114 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4115 }
4116
4117
4118 /*
4119 * create_listen_socket_v3
4120 *
4121 * Creates a socket for listening for accepting data connections.
4122 *
4123 * Parameters:
4124 * session (input) - session pointer.
4125 * addr (output) - location to store address of socket.
4126 * port (output) - location to store port of socket.
4127 *
4128 * Returns:
4129 * 0 - success.
4130 * -1 - error.
4131 */
4132 static int
create_listen_socket_v3(ndmpd_session_t * session,ulong_t * addr,ushort_t * port)4133 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4134 {
4135 session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4136 if (session->ns_mover.md_listen_sock < 0)
4137 return (-1);
4138
4139 /*
4140 * Add a file handler for the listen socket.
4141 * ndmpd_select will call accept_connection when a
4142 * connection is ready to be accepted.
4143 */
4144 if (ndmpd_add_file_handler(session, (void *) session,
4145 session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4146 accept_connection_v3) < 0) {
4147 (void) close(session->ns_mover.md_listen_sock);
4148 session->ns_mover.md_listen_sock = -1;
4149 return (-1);
4150 }
4151 NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4152 inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4153 return (0);
4154 }
4155
4156
4157 /*
4158 * mover_connect_sock
4159 *
4160 * Connect the mover to the specified address
4161 *
4162 * Parameters:
4163 * session (input) - session pointer.
4164 * mode (input) - mover mode.
4165 * addr (output) - location to store address of socket.
4166 * port (output) - location to store port of socket.
4167 *
4168 * Returns:
4169 * error code.
4170 */
4171 static ndmp_error
mover_connect_sock(ndmpd_session_t * session,ndmp_mover_mode mode,ulong_t addr,ushort_t port)4172 mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
4173 ulong_t addr, ushort_t port)
4174 {
4175 int sock;
4176
4177 sock = ndmp_connect_sock_v3(addr, port);
4178 if (sock < 0)
4179 return (NDMP_CONNECT_ERR);
4180
4181 /*
4182 * Backup/restore is handled by a callback called from main event loop,
4183 * which reads/writes data to md_sock socket. IO on socket must be
4184 * non-blocking, otherwise ndmpd would be unable to process other
4185 * incoming requests.
4186 */
4187 if (!set_socket_nonblock(sock)) {
4188 NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4189 "on socket: %m");
4190 (void) close(sock);
4191 return (NDMP_CONNECT_ERR);
4192 }
4193
4194 if (mode == NDMP_MOVER_MODE_READ) {
4195 if (ndmpd_add_file_handler(session, (void*)session, sock,
4196 NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4197 (void) close(sock);
4198 return (NDMP_CONNECT_ERR);
4199 }
4200 }
4201 session->ns_mover.md_sock = sock;
4202 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4203 session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4204 session->ns_mover.md_data_addr.tcp_port_v3 = port;
4205 return (NDMP_NO_ERR);
4206 }
4207
4208
4209 /*
4210 * ndmpd_local_read_v3
4211 *
4212 * Reads data from the local tape device.
4213 * Full tape records are read and buffered.
4214 *
4215 * Parameters:
4216 * session (input) - session pointer.
4217 * data (input) - location to store data.
4218 * length (input) - data length.
4219 *
4220 * Returns:
4221 * 1 - no read error but no writer running
4222 * 0 - data successfully read.
4223 * -1 - error.
4224 */
4225 int
ndmpd_local_read_v3(ndmpd_session_t * session,char * data,ulong_t length)4226 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4227 {
4228 ulong_t count;
4229 ulong_t len;
4230 ssize_t n;
4231
4232 count = 0;
4233 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4234 session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4235 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4236 NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4237 return (-1);
4238 }
4239
4240 /*
4241 * Automatically increase the seek window if necessary.
4242 * This is needed in the event the module attempts to read
4243 * past a seek window set via a prior call to ndmpd_seek() or
4244 * the module has not issued a seek. If no seek was issued then
4245 * pretend that a seek was issued to read the entire tape.
4246 */
4247 if (length > session->ns_mover.md_bytes_left_to_read) {
4248 /* ndmpd_seek() never called? */
4249 if (session->ns_data.dd_read_length == 0) {
4250 session->ns_mover.md_bytes_left_to_read = ~0LL;
4251 session->ns_data.dd_read_offset = 0LL;
4252 session->ns_data.dd_read_length = ~0LL;
4253 } else {
4254 session->ns_mover.md_bytes_left_to_read = length;
4255 session->ns_data.dd_read_offset =
4256 session->ns_mover.md_position;
4257 session->ns_data.dd_read_length = length;
4258 }
4259 }
4260
4261 /*
4262 * Read as many records as necessary to satisfy the request.
4263 */
4264 while (count < length) {
4265 /*
4266 * If the end of the mover window has been reached,
4267 * then notify the client that a new data window is needed.
4268 */
4269 if (session->ns_mover.md_position >=
4270 session->ns_mover.md_window_offset +
4271 session->ns_mover.md_window_length) {
4272 if (mover_pause_v3(session,
4273 NDMP_MOVER_PAUSE_SEEK) < 0) {
4274 ndmpd_mover_error(session,
4275 NDMP_MOVER_HALT_INTERNAL_ERROR);
4276 return (-1);
4277 }
4278 continue;
4279 }
4280
4281 len = length - count;
4282
4283 /*
4284 * Prevent reading past the end of the window.
4285 */
4286 if (len > session->ns_mover.md_window_offset +
4287 session->ns_mover.md_window_length -
4288 session->ns_mover.md_position)
4289 len = session->ns_mover.md_window_offset +
4290 session->ns_mover.md_window_length -
4291 session->ns_mover.md_position;
4292
4293 /*
4294 * Copy from the data buffer first.
4295 */
4296 if (session->ns_mover.md_w_index -
4297 session->ns_mover.md_r_index != 0) {
4298 /*
4299 * Limit the copy to the amount of data in the buffer.
4300 */
4301 if (len > session->ns_mover.md_w_index -
4302 session->ns_mover.md_r_index)
4303 len = session->ns_mover.md_w_index -
4304 session->ns_mover.md_r_index;
4305 (void) memcpy((void*)&data[count],
4306 &session->ns_mover.md_buf[session->
4307 ns_mover.md_r_index], len);
4308 count += len;
4309 session->ns_mover.md_r_index += len;
4310 session->ns_mover.md_bytes_left_to_read -= len;
4311 session->ns_mover.md_position += len;
4312 continue;
4313 }
4314
4315 /*
4316 * Determine if data needs to be buffered or
4317 * can be read directly to user supplied location.
4318 * We can fast path the read if at least a full record
4319 * needs to be read and there is no seek pending.
4320 * This is done to eliminate a buffer copy.
4321 */
4322 if (len >= session->ns_mover.md_record_size &&
4323 session->ns_mover.md_position >=
4324 session->ns_mover.md_seek_position) {
4325 n = mover_tape_read_v3(session, &data[count]);
4326 if (n <= 0) {
4327 if (n == TAPE_NO_WRITER_ERR)
4328 return (1);
4329
4330 ndmpd_mover_error(session,
4331 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4332 NDMP_MOVER_HALT_MEDIA_ERROR));
4333 return ((n == 0) ? 1 : -1);
4334 }
4335
4336 count += n;
4337 session->ns_mover.md_bytes_left_to_read -= n;
4338 session->ns_mover.md_position += n;
4339 session->ns_mover.md_record_num++;
4340 continue;
4341 }
4342
4343 /* Read the next record into the buffer. */
4344 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4345 if (n <= 0) {
4346 if (n == TAPE_NO_WRITER_ERR)
4347 return (1);
4348
4349 ndmpd_mover_error(session,
4350 (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4351 NDMP_MOVER_HALT_MEDIA_ERROR));
4352 return ((n == 0) ? 1 : -1);
4353 }
4354
4355 session->ns_mover.md_w_index = n;
4356 session->ns_mover.md_r_index = 0;
4357 session->ns_mover.md_record_num++;
4358
4359 NDMP_LOG(LOG_DEBUG, "n: %d", n);
4360
4361 /*
4362 * Discard data if the current data stream position is
4363 * prior to the seek position. This is necessary if a seek
4364 * request set the seek pointer to a position that is not a
4365 * record boundary. The seek request handler can only position
4366 * to the start of a record.
4367 */
4368 if (session->ns_mover.md_position <
4369 session->ns_mover.md_seek_position) {
4370 session->ns_mover.md_r_index =
4371 session->ns_mover.md_seek_position -
4372 session->ns_mover.md_position;
4373 session->ns_mover.md_position =
4374 session->ns_mover.md_seek_position;
4375 }
4376 }
4377
4378 return (0);
4379 }
4380