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