2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
8 * Copyright (c) 2007, The Storage Networking Industry Association.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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
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
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.
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. */
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>
55 #include "ndmpd_common.h"
60 * Maximum mover record size
62 #define MAX_MOVER_RECSIZE (512*KILOBYTE)
64 static int create_listen_socket_v2(ndmpd_session_t
*session
, ulong_t
*addr
,
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
,
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
,
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
,
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
,
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
);
97 int ndmp_max_mover_recsize
= MAX_MOVER_RECSIZE
; /* patchable */
99 #define TAPE_READ_ERR -1
100 #define TAPE_NO_WRITER_ERR -2
103 * Set non-blocking mode for socket.
106 set_socket_nonblock(int sock
)
110 flags
= fcntl(sock
, F_GETFL
, 0);
113 return (fcntl(sock
, F_SETFL
, flags
|O_NONBLOCK
) == 0);
117 * ************************************************************************
119 * ************************************************************************
123 * ndmpd_mover_get_state_v2
125 * This handler handles the mover_get_state request.
126 * Status information for the mover state machine is returned.
129 * connection (input) - connection handle.
130 * body (input) - request message body.
137 ndmpd_mover_get_state_v2(ndmp_connection_t
*connection
, void *body
)
139 ndmp_mover_get_state_reply_v2 reply
;
140 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
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
;
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
);
159 ndmp_send_reply(connection
, (void *) &reply
,
160 "sending tape_get_state reply");
165 * ndmpd_mover_listen_v2
167 * This handler handles mover_listen requests.
170 * connection (input) - connection handle.
171 * body (input) - request message body.
177 ndmpd_mover_listen_v2(ndmp_connection_t
*connection
, void *body
)
179 ndmp_mover_listen_request_v2
*request
;
180 ndmp_mover_listen_reply_v2 reply
;
181 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
185 request
= (ndmp_mover_listen_request_v2
*)body
;
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");
195 session
->ns_mover
.md_mode
= request
->mode
;
197 if (request
->addr_type
== NDMP_ADDR_LOCAL
) {
198 reply
.mover
.addr_type
= NDMP_ADDR_LOCAL
;
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");
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
);
211 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_LISTEN
;
214 * ndmp window should always set by client during restore
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;
222 reply
.error
= NDMP_NO_ERR
;
223 ndmp_send_reply(connection
, (void *) &reply
,
224 "sending mover_listen reply");
229 * ndmpd_mover_continue_v2
231 * This handler handles mover_continue requests.
234 * connection (input) - connection handle.
235 * body (input) - request message body.
242 ndmpd_mover_continue_v2(ndmp_connection_t
*connection
, void *body
)
244 ndmp_mover_continue_reply reply
;
245 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
247 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_PAUSED
) {
248 NDMP_LOG(LOG_DEBUG
, "Invalid state");
250 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
251 ndmp_send_reply(connection
, (void *) &reply
,
252 "sending mover_continue reply");
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");
263 * ndmpd_mover_abort_v2
265 * This handler handles mover_abort requests.
268 * connection (input) - connection handle.
269 * body (input) - request message body.
276 ndmpd_mover_abort_v2(ndmp_connection_t
*connection
, void *body
)
278 ndmp_mover_abort_reply reply
;
279 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
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");
285 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
286 ndmp_send_reply(connection
, (void *) &reply
,
287 "sending mover_abort reply");
291 reply
.error
= NDMP_NO_ERR
;
292 ndmp_send_reply(connection
, (void *) &reply
,
293 "sending mover_abort reply");
295 ndmpd_mover_error(session
, NDMP_MOVER_HALT_ABORTED
);
296 ndmp_stop_buffer_worker(session
);
301 * ndmpd_mover_stop_v2
303 * This handler handles mover_stop requests.
306 * connection (input) - connection handle.
307 * body (input) - request message body.
314 ndmpd_mover_stop_v2(ndmp_connection_t
*connection
, void *body
)
316 ndmp_mover_stop_reply reply
;
317 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
319 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_HALTED
) {
320 NDMP_LOG(LOG_DEBUG
, "Invalid state");
322 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
323 ndmp_send_reply(connection
, (void *) &reply
,
324 "sending mover_stop reply");
328 ndmp_waitfor_op(session
);
329 reply
.error
= NDMP_NO_ERR
;
330 ndmp_send_reply(connection
, (void *) &reply
,
331 "sending mover_stop reply");
333 ndmp_lbr_cleanup(session
);
334 ndmpd_mover_cleanup(session
);
335 (void) ndmpd_mover_init(session
);
336 (void) ndmp_lbr_init(session
);
341 * ndmpd_mover_set_window_v2
343 * This handler handles mover_set_window requests.
347 * connection (input) - connection handle.
348 * body (input) - request message body.
354 ndmpd_mover_set_window_v2(ndmp_connection_t
*connection
, void *body
)
356 ndmp_mover_set_window_request
*request
;
357 ndmp_mover_set_window_reply reply
;
358 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
360 request
= (ndmp_mover_set_window_request
*) body
;
363 * The NDMPv2 specification states that "a window can be set only
364 * when in the listen or paused state."
366 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
367 * allowing it in the idle state as well.
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
);
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
));
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
;
391 ndmp_send_reply(connection
, (void *) &reply
,
392 "sending mover_set_window reply");
397 * ndmpd_mover_read_v2
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.
408 * connection (input) - connection handle.
409 * body (input) - request message body.
415 ndmpd_mover_read_v2(ndmp_connection_t
*connection
, void *body
)
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
);
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");
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");
439 reply
.error
= NDMP_NO_ERR
;
440 ndmp_send_reply(connection
, &reply
, "sending mover_read reply");
442 err
= ndmpd_mover_seek(session
, quad_to_long_long(request
->offset
),
443 quad_to_long_long(request
->length
));
445 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
449 * Just return if we are waiting for the NDMP client to
456 * Start the mover for restore in the 3-way backups.
458 if (start_mover_for_restore(session
) < 0)
459 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
464 * ndmpd_mover_close_v2
466 * This handler handles mover_close requests.
469 * connection (input) - connection handle.
470 * body (input) - request message body.
477 ndmpd_mover_close_v2(ndmp_connection_t
*connection
, void *body
)
479 ndmp_mover_close_reply reply
;
480 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
482 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_PAUSED
) {
483 NDMP_LOG(LOG_DEBUG
, "Invalid state");
485 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
486 ndmp_send_reply(connection
, &reply
,
487 "sending mover_close reply");
490 free(session
->ns_mover
.md_data_addr_v4
.tcp_addr_v4
);
492 reply
.error
= NDMP_NO_ERR
;
493 ndmp_send_reply(connection
, &reply
, "sending mover_close reply");
495 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_CLOSED
);
500 * ndmpd_mover_set_record_size_v2
502 * This handler handles mover_set_record_size requests.
505 * connection (input) - connection handle.
506 * body (input) - request message body.
512 ndmpd_mover_set_record_size_v2(ndmp_connection_t
*connection
, void *body
)
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
);
518 request
= (ndmp_mover_set_record_size_request
*) body
;
520 session
->ns_mover
.md_record_size
= request
->len
;
521 session
->ns_mover
.md_buf
= realloc(session
->ns_mover
.md_buf
,
524 reply
.error
= NDMP_NO_ERR
;
525 ndmp_send_reply(connection
, &reply
,
526 "sending mover_set_record_size reply");
531 * ************************************************************************
533 * ************************************************************************
537 * ndmpd_mover_get_state_v3
539 * This handler handles the ndmp_mover_get_state_request.
540 * Status information for the mover state machine is returned.
543 * connection (input) - connection handle.
544 * body (input) - request message body.
551 ndmpd_mover_get_state_v3(ndmp_connection_t
*connection
, void *body
)
553 ndmp_mover_get_state_reply_v3 reply
;
554 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
556 (void) memset((void*)&reply
, 0, sizeof (reply
));
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
;
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
);
578 ndmp_send_reply(connection
, &reply
,
579 "sending ndmp_mover_get_state reply");
584 * ndmpd_mover_listen_v3
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
592 * connection (input) - connection handle.
593 * body (input) - request message body.
599 ndmpd_mover_listen_v3(ndmp_connection_t
*connection
, void *body
)
601 ndmp_mover_listen_request_v3
*request
;
602 ndmp_mover_listen_reply_v3 reply
;
603 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
607 request
= (ndmp_mover_listen_request_v3
*)body
;
609 (void) memset((void*)&reply
, 0, sizeof (reply
));
610 reply
.error
= NDMP_NO_ERR
;
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",
620 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
621 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
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
;
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.");
637 if (reply
.error
!= NDMP_NO_ERR
) {
638 ndmp_send_reply(connection
, &reply
,
639 "error sending ndmp_mover_listen reply");
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
;
650 if (create_listen_socket_v3(session
, &addr
, &port
) < 0) {
651 reply
.error
= NDMP_IO_ERR
;
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
);
665 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
666 NDMP_LOG(LOG_DEBUG
, "Invalid address type: %d",
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
;
675 ndmp_send_reply(connection
, &reply
,
676 "error sending ndmp_mover_listen reply");
681 * ndmpd_mover_continue_v3
683 * This handler handles ndmp_mover_continue_requests.
686 * connection (input) - connection handle.
687 * body (input) - request message body.
694 ndmpd_mover_continue_v3(ndmp_connection_t
*connection
, void *body
)
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
);
701 (void) memset((void*)&reply
, 0, sizeof (reply
));
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");
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");
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().
724 if (session
->ns_mover
.md_pause_reason
== NDMP_MOVER_PAUSE_SEEK
&&
725 session
->ns_mover
.md_sock
!= -1) {
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
735 ret
= ndmpd_mover_seek(session
,
736 session
->ns_mover
.md_seek_position
,
737 session
->ns_mover
.md_bytes_left_to_read
);
739 ndmpd_mover_error(session
,
740 NDMP_MOVER_HALT_INTERNAL_ERROR
);
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
);
752 * This should not happen because we should be in the
753 * right window. This means that DMA does not follow
756 NDMP_LOG(LOG_DEBUG
, "DMA Error.");
757 ndmpd_mover_error(session
,
758 NDMP_MOVER_HALT_INTERNAL_ERROR
);
763 (void) mutex_lock(&nlp
->nlp_mtx
);
764 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
765 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_NA
;
766 /* The tape has been likely exchanged, reset tape block counter */
767 session
->ns_tape
.td_record_count
= 0;
768 (void) cond_broadcast(&nlp
->nlp_cv
);
769 (void) mutex_unlock(&nlp
->nlp_mtx
);
771 reply
.error
= NDMP_NO_ERR
;
772 ndmp_send_reply(connection
, (void *) &reply
,
773 "sending mover_continue reply");
778 * ndmpd_mover_abort_v3
780 * This handler handles mover_abort requests.
783 * connection (input) - connection handle.
784 * body (input) - request message body.
791 ndmpd_mover_abort_v3(ndmp_connection_t
*connection
, void *body
)
793 ndmp_mover_abort_reply reply
;
794 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
796 if (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_IDLE
||
797 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_HALTED
) {
798 NDMP_LOG(LOG_DEBUG
, "Invalid state");
800 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
801 ndmp_send_reply(connection
, (void *) &reply
,
802 "sending mover_abort reply");
806 reply
.error
= NDMP_NO_ERR
;
807 ndmp_send_reply(connection
, (void *) &reply
,
808 "sending mover_abort reply");
810 ndmpd_mover_error(session
, NDMP_MOVER_HALT_ABORTED
);
815 * ndmpd_mover_set_window_v3
817 * This handler handles mover_set_window requests.
821 * connection (input) - connection handle.
822 * body (input) - request message body.
828 ndmpd_mover_set_window_v3(ndmp_connection_t
*connection
, void *body
)
830 ndmp_mover_set_window_request
*request
;
831 ndmp_mover_set_window_reply reply
;
832 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
834 request
= (ndmp_mover_set_window_request
*) body
;
837 * Note: The spec says that the window can be set only in the listen
838 * and paused states. We let this happen when mover is in the idle
839 * state as well. I can't rememebr which NDMP client (net_backup 4.5
840 * or net_worker 6.1.1) forced us to do this!
842 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
&&
843 session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_LISTEN
&&
844 session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_PAUSED
) {
845 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
846 NDMP_LOG(LOG_DEBUG
, "Invalid state %d",
847 session
->ns_mover
.md_state
);
848 } else if (session
->ns_mover
.md_record_size
== 0) {
849 if (session
->ns_protocol_version
== NDMPV4
)
850 reply
.error
= NDMP_PRECONDITION_ERR
;
852 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
853 NDMP_LOG(LOG_DEBUG
, "Invalid record size 0");
855 reply
.error
= NDMP_NO_ERR
;
857 if (quad_to_long_long(request
->length
) == 0) {
858 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
859 NDMP_LOG(LOG_DEBUG
, "Invalid window size %d",
860 quad_to_long_long(request
->length
));
863 if (reply
.error
!= NDMP_NO_ERR
) {
864 ndmp_send_reply(connection
, (void *) &reply
,
865 "sending mover_set_window_v3 reply");
869 session
->ns_mover
.md_pre_cond
= TRUE
;
870 session
->ns_mover
.md_window_offset
= quad_to_long_long(request
->offset
);
871 session
->ns_mover
.md_window_length
= quad_to_long_long(request
->length
);
874 * We have to update the position for DAR. DAR needs this
875 * information to position to the right index on tape,
876 * especially when we span the tapes.
878 #ifdef NO_POSITION_CHANGE
880 * Do not change the mover position if we are reading from
881 * the tape. In this way, we can use the position+window_length
882 * to know how much we can write to a tape before pausing with
885 if (session
->ns_mover
.md_mode
!= NDMP_MOVER_MODE_WRITE
)
886 #endif /* NO_POSITION_CHANGE */
887 session
->ns_mover
.md_position
=
888 session
->ns_mover
.md_window_offset
;
890 ndmp_send_reply(connection
, (void *) &reply
,
891 "sending mover_set_window_v3 reply");
896 * ndmpd_mover_read_v3
898 * This handler handles ndmp_mover_read_requests.
899 * If the requested offset is outside of the current window, the mover
900 * is paused and a notify_mover_paused request is sent notifying the
901 * client that a seek is required. If the requested offest is within
902 * the window but not within the current record, then the tape is
903 * positioned to the record containing the requested offest. The requested
904 * amount of data is then read from the tape device and written to the
908 * connection (input) - connection handle.
909 * body (input) - request message body.
915 ndmpd_mover_read_v3(ndmp_connection_t
*connection
, void *body
)
917 ndmp_mover_read_request
*request
= (ndmp_mover_read_request
*)body
;
918 ndmp_mover_read_reply reply
;
919 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
922 (void) memset((void*)&reply
, 0, sizeof (reply
));
924 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_ACTIVE
||
925 session
->ns_mover
.md_mode
!= NDMP_MOVER_MODE_WRITE
) {
926 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
927 NDMP_LOG(LOG_DEBUG
, "Invalid state");
928 } else if (session
->ns_mover
.md_bytes_left_to_read
!= 0) {
929 reply
.error
= NDMP_READ_IN_PROGRESS_ERR
;
930 NDMP_LOG(LOG_DEBUG
, "In progress");
931 } else if (session
->ns_tape
.td_fd
== -1) {
932 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
933 NDMP_LOG(LOG_DEBUG
, "Tape device is not open");
934 } else if (quad_to_long_long(request
->length
) == 0 ||
935 (quad_to_long_long(request
->length
) == MAX_WINDOW_SIZE
&&
936 quad_to_long_long(request
->offset
) != 0)) {
937 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
938 NDMP_LOG(LOG_DEBUG
, "Illegal args");
940 reply
.error
= NDMP_NO_ERR
;
943 ndmp_send_reply(connection
, (void *) &reply
,
944 "sending ndmp_mover_read_reply");
945 if (reply
.error
!= NDMP_NO_ERR
)
948 err
= ndmpd_mover_seek(session
, quad_to_long_long(request
->offset
),
949 quad_to_long_long(request
->length
));
951 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
956 * Just return if we are waiting for the DMA to complete the seek.
962 * Setup a handler function that will be called when
963 * data can be written to the data connection without blocking.
965 if (ndmpd_add_file_handler(session
, (void*)session
,
966 session
->ns_mover
.md_sock
, NDMPD_SELECT_MODE_WRITE
, HC_MOVER
,
967 mover_data_write_v3
) < 0) {
968 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
975 * ndmpd_mover_set_record_size_v3
977 * This handler handles mover_set_record_size requests.
980 * connection (input) - connection handle.
981 * body (input) - request message body.
987 ndmpd_mover_set_record_size_v3(ndmp_connection_t
*connection
, void *body
)
989 ndmp_mover_set_record_size_request
*request
;
990 ndmp_mover_set_record_size_reply reply
;
991 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
994 request
= (ndmp_mover_set_record_size_request
*) body
;
996 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
997 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
998 NDMP_LOG(LOG_DEBUG
, "Invalid mover state %d",
999 session
->ns_mover
.md_state
);
1000 } else if (request
->len
> (unsigned int)ndmp_max_mover_recsize
) {
1001 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1003 "Invalid argument %d, should be > 0 and <= %d",
1004 request
->len
, ndmp_max_mover_recsize
);
1005 } else if (request
->len
== session
->ns_mover
.md_record_size
)
1006 reply
.error
= NDMP_NO_ERR
;
1007 else if (!(cp
= realloc(session
->ns_mover
.md_buf
, request
->len
))) {
1008 reply
.error
= NDMP_NO_MEM_ERR
;
1010 reply
.error
= NDMP_NO_ERR
;
1011 session
->ns_mover
.md_buf
= cp
;
1012 session
->ns_mover
.md_record_size
= request
->len
;
1013 session
->ns_mover
.md_window_offset
= 0;
1014 session
->ns_mover
.md_window_length
= 0;
1017 ndmp_send_reply(connection
, (void *) &reply
,
1018 "sending mover_set_record_size reply");
1023 * ndmpd_mover_connect_v3
1024 * Request handler. Connects the mover to either a local
1025 * or remote data server.
1028 * connection (input) - connection handle.
1029 * body (input) - request message body.
1035 ndmpd_mover_connect_v3(ndmp_connection_t
*connection
, void *body
)
1037 ndmp_mover_connect_request_v3
*request
;
1038 ndmp_mover_connect_reply_v3 reply
;
1039 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1041 request
= (ndmp_mover_connect_request_v3
*)body
;
1043 (void) memset((void*)&reply
, 0, sizeof (reply
));
1045 if (request
->mode
!= NDMP_MOVER_MODE_READ
&&
1046 request
->mode
!= NDMP_MOVER_MODE_WRITE
) {
1047 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1048 NDMP_LOG(LOG_DEBUG
, "Invalid mode %d", request
->mode
);
1049 } else if (!ndmp_valid_v3addr_type(request
->addr
.addr_type
)) {
1050 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1051 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
1052 request
->addr
.addr_type
);
1053 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
1054 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1055 NDMP_LOG(LOG_DEBUG
, "Invalid state %d: mover is not idle",
1056 session
->ns_mover
.md_state
);
1057 } else if (session
->ns_tape
.td_fd
== -1) {
1058 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
1059 NDMP_LOG(LOG_DEBUG
, "No tape device open");
1060 } else if (request
->mode
== NDMP_MOVER_MODE_READ
&&
1061 session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
1062 reply
.error
= NDMP_WRITE_PROTECT_ERR
;
1063 NDMP_LOG(LOG_ERR
, "Write protected device.");
1065 reply
.error
= NDMP_NO_ERR
;
1067 if (reply
.error
!= NDMP_NO_ERR
) {
1068 ndmp_send_reply(connection
, (void *) &reply
,
1069 "sending ndmp_mover_connect reply");
1073 switch (request
->addr
.addr_type
) {
1074 case NDMP_ADDR_LOCAL
:
1076 * Verify that the data server is listening for a
1079 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_LISTEN
||
1080 session
->ns_data
.dd_listen_sock
!= -1) {
1082 "Data server is not in local listen state");
1083 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1085 session
->ns_data
.dd_state
= NDMP_DATA_STATE_CONNECTED
;
1089 reply
.error
= mover_connect_sock(session
, request
->mode
,
1090 request
->addr
.tcp_ip_v3
, request
->addr
.tcp_port_v3
);
1094 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1095 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
1096 request
->addr
.addr_type
);
1099 if (reply
.error
== NDMP_NO_ERR
) {
1100 session
->ns_mover
.md_data_addr
.addr_type
=
1101 request
->addr
.addr_type
;
1102 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
1103 session
->ns_mover
.md_mode
= request
->mode
;
1106 ndmp_send_reply(connection
, (void *) &reply
,
1107 "sending ndmp_mover_connect reply");
1112 * ************************************************************************
1114 * ************************************************************************
1118 * ndmpd_mover_get_state_v4
1120 * This handler handles the ndmp_mover_get_state_request.
1121 * Status information for the mover state machine is returned.
1124 * connection (input) - connection handle.
1125 * body (input) - request message body.
1132 ndmpd_mover_get_state_v4(ndmp_connection_t
*connection
, void *body
)
1134 ndmp_mover_get_state_reply_v4 reply
;
1135 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1137 (void) memset((void*)&reply
, 0, sizeof (reply
));
1139 reply
.error
= NDMP_NO_ERR
;
1140 reply
.state
= session
->ns_mover
.md_state
;
1141 reply
.mode
= session
->ns_mover
.md_mode
;
1142 reply
.pause_reason
= session
->ns_mover
.md_pause_reason
;
1143 reply
.halt_reason
= session
->ns_mover
.md_halt_reason
;
1144 reply
.record_size
= session
->ns_mover
.md_record_size
;
1145 reply
.record_num
= session
->ns_mover
.md_record_num
;
1147 long_long_to_quad(session
->ns_mover
.md_data_written
);
1148 reply
.seek_position
=
1149 long_long_to_quad(session
->ns_mover
.md_seek_position
);
1150 reply
.bytes_left_to_read
=
1151 long_long_to_quad(session
->ns_mover
.md_bytes_left_to_read
);
1152 reply
.window_offset
=
1153 long_long_to_quad(session
->ns_mover
.md_window_offset
);
1154 reply
.window_length
=
1155 long_long_to_quad(session
->ns_mover
.md_window_length
);
1156 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
)
1157 ndmp_copy_addr_v4(&reply
.data_connection_addr
,
1158 &session
->ns_mover
.md_data_addr_v4
);
1160 ndmp_send_reply(connection
, (void *) &reply
,
1161 "sending ndmp_mover_get_state reply");
1162 free(reply
.data_connection_addr
.tcp_addr_v4
);
1167 * ndmpd_mover_listen_v4
1169 * This handler handles ndmp_mover_listen_requests.
1170 * A TCP/IP socket is created that is used to listen for
1171 * and accept data connections initiated by a remote
1175 * connection (input) - connection handle.
1176 * body (input) - request message body.
1182 ndmpd_mover_listen_v4(ndmp_connection_t
*connection
, void *body
)
1184 ndmp_mover_listen_request_v4
*request
;
1186 ndmp_mover_listen_reply_v4 reply
;
1187 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1191 request
= (ndmp_mover_listen_request_v4
*)body
;
1193 (void) memset((void*)&reply
, 0, sizeof (reply
));
1194 reply
.error
= NDMP_NO_ERR
;
1196 if (request
->mode
!= NDMP_MOVER_MODE_READ
&&
1197 request
->mode
!= NDMP_MOVER_MODE_WRITE
) {
1198 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1199 NDMP_LOG(LOG_DEBUG
, "Invalid mode %d", request
->mode
);
1200 } else if (!ndmp_valid_v3addr_type(request
->addr_type
)) {
1201 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1202 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
1203 request
->addr_type
);
1204 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
1205 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1207 "Invalid mover state to process listen request");
1208 } else if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_IDLE
) {
1209 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1211 "Invalid data state to process listen request");
1212 } else if (session
->ns_tape
.td_fd
== -1) {
1213 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
1214 NDMP_LOG(LOG_DEBUG
, "No tape device open");
1215 } else if (session
->ns_mover
.md_record_size
== 0) {
1216 reply
.error
= NDMP_PRECONDITION_ERR
;
1217 NDMP_LOG(LOG_DEBUG
, "Invalid record size 0");
1218 } else if (request
->mode
== NDMP_MOVER_MODE_READ
&&
1219 session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
1220 reply
.error
= NDMP_PERMISSION_ERR
;
1221 NDMP_LOG(LOG_ERR
, "Write protected device.");
1224 if (reply
.error
!= NDMP_NO_ERR
) {
1225 ndmp_send_reply(connection
, (void *) &reply
,
1226 "error sending ndmp_mover_listen reply");
1230 switch (request
->addr_type
) {
1231 case NDMP_ADDR_LOCAL
:
1232 reply
.connect_addr
.addr_type
= NDMP_ADDR_LOCAL
;
1233 session
->ns_mover
.md_data_addr
.addr_type
= NDMP_ADDR_LOCAL
;
1234 reply
.error
= NDMP_NO_ERR
;
1237 if (create_listen_socket_v3(session
, &addr
, &port
) < 0) {
1238 reply
.error
= NDMP_IO_ERR
;
1241 reply
.error
= NDMP_NO_ERR
;
1243 session
->ns_mover
.md_data_addr_v4
.addr_type
= NDMP_ADDR_TCP
;
1244 session
->ns_mover
.md_data_addr_v4
.tcp_len_v4
= 1;
1245 session
->ns_mover
.md_data_addr_v4
.tcp_addr_v4
=
1246 ndmp_malloc(sizeof (ndmp_tcp_addr_v4
));
1248 session
->ns_mover
.md_data_addr_v4
.tcp_ip_v4(0) = addr
;
1249 session
->ns_mover
.md_data_addr_v4
.tcp_port_v4(0) = ntohs(port
);
1251 ndmp_copy_addr_v4(&reply
.connect_addr
,
1252 &session
->ns_mover
.md_data_addr_v4
);
1254 /* For compatibility with V3 */
1255 session
->ns_mover
.md_data_addr
.addr_type
= NDMP_ADDR_TCP
;
1256 session
->ns_mover
.md_data_addr
.tcp_ip_v3
= addr
;
1257 session
->ns_mover
.md_data_addr
.tcp_port_v3
= ntohs(port
);
1258 NDMP_LOG(LOG_DEBUG
, "listen_socket: %d",
1259 session
->ns_mover
.md_listen_sock
);
1262 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1263 NDMP_LOG(LOG_DEBUG
, "Invalid address type: %d",
1264 request
->addr_type
);
1267 if (reply
.error
== NDMP_NO_ERR
) {
1268 session
->ns_mover
.md_mode
= request
->mode
;
1269 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_LISTEN
;
1272 ndmp_send_reply(connection
, (void *) &reply
,
1273 "error sending ndmp_mover_listen reply");
1274 free(reply
.connect_addr
.tcp_addr_v4
);
1278 * ndmpd_mover_connect_v4
1279 * Request handler. Connects the mover to either a local
1280 * or remote data server.
1283 * connection (input) - connection handle.
1284 * body (input) - request message body.
1290 ndmpd_mover_connect_v4(ndmp_connection_t
*connection
, void *body
)
1292 ndmp_mover_connect_request_v4
*request
;
1293 ndmp_mover_connect_reply_v4 reply
;
1294 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1296 request
= (ndmp_mover_connect_request_v4
*)body
;
1297 (void) memset((void*)&reply
, 0, sizeof (reply
));
1299 if (request
->mode
!= NDMP_MOVER_MODE_READ
&&
1300 request
->mode
!= NDMP_MOVER_MODE_WRITE
) {
1301 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1302 NDMP_LOG(LOG_DEBUG
, "Invalid mode %d", request
->mode
);
1303 } else if (!ndmp_valid_v3addr_type(request
->addr
.addr_type
)) {
1304 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1305 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
1306 request
->addr
.addr_type
);
1307 } else if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_IDLE
) {
1308 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1309 NDMP_LOG(LOG_DEBUG
, "Invalid state %d: mover is not idle",
1310 session
->ns_mover
.md_state
);
1311 } else if (session
->ns_tape
.td_fd
== -1) {
1312 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
1313 NDMP_LOG(LOG_DEBUG
, "No tape device open");
1314 } else if (request
->mode
== NDMP_MOVER_MODE_READ
&&
1315 session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
1316 reply
.error
= NDMP_PERMISSION_ERR
;
1317 NDMP_LOG(LOG_ERR
, "Write protected device.");
1318 } else if (session
->ns_mover
.md_record_size
== 0) {
1319 reply
.error
= NDMP_PRECONDITION_ERR
;
1320 NDMP_LOG(LOG_DEBUG
, "Invalid record size 0");
1322 reply
.error
= NDMP_NO_ERR
;
1324 if (reply
.error
!= NDMP_NO_ERR
) {
1325 ndmp_send_reply(connection
, (void *) &reply
,
1326 "sending ndmp_mover_connect reply");
1330 switch (request
->addr
.addr_type
) {
1331 case NDMP_ADDR_LOCAL
:
1333 * Verify that the data server is listening for a
1336 if (session
->ns_data
.dd_state
!= NDMP_DATA_STATE_LISTEN
||
1337 session
->ns_data
.dd_listen_sock
!= -1) {
1339 "Data server is not in local listen state");
1340 reply
.error
= NDMP_ILLEGAL_STATE_ERR
;
1342 session
->ns_data
.dd_state
= NDMP_DATA_STATE_CONNECTED
;
1346 reply
.error
= mover_connect_sock(session
, request
->mode
,
1347 request
->addr
.tcp_ip_v4(0), request
->addr
.tcp_port_v4(0));
1351 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
1352 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
1353 request
->addr
.addr_type
);
1356 if (reply
.error
== NDMP_NO_ERR
) {
1357 session
->ns_mover
.md_data_addr
.addr_type
=
1358 request
->addr
.addr_type
;
1359 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
1360 session
->ns_mover
.md_mode
= request
->mode
;
1363 ndmp_send_reply(connection
, (void *) &reply
,
1364 "sending ndmp_mover_connect reply");
1370 * ************************************************************************
1372 * ************************************************************************
1378 * Writes data to the mover.
1379 * Buffers and write data to the tape device.
1380 * A full tape record is buffered before being written.
1383 * session (input) - session pointer.
1384 * data (input) - data to be written.
1385 * length (input) - data length.
1388 * 0 - data successfully written.
1392 ndmpd_local_write(ndmpd_session_t
*session
, char *data
, ulong_t length
)
1399 * A length of 0 indicates that any buffered data should be
1403 if (session
->ns_mover
.md_w_index
== 0)
1407 &session
->ns_mover
.md_buf
[session
->ns_mover
.md_w_index
],
1408 0, session
->ns_mover
.md_record_size
-
1409 session
->ns_mover
.md_w_index
);
1411 n
= mover_tape_write_v3(session
, session
->ns_mover
.md_buf
,
1412 session
->ns_mover
.md_record_size
);
1414 ndmpd_mover_error(session
,
1415 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
1416 NDMP_MOVER_HALT_INTERNAL_ERROR
));
1419 session
->ns_mover
.md_position
+= n
;
1420 session
->ns_mover
.md_data_written
+=
1421 session
->ns_mover
.md_w_index
;
1422 session
->ns_mover
.md_record_num
++;
1423 session
->ns_mover
.md_w_index
= 0;
1426 /* Break the data into records. */
1427 while (count
< length
) {
1429 * Determine if data needs to be buffered or
1430 * can be written directly from user supplied location.
1431 * We can fast path the write if there is no pending
1432 * buffered data and there is at least a full record's worth
1433 * of data to be written.
1435 if (session
->ns_mover
.md_w_index
== 0 &&
1436 length
- count
>= session
->ns_mover
.md_record_size
) {
1437 n
= mover_tape_write_v3(session
, &data
[count
],
1438 session
->ns_mover
.md_record_size
);
1440 ndmpd_mover_error(session
,
1441 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
1442 NDMP_MOVER_HALT_INTERNAL_ERROR
));
1445 session
->ns_mover
.md_position
+= n
;
1446 session
->ns_mover
.md_data_written
+= n
;
1447 session
->ns_mover
.md_record_num
++;
1451 /* Buffer the data */
1452 len
= length
- count
;
1453 if (len
> session
->ns_mover
.md_record_size
-
1454 session
->ns_mover
.md_w_index
)
1455 len
= session
->ns_mover
.md_record_size
-
1456 session
->ns_mover
.md_w_index
;
1459 &session
->ns_mover
.md_buf
[session
->ns_mover
.md_w_index
],
1461 session
->ns_mover
.md_w_index
+= len
;
1464 /* Write the buffer if its full */
1465 if (session
->ns_mover
.md_w_index
==
1466 session
->ns_mover
.md_record_size
) {
1467 n
= mover_tape_write_v3(session
,
1468 session
->ns_mover
.md_buf
,
1469 session
->ns_mover
.md_record_size
);
1471 ndmpd_mover_error(session
,
1472 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
1473 NDMP_MOVER_HALT_INTERNAL_ERROR
));
1476 session
->ns_mover
.md_position
+= n
;
1477 session
->ns_mover
.md_data_written
+= n
;
1478 session
->ns_mover
.md_record_num
++;
1479 session
->ns_mover
.md_w_index
= 0;
1488 * ndmpd_remote_write
1490 * Writes data to the remote mover.
1493 * session (input) - session pointer.
1494 * data (input) - data to be written.
1495 * length (input) - data length.
1498 * 0 - data successfully written.
1502 ndmpd_remote_write(ndmpd_session_t
*session
, char *data
, ulong_t length
)
1507 while (count
< length
) {
1508 if (session
->ns_eof
== TRUE
||
1509 session
->ns_data
.dd_abort
== TRUE
)
1512 if ((n
= write(session
->ns_data
.dd_sock
, &data
[count
],
1513 length
- count
)) < 0) {
1514 NDMP_LOG(LOG_ERR
, "Socket write error: %m.");
1526 * Reads data from the local tape device.
1527 * Full tape records are read and buffered.
1530 * session (input) - session pointer.
1531 * data (input) - location to store data.
1532 * length (input) - data length.
1535 * 0 - data successfully read.
1537 * 1 - session terminated or operation aborted.
1540 ndmpd_local_read(ndmpd_session_t
*session
, char *data
, ulong_t length
)
1545 ndmp_notify_mover_paused_request pause_request
;
1548 * Automatically increase the seek window if necessary.
1549 * This is needed in the event the module attempts to read
1550 * past a seek window set via a prior call to ndmpd_seek() or
1551 * the module has not issued a seek. If no seek was issued then
1552 * pretend that a seek was issued to read the entire tape.
1554 if (length
> session
->ns_mover
.md_bytes_left_to_read
) {
1555 /* ndmpd_seek() never called? */
1556 if (session
->ns_data
.dd_read_length
== 0) {
1557 session
->ns_mover
.md_bytes_left_to_read
= ~0LL;
1558 session
->ns_data
.dd_read_offset
= 0LL;
1559 session
->ns_data
.dd_read_length
= ~0LL;
1561 session
->ns_mover
.md_bytes_left_to_read
= length
;
1562 session
->ns_data
.dd_read_offset
=
1563 session
->ns_mover
.md_position
;
1564 session
->ns_data
.dd_read_length
= length
;
1568 * Read as many records as necessary to satisfy the request.
1570 while (count
< length
) {
1572 * If the end of the mover window has been reached,
1573 * then notify the client that a new data window is needed.
1575 if (session
->ns_mover
.md_position
>=
1576 session
->ns_mover
.md_window_offset
+
1577 session
->ns_mover
.md_window_length
) {
1579 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
1580 session
->ns_mover
.md_pause_reason
=
1581 NDMP_MOVER_PAUSE_SEEK
;
1582 pause_request
.reason
= NDMP_MOVER_PAUSE_SEEK
;
1583 pause_request
.seek_position
=
1584 long_long_to_quad(session
->ns_mover
.md_position
);
1586 if (ndmp_send_request(session
->ns_connection
,
1587 NDMP_NOTIFY_MOVER_PAUSED
, NDMP_NO_ERR
,
1588 (void *) &pause_request
, 0) < 0) {
1590 "Sending notify_mover_paused request");
1591 ndmpd_mover_error(session
,
1592 NDMP_MOVER_HALT_INTERNAL_ERROR
);
1596 * Wait until the state is changed by
1597 * an abort or continue request.
1599 if (ndmp_wait_for_mover(session
) != 0)
1602 len
= length
- count
;
1605 * Prevent reading past the end of the window.
1608 session
->ns_mover
.md_window_offset
+
1609 session
->ns_mover
.md_window_length
-
1610 session
->ns_mover
.md_position
)
1611 len
= session
->ns_mover
.md_window_offset
+
1612 session
->ns_mover
.md_window_length
-
1613 session
->ns_mover
.md_position
;
1616 * Copy from the data buffer first.
1618 if (session
->ns_mover
.md_w_index
-
1619 session
->ns_mover
.md_r_index
!= 0) {
1621 * Limit the copy to the amount of data in the buffer.
1623 if (len
> session
->ns_mover
.md_w_index
-
1624 session
->ns_mover
.md_r_index
)
1625 len
= session
->ns_mover
.md_w_index
1626 - session
->ns_mover
.md_r_index
;
1628 (void) memcpy((void *) &data
[count
],
1629 &session
->ns_mover
.md_buf
[session
->
1630 ns_mover
.md_r_index
], len
);
1632 session
->ns_mover
.md_r_index
+= len
;
1633 session
->ns_mover
.md_bytes_left_to_read
-= len
;
1634 session
->ns_mover
.md_position
+= len
;
1638 * Determine if data needs to be buffered or
1639 * can be read directly to user supplied location.
1640 * We can fast path the read if at least a full record
1641 * needs to be read and there is no seek pending.
1642 * This is done to eliminate a buffer copy.
1644 if (len
>= session
->ns_mover
.md_record_size
&&
1645 session
->ns_mover
.md_position
>=
1646 session
->ns_mover
.md_seek_position
) {
1647 n
= tape_read(session
, &data
[count
]);
1649 if (n
== TAPE_NO_WRITER_ERR
)
1652 ndmpd_mover_error(session
,
1653 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
1654 NDMP_MOVER_HALT_INTERNAL_ERROR
));
1655 return (n
== 0) ? (1) : (-1);
1658 session
->ns_mover
.md_bytes_left_to_read
-= n
;
1659 session
->ns_mover
.md_position
+= n
;
1662 /* Read the next record into the buffer. */
1663 n
= tape_read(session
, session
->ns_mover
.md_buf
);
1665 if (n
== TAPE_NO_WRITER_ERR
)
1668 ndmpd_mover_error(session
,
1669 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
1670 NDMP_MOVER_HALT_INTERNAL_ERROR
));
1671 return (n
== 0) ? (1) : (-1);
1673 session
->ns_mover
.md_w_index
= n
;
1674 session
->ns_mover
.md_r_index
= 0;
1676 NDMP_LOG(LOG_DEBUG
, "n: %d", n
);
1679 * Discard data if the current data stream position is
1680 * prior to the seek position. This is necessary if a seek
1681 * request set the seek pointer to a position that is not a
1682 * record boundary. The seek request handler can only position
1683 * to the start of a record.
1685 if (session
->ns_mover
.md_position
<
1686 session
->ns_mover
.md_seek_position
) {
1687 session
->ns_mover
.md_r_index
=
1688 session
->ns_mover
.md_seek_position
-
1689 session
->ns_mover
.md_position
;
1690 session
->ns_mover
.md_position
=
1691 session
->ns_mover
.md_seek_position
;
1702 * Reads data from the remote mover.
1705 * session (input) - session pointer.
1706 * data (input) - data to be written.
1707 * length (input) - data length.
1710 * 0 - data successfully read.
1712 * 1 - session terminated or operation aborted.
1715 ndmpd_remote_read(ndmpd_session_t
*session
, char *data
, ulong_t length
)
1720 ndmp_notify_data_read_request request
;
1722 while (count
< length
) {
1723 len
= length
- count
;
1726 * If the end of the seek window has been reached then
1727 * send an ndmp_read request to the client.
1728 * The NDMP client will then send a mover_data_read request to
1729 * the remote mover and the mover will send more data.
1730 * This condition can occur if the module attempts to read past
1731 * a seek window set via a prior call to ndmpd_seek() or
1732 * the module has not issued a seek. If no seek was issued then
1733 * pretend that a seek was issued to read the entire tape.
1735 if (session
->ns_mover
.md_bytes_left_to_read
== 0) {
1736 /* ndmpd_seek() never called? */
1737 if (session
->ns_data
.dd_read_length
== 0) {
1738 session
->ns_mover
.md_bytes_left_to_read
= ~0LL;
1739 session
->ns_data
.dd_read_offset
= 0LL;
1740 session
->ns_data
.dd_read_length
= ~0LL;
1742 session
->ns_mover
.md_bytes_left_to_read
= len
;
1743 session
->ns_data
.dd_read_offset
=
1744 session
->ns_mover
.md_position
;
1745 session
->ns_data
.dd_read_length
= len
;
1749 long_long_to_quad(session
->ns_data
.dd_read_offset
);
1751 long_long_to_quad(session
->ns_data
.dd_read_length
);
1753 if (ndmp_send_request_lock(session
->ns_connection
,
1754 NDMP_NOTIFY_DATA_READ
, NDMP_NO_ERR
,
1755 (void *) &request
, 0) < 0) {
1757 "Sending notify_data_read request");
1761 if (session
->ns_eof
== TRUE
||
1762 session
->ns_data
.dd_abort
== TRUE
)
1766 * If the module called ndmpd_seek() prior to reading all of the
1767 * data that the remote mover was requested to send, then the
1768 * excess data from the seek has to be discardd.
1770 if (session
->ns_mover
.md_discard_length
!= 0) {
1771 n
= discard_data(session
,
1772 (ulong_t
)session
->ns_mover
.md_discard_length
);
1775 session
->ns_mover
.md_discard_length
-= n
;
1779 * Don't attempt to read more data than the remote is sending.
1781 if (len
> session
->ns_mover
.md_bytes_left_to_read
)
1782 len
= session
->ns_mover
.md_bytes_left_to_read
;
1784 NDMP_LOG(LOG_DEBUG
, "len: %u", len
);
1786 if ((n
= read(session
->ns_data
.dd_sock
, &data
[count
],
1788 NDMP_LOG(LOG_ERR
, "Socket read error: %m.");
1791 /* read returns 0 if the connection was closed */
1796 session
->ns_mover
.md_bytes_left_to_read
-= n
;
1797 session
->ns_mover
.md_position
+= n
;
1803 /* *** ndmpd internal functions ***************************************** */
1808 * Initialize mover specific session variables.
1809 * Don't initialize variables such as record_size that need to
1810 * persist across data operations. A client may open a connection and
1811 * do multiple backups after setting the record_size.
1814 * session (input) - session pointer.
1821 ndmpd_mover_init(ndmpd_session_t
*session
)
1823 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_IDLE
;
1824 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_NA
;
1825 session
->ns_mover
.md_halt_reason
= NDMP_MOVER_HALT_NA
;
1826 session
->ns_mover
.md_data_written
= 0LL;
1827 session
->ns_mover
.md_seek_position
= 0LL;
1828 session
->ns_mover
.md_bytes_left_to_read
= 0LL;
1829 session
->ns_mover
.md_window_offset
= 0LL;
1830 session
->ns_mover
.md_window_length
= MAX_WINDOW_SIZE
;
1831 session
->ns_mover
.md_position
= 0LL;
1832 session
->ns_mover
.md_discard_length
= 0;
1833 session
->ns_mover
.md_record_num
= 0;
1834 session
->ns_mover
.md_record_size
= 0;
1835 session
->ns_mover
.md_listen_sock
= -1;
1836 session
->ns_mover
.md_pre_cond
= FALSE
;
1837 session
->ns_mover
.md_sock
= -1;
1838 session
->ns_mover
.md_r_index
= 0;
1839 session
->ns_mover
.md_w_index
= 0;
1840 session
->ns_mover
.md_buf
= ndmp_malloc(MAX_RECORD_SIZE
);
1841 if (!session
->ns_mover
.md_buf
)
1844 if (ndmp_get_version(session
->ns_connection
) == NDMPV3
) {
1845 session
->ns_mover
.md_mode
= NDMP_MOVER_MODE_READ
;
1846 (void) memset(&session
->ns_mover
.md_data_addr
, 0,
1847 sizeof (ndmp_addr_v3
));
1854 * ndmpd_mover_shut_down
1856 * Shutdown the mover. It closes all the sockets.
1859 * session (input) - session pointer.
1865 ndmpd_mover_shut_down(ndmpd_session_t
*session
)
1867 ndmp_lbr_params_t
*nlp
;
1869 if ((nlp
= ndmp_get_nlp(session
)) == NULL
)
1872 (void) mutex_lock(&nlp
->nlp_mtx
);
1873 if (session
->ns_mover
.md_listen_sock
!= -1) {
1874 NDMP_LOG(LOG_DEBUG
, "mover.listen_sock: %d",
1875 session
->ns_mover
.md_listen_sock
);
1876 (void) ndmpd_remove_file_handler(session
,
1877 session
->ns_mover
.md_listen_sock
);
1878 (void) close(session
->ns_mover
.md_listen_sock
);
1879 session
->ns_mover
.md_listen_sock
= -1;
1881 if (session
->ns_mover
.md_sock
!= -1) {
1882 NDMP_LOG(LOG_DEBUG
, "mover.sock: %d",
1883 session
->ns_mover
.md_sock
);
1884 (void) ndmpd_remove_file_handler(session
,
1885 session
->ns_mover
.md_sock
);
1886 (void) close(session
->ns_mover
.md_sock
);
1887 session
->ns_mover
.md_sock
= -1;
1889 (void) cond_broadcast(&nlp
->nlp_cv
);
1890 (void) mutex_unlock(&nlp
->nlp_mtx
);
1895 * ndmpd_mover_cleanup
1898 * session (input) - session pointer.
1904 ndmpd_mover_cleanup(ndmpd_session_t
*session
)
1906 NDMP_FREE(session
->ns_mover
.md_buf
);
1911 * ndmpd_mover_connect
1912 * Create a connection to the specified mover.
1915 * session (input) - session pointer
1921 ndmpd_mover_connect(ndmpd_session_t
*session
, ndmp_mover_mode mover_mode
)
1923 ndmp_mover_addr
*mover
= &session
->ns_data
.dd_mover
;
1924 struct sockaddr_in sin
;
1927 if (mover
->addr_type
== NDMP_ADDR_TCP
) {
1928 if (mover
->ndmp_mover_addr_u
.addr
.ip_addr
) {
1929 (void) memset((void *) &sin
, 0, sizeof (sin
));
1930 sin
.sin_family
= AF_INET
;
1931 sin
.sin_addr
.s_addr
=
1932 htonl(mover
->ndmp_mover_addr_u
.addr
.ip_addr
);
1934 htons(mover
->ndmp_mover_addr_u
.addr
.port
);
1937 * If the address type is TCP but both the address and
1938 * the port number are zero, we have to use a different
1939 * socket than the mover socket. This can happen when
1940 * using NDMP disk to disk copy (AKA D2D copy).
1941 * The NDMPCopy client will send a zero address to
1942 * direct the server to use the mover socket as the
1943 * data socket to receive the recovery data.
1945 if (sin
.sin_addr
.s_addr
== 0 && sin
.sin_port
== 0) {
1946 session
->ns_data
.dd_sock
=
1947 session
->ns_mover
.md_sock
;
1948 return (NDMP_NO_ERR
);
1951 NDMP_LOG(LOG_DEBUG
, "addr: %u port: %u",
1952 mover
->ndmp_mover_addr_u
.addr
.ip_addr
,
1953 (ulong_t
)sin
.sin_port
);
1955 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
1956 NDMP_LOG(LOG_DEBUG
, "Socket error: %m");
1957 return (NDMP_IO_ERR
);
1959 if (connect(sock
, (struct sockaddr
*)&sin
,
1960 sizeof (sin
)) < 0) {
1961 NDMP_LOG(LOG_DEBUG
, "Connect error: %m");
1963 return (NDMP_IO_ERR
);
1965 set_socket_options(sock
);
1967 if ((session
->ns_mover
.md_state
!=
1968 NDMP_MOVER_STATE_ACTIVE
) ||
1969 (session
->ns_mover
.md_sock
== -1)) {
1972 "Not in active state mover"
1973 " state = %d or Invalid mover sock=%d",
1974 session
->ns_mover
.md_state
,
1975 session
->ns_mover
.md_sock
);
1976 return (NDMP_ILLEGAL_STATE_ERR
);
1979 sock
= session
->ns_mover
.md_sock
;
1981 "session: 0x%x setting data sock fd: %d to be"
1982 " same as listen_sock", session
, sock
);
1985 NDMP_LOG(LOG_DEBUG
, "sock fd: %d", sock
);
1987 session
->ns_data
.dd_sock
= sock
;
1989 NDMP_LOG(LOG_DEBUG
, "data.mover_sock: %u", sock
);
1991 return (NDMP_NO_ERR
);
1993 /* Local mover connection. */
1995 if (session
->ns_mover
.md_state
!= NDMP_MOVER_STATE_LISTEN
) {
1996 NDMP_LOG(LOG_DEBUG
, "Mover is not in listen state");
1997 return (NDMP_ILLEGAL_STATE_ERR
);
1999 if (session
->ns_tape
.td_fd
== -1) {
2000 NDMP_LOG(LOG_DEBUG
, "Tape device not open");
2001 return (NDMP_DEV_NOT_OPEN_ERR
);
2003 if (mover_mode
== NDMP_MOVER_MODE_READ
&&
2004 session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
2005 NDMP_LOG(LOG_ERR
, "Write protected device.");
2006 return (NDMP_WRITE_PROTECT_ERR
);
2008 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
2009 session
->ns_mover
.md_mode
= mover_mode
;
2011 return (NDMP_NO_ERR
);
2019 * Seek to the requested data stream position.
2020 * If the requested offset is outside of the current window,
2021 * the mover is paused and a notify_mover_paused request is sent
2022 * notifying the client that a seek is required.
2023 * If the requested offest is within the window but not within the
2024 * current record, then the tape is positioned to the record containing
2025 * the requested offest.
2026 * The requested amount of data is then read from the tape device and
2027 * written to the data connection.
2030 * session (input) - session pointer.
2031 * offset (input) - data stream position to seek to.
2032 * length (input) - amount of data that will be read.
2035 * 1 - seek pending completion by the NDMP client.
2036 * 0 - seek successfully completed.
2040 ndmpd_mover_seek(ndmpd_session_t
*session
, u_longlong_t offset
,
2041 u_longlong_t length
)
2045 u_longlong_t tape_position
;
2046 u_longlong_t buf_position
;
2047 ndmp_notify_mover_paused_request pause_request
;
2049 session
->ns_mover
.md_seek_position
= offset
;
2050 session
->ns_mover
.md_bytes_left_to_read
= length
;
2053 * If the requested position is outside of the window,
2054 * notify the client that a seek is required.
2056 if (session
->ns_mover
.md_seek_position
<
2057 session
->ns_mover
.md_window_offset
||
2058 session
->ns_mover
.md_seek_position
>=
2059 session
->ns_mover
.md_window_offset
+
2060 session
->ns_mover
.md_window_length
) {
2061 NDMP_LOG(LOG_DEBUG
, "MOVER_PAUSE_SEEK(%llu)",
2062 session
->ns_mover
.md_seek_position
);
2064 session
->ns_mover
.md_w_index
= 0;
2065 session
->ns_mover
.md_r_index
= 0;
2067 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
2068 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_SEEK
;
2069 pause_request
.reason
= NDMP_MOVER_PAUSE_SEEK
;
2070 pause_request
.seek_position
= long_long_to_quad(offset
);
2072 if (ndmp_send_request(session
->ns_connection
,
2073 NDMP_NOTIFY_MOVER_PAUSED
, NDMP_NO_ERR
,
2074 (void *) &pause_request
, 0) < 0) {
2076 "Sending notify_mover_paused request");
2082 * Determine the data stream position of the first byte in the
2085 buf_position
= session
->ns_mover
.md_position
-
2086 (session
->ns_mover
.md_position
% session
->ns_mover
.md_record_size
);
2089 * Determine the data stream position of the next byte that
2090 * will be read from tape.
2092 tape_position
= buf_position
;
2093 if (session
->ns_mover
.md_w_index
!= 0)
2094 tape_position
+= session
->ns_mover
.md_record_size
;
2097 * Check if requested position is for data that has been read and is
2100 if (offset
>= buf_position
&& offset
< tape_position
) {
2101 session
->ns_mover
.md_position
= offset
;
2102 session
->ns_mover
.md_r_index
= session
->ns_mover
.md_position
-
2105 NDMP_LOG(LOG_DEBUG
, "pos %llu r_index %u",
2106 session
->ns_mover
.md_position
,
2107 session
->ns_mover
.md_r_index
);
2113 if (tape_position
> session
->ns_mover
.md_seek_position
) {
2114 /* Need to seek backward. */
2116 ctlcnt
= (int)((tape_position
- offset
- 1)
2117 / session
->ns_mover
.md_record_size
) + 1;
2118 tape_position
-= ((u_longlong_t
)(((tape_position
- offset
- 1) /
2119 session
->ns_mover
.md_record_size
) + 1) *
2120 (u_longlong_t
)session
->ns_mover
.md_record_size
);
2122 } else if (offset
>= tape_position
+ session
->ns_mover
.md_record_size
) {
2123 /* Need to seek forward. */
2125 ctlcnt
= (int)((offset
- tape_position
)
2126 / session
->ns_mover
.md_record_size
);
2127 tape_position
+= ((u_longlong_t
)(((offset
- tape_position
) /
2128 session
->ns_mover
.md_record_size
)) *
2129 (u_longlong_t
)session
->ns_mover
.md_record_size
);
2131 /* Reposition the tape if necessary. */
2133 NDMP_LOG(LOG_DEBUG
, "cmd %d count %d",
2135 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, ctlcmd
, ctlcnt
);
2138 session
->ns_mover
.md_position
= tape_position
;
2139 session
->ns_mover
.md_r_index
= 0;
2140 session
->ns_mover
.md_w_index
= 0;
2142 NDMP_LOG(LOG_DEBUG
, "pos %llu", session
->ns_mover
.md_position
);
2148 /* ** static functions ************************************************** */
2151 * create_listen_socket_v2
2153 * Creates a socket for listening for accepting data connections.
2156 * session (input) - session pointer.
2157 * addr (output) - location to store address of socket.
2158 * port (output) - location to store port of socket.
2165 create_listen_socket_v2(ndmpd_session_t
*session
, ulong_t
*addr
, ushort_t
*port
)
2167 session
->ns_mover
.md_listen_sock
= ndmp_create_socket(addr
, port
);
2168 if (session
->ns_mover
.md_listen_sock
< 0)
2172 * Add a file handler for the listen socket.
2173 * ndmpd_select will call accept_connection when a
2174 * connection is ready to be accepted.
2176 if (ndmpd_add_file_handler(session
, (void *) session
,
2177 session
->ns_mover
.md_listen_sock
, NDMPD_SELECT_MODE_READ
, HC_MOVER
,
2178 accept_connection
) < 0) {
2179 (void) close(session
->ns_mover
.md_listen_sock
);
2180 session
->ns_mover
.md_listen_sock
= -1;
2184 NDMP_LOG(LOG_DEBUG
, "addr: 0x%x, port: %d", *addr
, *port
);
2191 * Accept a data connection from a data server.
2192 * Called by ndmpd_select when a connection is pending on
2193 * the mover listen socket.
2196 * cookie (input) - session pointer.
2197 * fd (input) - file descriptor.
2198 * mode (input) - select mode.
2205 accept_connection(void *cookie
, int fd
, ulong_t mode
)
2207 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
2208 struct sockaddr_in from
;
2211 from_len
= sizeof (from
);
2212 session
->ns_mover
.md_sock
= accept(fd
, (struct sockaddr
*)&from
,
2215 (void) ndmpd_remove_file_handler(session
, fd
);
2216 (void) close(session
->ns_mover
.md_listen_sock
);
2217 session
->ns_mover
.md_listen_sock
= -1;
2219 if (session
->ns_mover
.md_sock
< 0) {
2220 NDMP_LOG(LOG_DEBUG
, "Accept error: %m");
2221 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_ERROR
);
2224 set_socket_options(session
->ns_mover
.md_sock
);
2226 NDMP_LOG(LOG_DEBUG
, "sock fd: %d", session
->ns_mover
.md_sock
);
2228 if (session
->ns_mover
.md_mode
== NDMP_MOVER_MODE_READ
) {
2229 if (start_mover_for_backup(session
) < 0) {
2230 ndmpd_mover_error(session
,
2231 NDMP_MOVER_HALT_INTERNAL_ERROR
);
2234 NDMP_LOG(LOG_DEBUG
, "Backup connection established by %s:%d",
2235 inet_ntoa(IN_ADDR(from
.sin_addr
.s_addr
)),
2236 ntohs(from
.sin_port
));
2238 NDMP_LOG(LOG_DEBUG
, "Restore connection established by %s:%d",
2239 inet_ntoa(IN_ADDR(from
.sin_addr
.s_addr
)),
2240 ntohs(from
.sin_port
));
2243 NDMP_LOG(LOG_DEBUG
, "Received connection");
2245 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
2251 * Reads a data record from tape. Detects and handles EOT conditions.
2254 * session (input) - session pointer.
2255 * data (input) - location to read data to.
2258 * 0 - operation aborted.
2259 * -1 - tape read error.
2260 * otherwise - number of bytes read.
2263 tape_read(ndmpd_session_t
*session
, char *data
)
2267 int count
= session
->ns_mover
.md_record_size
;
2270 n
= read(session
->ns_tape
.td_fd
, data
, count
);
2272 NDMP_LOG(LOG_ERR
, "Tape read error: %m.");
2273 return (TAPE_READ_ERR
);
2278 if (!is_writer_running(session
))
2279 return (TAPE_NO_WRITER_ERR
);
2282 * End of media reached.
2283 * Notify client and wait for the client to
2284 * either abort the data operation or continue the
2285 * operation after changing the tape.
2287 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
2289 "End of tape reached. Load next tape");
2292 "End of tape reached. Load next tape");
2294 err
= change_tape(session
);
2296 /* Operation aborted or connection terminated? */
2299 * K.L. Go back one record if it is read
2303 if (count
!= session
->ns_mover
.md_record_size
) {
2304 (void) ndmp_mtioctl(
2305 session
->ns_tape
.td_fd
, MTBSR
, 1);
2309 /* Retry the read from the new tape. */
2313 /* Change to pass Veritas Netbackup prequal test. */
2317 session
->ns_mover
.md_record_num
++;
2318 session
->ns_tape
.td_record_count
++;
2327 * Send a notify_pause request (protocol version 1) or
2328 * notify_mover_pause request (protocol version 2) to the
2329 * NDMP client to inform
2330 * the client that a tape volume change is required.
2331 * Process messages until the data/mover operation is either aborted
2335 * client_data (input) - session pointer.
2338 * 0 - operation has been continued.
2339 * -1 - operation has been aborted.
2342 change_tape(ndmpd_session_t
*session
)
2344 ndmp_notify_mover_paused_request request
;
2346 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
2348 if (session
->ns_mover
.md_mode
== NDMP_MOVER_MODE_READ
)
2349 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_EOM
;
2351 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_EOF
;
2353 request
.reason
= session
->ns_mover
.md_pause_reason
;
2354 request
.seek_position
= long_long_to_quad(0LL);
2356 NDMP_LOG(LOG_DEBUG
, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2357 session
->ns_mover
.md_pause_reason
);
2359 if (ndmp_send_request(session
->ns_connection
,
2360 NDMP_NOTIFY_MOVER_PAUSED
, NDMP_NO_ERR
,
2361 (void *) &request
, 0) < 0) {
2363 "Sending notify_mover_paused request");
2367 * Wait for until the state is changed by
2368 * an abort or continue request.
2370 return (ndmp_wait_for_mover(session
));
2377 * Read and discard data from the data connection.
2378 * Called when a module has called ndmpd_seek() prior to
2379 * reading all of the data from the previous seek.
2382 * session (input) - session pointer.
2385 * number of bytes read and discarded.
2389 discard_data(ndmpd_session_t
*session
, ulong_t length
)
2394 if ((addr
= ndmp_malloc(length
)) == NULL
)
2397 /* Read and discard the data. */
2398 n
= read(session
->ns_mover
.md_sock
, addr
, length
);
2400 NDMP_LOG(LOG_ERR
, "Socket read error: %m.");
2411 * mover_tape_read_one_buf
2413 * Read one buffer from the tape. This is used by mover_tape_reader
2416 * session (input) - session pointer.
2417 * buf (input) - buffer read
2424 mover_tape_read_one_buf(ndmpd_session_t
*session
, tlm_buffer_t
*buf
)
2428 tlm_buffer_mark_empty(buf
);
2431 * If the end of the mover window has been reached,
2432 * then notify the client that a seek is needed.
2433 * Remove the file handler to prevent this function from
2434 * being called. The handler will be reinstalled in
2435 * ndmpd_mover_continue.
2438 if (session
->ns_mover
.md_position
>=
2439 session
->ns_mover
.md_window_offset
+
2440 session
->ns_mover
.md_window_length
) {
2441 ndmp_notify_mover_paused_request pause_request
;
2443 NDMP_LOG(LOG_DEBUG
, "end of mover window");
2445 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
2446 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_SEEK
;
2447 pause_request
.reason
= NDMP_MOVER_PAUSE_SEEK
;
2448 pause_request
.seek_position
=
2449 long_long_to_quad(session
->ns_mover
.md_position
);
2451 if (ndmp_send_request(session
->ns_connection
,
2452 NDMP_NOTIFY_MOVER_PAUSED
, NDMP_NO_ERR
,
2453 (void *) &pause_request
, 0) < 0) {
2455 "Sending notify_mover_paused request");
2456 ndmpd_mover_error(session
,
2457 NDMP_MOVER_HALT_INTERNAL_ERROR
);
2459 buf
->tb_errno
= EIO
;
2460 return (TAPE_READ_ERR
);
2463 n
= tape_read(session
, buf
->tb_buffer_data
);
2465 NDMP_LOG(LOG_DEBUG
, "read %d bytes from tape", n
);
2469 ndmpd_mover_error(session
,
2470 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
2471 NDMP_MOVER_HALT_INTERNAL_ERROR
));
2472 return (TAPE_READ_ERR
);
2475 buf
->tb_full
= TRUE
;
2476 buf
->tb_buffer_size
= session
->ns_mover
.md_record_size
;
2479 * Discard data if the current data stream position is
2480 * prior to the seek position. This is necessary if a seek
2481 * request set the seek pointer to a position that is not a
2482 * record boundary. The seek request handler can only position
2483 * to the start of a record.
2485 if (session
->ns_mover
.md_position
< session
->ns_mover
.md_seek_position
)
2486 session
->ns_mover
.md_position
=
2487 session
->ns_mover
.md_seek_position
;
2496 * Mover tape reader thread. It is launched when the mover is started
2500 * session (input) - session pointer.
2507 mover_tape_reader(ndmpd_session_t
*session
)
2509 int bidx
; /* buffer index */
2511 ndmp_lbr_params_t
*nlp
;
2513 tlm_buffers_t
*bufs
;
2514 tlm_cmd_t
*lcmd
; /* Local command */
2515 tlm_commands_t
*cmds
; /* Commands structure */
2517 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
2518 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2522 cmds
= &nlp
->nlp_cmds
;
2523 lcmd
= cmds
->tcs_command
;
2524 bufs
= lcmd
->tc_buffers
;
2527 cmds
->tcs_reader_count
++;
2530 * Let our parent thread know that we are running.
2532 tlm_cmd_signal(cmds
->tcs_command
, TLM_TAPE_READER
);
2534 buf
= tlm_buffer_in_buf(bufs
, &bidx
);
2535 while (cmds
->tcs_reader
== TLM_RESTORE_RUN
&&
2536 lcmd
->tc_reader
== TLM_RESTORE_RUN
) {
2537 buf
= tlm_buffer_in_buf(bufs
, NULL
);
2540 NDMP_LOG(LOG_DEBUG
, "R%d", bidx
);
2542 * The buffer is still full, wait for the consumer
2545 tlm_buffer_out_buf_timed_wait(bufs
, 100);
2548 NDMP_LOG(LOG_DEBUG
, "r%d", bidx
);
2550 rv
= mover_tape_read_one_buf(session
, buf
);
2552 * If there was an error while reading, such as
2556 NDMP_LOG(LOG_DEBUG
, "Exiting, rv: %d", rv
);
2561 * Can we do more buffering?
2563 if (is_buffer_erroneous(buf
)) {
2565 "Exiting, errno: %d, eot: %d, eof: %d",
2566 buf
->tb_errno
, buf
->tb_eot
, buf
->tb_eof
);
2570 (void) tlm_buffer_advance_in_idx(bufs
);
2571 tlm_buffer_release_in_buf(bufs
);
2572 bidx
= bufs
->tbs_buffer_in
;
2576 /* If the consumer is waiting for us, wake it up. */
2577 tlm_buffer_release_in_buf(bufs
);
2582 cmds
->tcs_reader_count
--;
2584 lcmd
->tc_writer
= TLM_STOP
;
2590 * mover_socket_write_one_buf
2592 * Write one buffer to the network socket. This is used by mover_socket_writer
2595 * session (input) - session pointer.
2596 * buf (input) - buffer read
2603 mover_socket_write_one_buf(ndmpd_session_t
*session
, tlm_buffer_t
*buf
)
2607 /* Write the data to the data connection. */
2609 n
= write(session
->ns_mover
.md_sock
, buf
->tb_buffer_data
,
2610 buf
->tb_buffer_size
);
2612 NDMP_LOG(LOG_DEBUG
, "n: %d, len: %d", n
, buf
->tb_buffer_size
);
2615 NDMP_LOG(LOG_DEBUG
, "n: %d, errno: %m", n
);
2616 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_CLOSED
);
2620 session
->ns_mover
.md_position
+= n
;
2621 session
->ns_mover
.md_bytes_left_to_read
-= n
;
2622 tlm_buffer_mark_empty(buf
);
2625 * If the read limit has been reached,
2626 * then remove the file handler to prevent this
2627 * function from getting called. The next mover_read request
2628 * will reinstall the handler.
2630 if (session
->ns_mover
.md_bytes_left_to_read
== 0) {
2631 NDMP_LOG(LOG_DEBUG
, "bytes_left_to_read == 0");
2632 (void) ndmpd_remove_file_handler(session
,
2633 session
->ns_mover
.md_sock
);
2643 * mover_socket_writer
2645 * Mover's socket writer thread. This thread sends the read buffer
2646 * from the tape to the data server through the network socket.
2649 * session (input) - session pointer.
2656 mover_socket_writer(ndmpd_session_t
*session
)
2658 int bidx
; /* buffer index */
2659 ndmp_lbr_params_t
*nlp
;
2661 tlm_buffers_t
*bufs
;
2662 tlm_cmd_t
*lcmd
; /* Local command */
2663 tlm_commands_t
*cmds
; /* Commands structure */
2665 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
2666 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2670 cmds
= &nlp
->nlp_cmds
;
2671 lcmd
= cmds
->tcs_command
;
2672 bufs
= lcmd
->tc_buffers
;
2675 cmds
->tcs_writer_count
++;
2678 * Let our parent thread know that we are running.
2680 tlm_cmd_signal(cmds
->tcs_command
, TLM_SOCK_WRITER
);
2682 bidx
= bufs
->tbs_buffer_out
;
2683 while (cmds
->tcs_writer
!= (int)TLM_ABORT
&&
2684 lcmd
->tc_writer
!= (int)TLM_ABORT
) {
2685 buf
= &bufs
->tbs_buffer
[bidx
];
2688 NDMP_LOG(LOG_DEBUG
, "w%d", bidx
);
2690 if (mover_socket_write_one_buf(session
, buf
) < 0) {
2692 "mover_socket_write_one_buf() < 0");
2696 (void) tlm_buffer_advance_out_idx(bufs
);
2697 tlm_buffer_release_out_buf(bufs
);
2698 bidx
= bufs
->tbs_buffer_out
;
2700 if (lcmd
->tc_writer
!= TLM_RESTORE_RUN
) {
2701 /* No more data is coming, time to exit */
2702 NDMP_LOG(LOG_DEBUG
, "Time to exit");
2705 NDMP_LOG(LOG_DEBUG
, "W%d", bidx
);
2707 * The buffer is not full, wait for the producer
2708 * thread to fill it.
2710 tlm_buffer_in_buf_timed_wait(bufs
, 100);
2714 if (cmds
->tcs_writer
== (int)TLM_ABORT
)
2715 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_writer == (int)TLM_ABORT");
2716 if (lcmd
->tc_writer
== (int)TLM_ABORT
)
2717 NDMP_LOG(LOG_DEBUG
, "lcmd->tc_writer == TLM_ABORT");
2719 /* If the producer is waiting for us, wake it up. */
2720 tlm_buffer_release_out_buf(bufs
);
2725 cmds
->tcs_writer_count
--;
2727 lcmd
->tc_reader
= TLM_STOP
;
2733 * start_mover_for_restore
2735 * Creates the mover tape reader and network writer threads for
2736 * the mover to perform the 3-way restore.
2739 * session (input) - session pointer.
2746 start_mover_for_restore(ndmpd_session_t
*session
)
2748 ndmp_lbr_params_t
*nlp
;
2749 tlm_commands_t
*cmds
;
2753 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
2754 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2758 cmds
= &nlp
->nlp_cmds
;
2759 (void) memset(cmds
, 0, sizeof (*cmds
));
2760 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_RESTORE_RUN
;
2761 xfer_size
= ndmp_buffer_get_size(session
);
2762 cmds
->tcs_command
= tlm_create_reader_writer_ipc(FALSE
, xfer_size
);
2763 if (cmds
->tcs_command
== NULL
)
2766 cmds
->tcs_command
->tc_reader
= TLM_RESTORE_RUN
;
2767 cmds
->tcs_command
->tc_writer
= TLM_RESTORE_RUN
;
2770 * We intentionnally don't wait for the threads to start since the
2771 * reply of the request (which resulted in calling this function)
2772 * must be sent to the client before probable errors are sent
2775 rc
= pthread_create(NULL
, NULL
, (funct_t
)mover_tape_reader
, session
);
2777 tlm_cmd_wait(cmds
->tcs_command
, TLM_TAPE_READER
);
2779 NDMP_LOG(LOG_DEBUG
, "Launch mover_tape_reader: %s",
2784 rc
= pthread_create(NULL
, NULL
, (funct_t
)mover_socket_writer
, session
);
2786 tlm_cmd_wait(cmds
->tcs_command
, TLM_SOCK_WRITER
);
2788 NDMP_LOG(LOG_DEBUG
, "Launch mover_socket_writer: %s",
2793 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
2799 * mover_socket_read_one_buf
2801 * Read one buffer from the network socket for the mover. This is used
2802 * by mover_socket_reader
2805 * session (input) - session pointer.
2806 * buf (input) - buffer read
2807 * read_size (input) - size to be read
2814 mover_socket_read_one_buf(ndmpd_session_t
*session
, tlm_buffer_t
*buf
,
2820 tlm_buffer_mark_empty(buf
);
2821 for (index
= 0, toread
= read_size
; toread
> 0; ) {
2823 NDMP_LOG(LOG_DEBUG
, "index: %d, toread: %d", index
, toread
);
2825 n
= read(session
->ns_mover
.md_sock
, &buf
->tb_buffer_data
[index
],
2828 NDMP_LOG(LOG_DEBUG
, "n: %d", n
);
2831 NDMP_LOG(LOG_DEBUG
, "n: %d", n
);
2836 buf
->tb_errno
= errno
;
2837 buf
->tb_buffer_size
= 0;
2838 NDMP_LOG(LOG_DEBUG
, "n: %d, errno: %m", n
);
2844 buf
->tb_full
= TRUE
;
2845 buf
->tb_buffer_size
= read_size
;
2847 (void) memset(&buf
->tb_buffer_data
[index
], 0,
2851 buf
->tb_buffer_size
= 0;
2854 NDMP_LOG(LOG_DEBUG
, "full: %d, eot: %d, eof: %d,"
2855 " errno: %d, size: %d, data: 0x%x",
2856 buf
->tb_full
, buf
->tb_eot
, buf
->tb_eof
, buf
->tb_errno
,
2857 buf
->tb_buffer_size
, buf
->tb_buffer_data
);
2865 * mover_socket_reader
2867 * Mover socket reader thread. This is used when reading data from the
2868 * network socket for performing remote backups.
2871 * session (input) - session pointer.
2878 mover_socket_reader(ndmpd_session_t
*session
)
2880 int bidx
; /* buffer index */
2881 ndmp_lbr_params_t
*nlp
;
2883 tlm_buffers_t
*bufs
;
2884 tlm_cmd_t
*lcmd
; /* Local command */
2885 tlm_commands_t
*cmds
; /* Commands structure */
2888 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
2889 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
2893 cmds
= &nlp
->nlp_cmds
;
2894 lcmd
= cmds
->tcs_command
;
2895 bufs
= lcmd
->tc_buffers
;
2898 cmds
->tcs_reader_count
++;
2901 * Let our parent thread know that we are running.
2903 tlm_cmd_signal(cmds
->tcs_command
, TLM_SOCK_READER
);
2905 bidx
= bufs
->tbs_buffer_in
;
2906 while (cmds
->tcs_reader
== TLM_BACKUP_RUN
&&
2907 lcmd
->tc_reader
== TLM_BACKUP_RUN
) {
2908 buf
= &bufs
->tbs_buffer
[bidx
];
2911 NDMP_LOG(LOG_DEBUG
, "R%d", bidx
);
2913 * The buffer is still full, wait for the consumer
2916 tlm_buffer_out_buf_timed_wait(bufs
, 100);
2918 NDMP_LOG(LOG_DEBUG
, "r%d, nr: %d", bidx
, ++nr
);
2920 (void) mover_socket_read_one_buf(session
, buf
,
2921 bufs
->tbs_data_transfer_size
);
2924 * Can we do more buffering?
2926 if (is_buffer_erroneous(buf
)) {
2928 "Exiting, errno: %d, eot: %d, eof: %d",
2929 buf
->tb_errno
, buf
->tb_eot
, buf
->tb_eof
);
2933 (void) tlm_buffer_advance_in_idx(bufs
);
2934 tlm_buffer_release_in_buf(bufs
);
2935 bidx
= bufs
->tbs_buffer_in
;
2939 if (cmds
->tcs_reader
!= TLM_BACKUP_RUN
)
2940 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_reader != TLM_BACKUP_RUN");
2941 if (lcmd
->tc_reader
!= TLM_BACKUP_RUN
)
2942 NDMP_LOG(LOG_DEBUG
, "lcmd->tc_reader != TLM_BACKUP_RUN");
2943 NDMP_LOG(LOG_DEBUG
, "nr: %d", nr
);
2945 /* If the consumer is waiting for us, wake it up. */
2946 tlm_buffer_release_in_buf(bufs
);
2951 cmds
->tcs_reader_count
--;
2953 lcmd
->tc_writer
= TLM_STOP
;
2959 * mover_tape_writer_one_buf
2961 * Write one buffer for the mover to the local tape device. This is
2962 * used by mover_tape_writer thread.
2965 * session (input) - session pointer.
2966 * buf (input) - buffer read
2973 mover_tape_write_one_buf(ndmpd_session_t
*session
, tlm_buffer_t
*buf
)
2977 NDMP_LOG(LOG_DEBUG
, "full: %d, eot: %d, eof: %d,"
2978 " errno: %d, size: %d, data: 0x%x",
2979 buf
->tb_full
, buf
->tb_eot
, buf
->tb_eof
, buf
->tb_errno
,
2980 buf
->tb_buffer_size
, buf
->tb_buffer_data
);
2982 n
= mover_tape_write_v3(session
, buf
->tb_buffer_data
,
2983 buf
->tb_buffer_size
);
2985 NDMP_LOG(LOG_DEBUG
, "n: %d", n
);
2988 ndmpd_mover_error(session
, (n
== 0 ? NDMP_MOVER_HALT_ABORTED
2989 : NDMP_MOVER_HALT_INTERNAL_ERROR
));
2992 session
->ns_mover
.md_position
+= n
;
2993 session
->ns_mover
.md_data_written
+= n
;
2994 session
->ns_mover
.md_record_num
++;
2996 NDMP_LOG(LOG_DEBUG
, "Calling tlm_buffer_mark_empty(buf)");
2997 tlm_buffer_mark_empty(buf
);
3006 * Mover tape writer thread. This is used for performing remote backups
3007 * in a 3-way configuration. It writes the data from network socket to
3008 * the locally attached tape device.
3011 * session (input) - session pointer.
3018 mover_tape_writer(ndmpd_session_t
*session
)
3021 ndmp_lbr_params_t
*nlp
;
3023 tlm_buffers_t
*bufs
;
3025 tlm_commands_t
*cmds
;
3028 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
3029 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
3033 cmds
= &nlp
->nlp_cmds
;
3034 lcmd
= cmds
->tcs_command
;
3035 bufs
= lcmd
->tc_buffers
;
3038 cmds
->tcs_writer_count
++;
3041 * Let our parent thread know that we are running.
3043 tlm_cmd_signal(cmds
->tcs_command
, TLM_TAPE_WRITER
);
3045 bidx
= bufs
->tbs_buffer_out
;
3046 buf
= &bufs
->tbs_buffer
[bidx
];
3047 while (cmds
->tcs_writer
!= (int)TLM_ABORT
&&
3048 lcmd
->tc_writer
!= (int)TLM_ABORT
) {
3050 NDMP_LOG(LOG_DEBUG
, "w%d, nw: %d", bidx
, ++nw
);
3052 if (mover_tape_write_one_buf(session
, buf
) < 0) {
3054 "mover_tape_write_one_buf() failed");
3058 (void) tlm_buffer_advance_out_idx(bufs
);
3059 tlm_buffer_release_out_buf(bufs
);
3060 bidx
= bufs
->tbs_buffer_out
;
3061 buf
= &bufs
->tbs_buffer
[bidx
];
3063 if (lcmd
->tc_writer
!= TLM_BACKUP_RUN
) {
3064 /* No more data is coming, time to exit */
3065 NDMP_LOG(LOG_DEBUG
, "Time to exit");
3068 NDMP_LOG(LOG_DEBUG
, "W%d", bidx
);
3070 * The buffer is not full, wait for the producer
3071 * thread to fill it.
3073 tlm_buffer_in_buf_timed_wait(bufs
, 100);
3077 if (cmds
->tcs_writer
== (int)TLM_ABORT
)
3078 NDMP_LOG(LOG_DEBUG
, "cmds->tcs_writer == TLM_ABORT");
3079 if (lcmd
->tc_writer
== (int)TLM_ABORT
)
3080 NDMP_LOG(LOG_DEBUG
, "lcmd->tc_writer == TLM_ABORT");
3081 NDMP_LOG(LOG_DEBUG
, "nw: %d", nw
);
3083 if (buf
->tb_errno
== 0) {
3084 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_CLOSED
);
3086 NDMP_LOG(LOG_DEBUG
, "buf->tb_errno: %d", buf
->tb_errno
);
3087 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
3090 /* If the producer is waiting for us, wake it up. */
3091 tlm_buffer_release_out_buf(bufs
);
3096 cmds
->tcs_writer_count
--;
3098 lcmd
->tc_reader
= TLM_STOP
;
3104 * start_mover_for_backup
3106 * Starts a remote backup by running socket reader and tape
3107 * writer threads. The mover runs a remote backup in a 3-way backup
3111 * session (input) - session pointer.
3118 start_mover_for_backup(ndmpd_session_t
*session
)
3120 ndmp_lbr_params_t
*nlp
;
3121 tlm_commands_t
*cmds
;
3124 if ((nlp
= ndmp_get_nlp(session
)) == NULL
) {
3125 NDMP_LOG(LOG_DEBUG
, "nlp == NULL");
3129 cmds
= &nlp
->nlp_cmds
;
3130 (void) memset(cmds
, 0, sizeof (*cmds
));
3131 cmds
->tcs_reader
= cmds
->tcs_writer
= TLM_BACKUP_RUN
;
3132 cmds
->tcs_command
= tlm_create_reader_writer_ipc(TRUE
,
3133 session
->ns_mover
.md_record_size
);
3134 if (cmds
->tcs_command
== NULL
)
3137 cmds
->tcs_command
->tc_reader
= TLM_BACKUP_RUN
;
3138 cmds
->tcs_command
->tc_writer
= TLM_BACKUP_RUN
;
3141 * We intentionally don't wait for the threads to start since the
3142 * reply of the request (which resulted in calling this function)
3143 * must be sent to the client before probable errors are sent
3146 rc
= pthread_create(NULL
, NULL
, (funct_t
)mover_socket_reader
, session
);
3148 tlm_cmd_wait(cmds
->tcs_command
, TLM_SOCK_READER
);
3150 NDMP_LOG(LOG_DEBUG
, "Launch mover_socket_reader: %s",
3155 rc
= pthread_create(NULL
, NULL
, (funct_t
)mover_tape_writer
, session
);
3157 tlm_cmd_wait(cmds
->tcs_command
, TLM_TAPE_WRITER
);
3159 NDMP_LOG(LOG_DEBUG
, "Launch mover_tape_writer: %s",
3164 tlm_release_reader_writer_ipc(cmds
->tcs_command
);
3172 * Find out if the writer thread has started or not.
3175 * session (input) - session pointer.
3180 * Note: non-zero is also returned if the backup type is
3181 * neither TAR nor DUMP. I.e. the is_writer_running()
3182 * check does not apply in this case and things should
3183 * appear successful.
3186 is_writer_running(ndmpd_session_t
*session
)
3189 ndmp_lbr_params_t
*nlp
;
3191 if (session
&& (session
->ns_butype
> NDMP_BUTYPE_DUMP
))
3194 if (session
== NULL
)
3196 else if ((nlp
= ndmp_get_nlp(session
)) == NULL
)
3199 rv
= (nlp
->nlp_cmds
.tcs_writer_count
> 0);
3206 * is_writer_running_v3
3208 * Find out if the writer thread has started or not.
3211 * session (input) - session pointer.
3216 * Note: non-zero is also returned if the backup type is
3217 * neither TAR nor DUMP. I.e. the is_writer_running()
3218 * check does not apply in this case and things should
3219 * appear successful.
3222 is_writer_running_v3(ndmpd_session_t
*session
)
3225 ndmp_lbr_params_t
*nlp
;
3227 if (session
&& (session
->ns_butype
> NDMP_BUTYPE_DUMP
))
3230 if (session
== NULL
)
3232 else if (session
->ns_mover
.md_data_addr
.addr_type
== NDMP_ADDR_TCP
)
3234 else if ((nlp
= ndmp_get_nlp(session
)) == NULL
)
3237 rv
= (nlp
->nlp_cmds
.tcs_writer_count
> 0);
3244 * ndmpd_mover_error_send
3246 * This function sends the notify message to the client.
3249 * session (input) - session pointer.
3250 * reason (input) - halt reason.
3256 ndmpd_mover_error_send(ndmpd_session_t
*session
, ndmp_mover_halt_reason reason
)
3258 ndmp_notify_mover_halted_request req
;
3260 req
.reason
= reason
;
3261 req
.text_reason
= "";
3263 return (ndmp_send_request(session
->ns_connection
,
3264 NDMP_NOTIFY_MOVER_HALTED
, NDMP_NO_ERR
, (void *)&req
, 0));
3269 * ndmpd_mover_error_send_v4
3271 * This function sends the notify message to the client.
3274 * session (input) - session pointer.
3275 * reason (input) - halt reason.
3281 ndmpd_mover_error_send_v4(ndmpd_session_t
*session
,
3282 ndmp_mover_halt_reason reason
)
3284 ndmp_notify_mover_halted_request_v4 req
;
3286 req
.reason
= reason
;
3288 return (ndmp_send_request(session
->ns_connection
,
3289 NDMP_NOTIFY_MOVER_HALTED
, NDMP_NO_ERR
, (void *)&req
, 0));
3296 * This function is called when an unrecoverable mover error
3297 * has been detected. A notify message is sent to the client and the
3298 * mover is placed into the halted state.
3301 * session (input) - session pointer.
3302 * reason (input) - halt reason.
3308 ndmpd_mover_error(ndmpd_session_t
*session
, ndmp_mover_halt_reason reason
)
3310 ndmp_lbr_params_t
*nlp
= ndmp_get_nlp(session
);
3312 if (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_HALTED
||
3313 (session
->ns_protocol_version
> NDMPV2
&&
3314 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_IDLE
))
3317 if (session
->ns_protocol_version
== NDMPV4
) {
3318 if (ndmpd_mover_error_send_v4(session
, reason
) < 0)
3320 "Error sending notify_mover_halted request");
3322 /* No media error in V3 */
3323 if (reason
== NDMP_MOVER_HALT_MEDIA_ERROR
)
3324 reason
= NDMP_MOVER_HALT_INTERNAL_ERROR
;
3325 if (ndmpd_mover_error_send(session
, reason
) < 0)
3327 "Error sending notify_mover_halted request");
3330 (void) mutex_lock(&nlp
->nlp_mtx
);
3331 if (session
->ns_mover
.md_listen_sock
!= -1) {
3332 (void) ndmpd_remove_file_handler(session
,
3333 session
->ns_mover
.md_listen_sock
);
3334 (void) close(session
->ns_mover
.md_listen_sock
);
3335 session
->ns_mover
.md_listen_sock
= -1;
3337 if (session
->ns_mover
.md_sock
!= -1) {
3338 (void) ndmpd_remove_file_handler(session
,
3339 session
->ns_mover
.md_sock
);
3340 (void) close(session
->ns_mover
.md_sock
);
3341 session
->ns_mover
.md_sock
= -1;
3344 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_HALTED
;
3345 session
->ns_mover
.md_halt_reason
= reason
;
3346 (void) cond_broadcast(&nlp
->nlp_cv
);
3347 (void) mutex_unlock(&nlp
->nlp_mtx
);
3354 * Send an ndmp_notify_mover_paused request to the
3355 * NDMP client to inform the client that its attention is required.
3356 * Process messages until the data/mover operation is either aborted
3360 * client_data (input) - session pointer.
3361 * reason (input) - pause reason.
3364 * 0 - operation has been continued.
3365 * -1 - operation has been aborted.
3368 mover_pause_v3(ndmpd_session_t
*session
, ndmp_mover_pause_reason reason
)
3371 ndmp_notify_mover_paused_request request
;
3374 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
3375 session
->ns_mover
.md_pause_reason
= reason
;
3376 session
->ns_mover
.md_pre_cond
= FALSE
;
3378 request
.reason
= session
->ns_mover
.md_pause_reason
;
3379 request
.seek_position
=
3380 long_long_to_quad(session
->ns_mover
.md_position
);
3382 if (ndmp_send_request(session
->ns_connection
, NDMP_NOTIFY_MOVER_PAUSED
,
3383 NDMP_NO_ERR
, (void *)&request
, 0) < 0) {
3385 "Error sending notify_mover_paused_request");
3390 * 3-way operations are single-thread. The same thread
3391 * should process the messages.
3393 * 2-way operations are multi-thread. The main thread
3394 * processes the messages. We just need to wait and
3395 * see if the mover state changes or the operation aborts.
3397 if (session
->ns_mover
.md_data_addr
.addr_type
== NDMP_ADDR_TCP
) {
3399 * Process messages until the state is changed by
3400 * an abort, continue, or close request .
3403 if (ndmpd_select(session
, TRUE
, HC_CLIENT
) < 0)
3406 if (session
->ns_eof
== TRUE
)
3409 switch (session
->ns_mover
.md_state
) {
3410 case NDMP_MOVER_STATE_ACTIVE
:
3411 session
->ns_tape
.td_record_count
= 0;
3414 case NDMP_MOVER_STATE_PAUSED
:
3423 if (session
->ns_mover
.md_data_addr
.addr_type
==
3425 rv
= ndmp_wait_for_mover(session
);
3427 NDMP_LOG(LOG_DEBUG
, "Invalid address type %d",
3428 session
->ns_mover
.md_data_addr
.addr_type
);
3438 * mover_tape_write_v3
3440 * Writes a data record to tape. Detects and handles EOT conditions.
3443 * session (input) - session pointer.
3444 * data (input) - data to be written.
3445 * length (input) - length of data to be written.
3448 * 0 - operation aborted by client.
3450 * otherwise - number of bytes written.
3453 mover_tape_write_v3(ndmpd_session_t
*session
, char *data
, ssize_t length
)
3456 ssize_t count
= length
;
3460 * Enforce mover window on write.
3462 if (session
->ns_mover
.md_position
>=
3463 session
->ns_mover
.md_window_offset
+
3464 session
->ns_mover
.md_window_length
) {
3465 NDMP_LOG(LOG_DEBUG
, "MOVER_PAUSE_EOW");
3467 if (mover_pause_v3(session
, NDMP_MOVER_PAUSE_EOW
) < 0)
3468 /* Operation aborted or connection terminated */
3473 n
= write(session
->ns_tape
.td_fd
, data
, count
);
3475 NDMP_LOG(LOG_ERR
, "Tape write error: %m.");
3481 session
->ns_tape
.td_record_count
++;
3486 struct mtget mtstatus
;
3488 (void) ioctl(session
->ns_tape
.td_fd
, MTIOCGET
,
3490 NDMP_LOG(LOG_DEBUG
, "EOM detected (%d written bytes, "
3491 "mover record %d, file #%d, block #%d)", n
,
3492 session
->ns_tape
.td_record_count
,
3493 mtstatus
.mt_fileno
, mtstatus
.mt_blkno
);
3496 * Notify the client to either abort the operation
3497 * or change the tape.
3499 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
3501 "End of tape reached. Load next tape");
3503 if (mover_pause_v3(session
, NDMP_MOVER_PAUSE_EOM
) < 0)
3504 /* Operation aborted or connection terminated */
3514 * mover_tape_flush_v3
3516 * Writes all remaining buffered data to tape. A partial record is
3517 * padded out to a full record with zeros.
3520 * session (input) - session pointer.
3521 * data (input) - data to be written.
3522 * length (input) - length of data to be written.
3526 * otherwise - number of bytes written.
3529 mover_tape_flush_v3(ndmpd_session_t
*session
)
3533 if (session
->ns_mover
.md_w_index
== 0)
3536 (void) memset((void*)&session
->ns_mover
.md_buf
[session
->
3537 ns_mover
.md_w_index
], 0,
3538 session
->ns_mover
.md_record_size
- session
->ns_mover
.md_w_index
);
3540 n
= mover_tape_write_v3(session
, session
->ns_mover
.md_buf
,
3541 session
->ns_mover
.md_record_size
);
3543 NDMP_LOG(LOG_ERR
, "Tape write error: %m.");
3547 session
->ns_mover
.md_w_index
= 0;
3548 session
->ns_mover
.md_position
+= n
;
3554 * ndmpd_local_write_v3
3556 * Buffers and writes data to the tape device.
3557 * A full tape record is buffered before being written.
3560 * session (input) - session pointer.
3561 * data (input) - data to be written.
3562 * length (input) - data length.
3565 * 0 - data successfully written.
3569 ndmpd_local_write_v3(ndmpd_session_t
*session
, char *data
, ulong_t length
)
3575 if (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_IDLE
||
3576 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_LISTEN
||
3577 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_HALTED
) {
3578 NDMP_LOG(LOG_DEBUG
, "Invalid mover state to write data");
3583 * A length of 0 indicates that any buffered data should be
3587 if (session
->ns_mover
.md_w_index
== 0)
3590 (void) memset((void*)&session
->ns_mover
.md_buf
[session
->
3591 ns_mover
.md_w_index
], 0, session
->ns_mover
.md_record_size
-
3592 session
->ns_mover
.md_w_index
);
3594 n
= mover_tape_write_v3(session
, session
->ns_mover
.md_buf
,
3595 session
->ns_mover
.md_record_size
);
3597 ndmpd_mover_error(session
,
3598 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
3599 NDMP_MOVER_HALT_MEDIA_ERROR
));
3603 session
->ns_mover
.md_position
+= n
;
3604 session
->ns_mover
.md_data_written
+=
3605 session
->ns_mover
.md_w_index
;
3606 session
->ns_mover
.md_record_num
++;
3607 session
->ns_mover
.md_w_index
= 0;
3611 /* Break the data into records. */
3612 while (count
< length
) {
3614 * Determine if data needs to be buffered or
3615 * can be written directly from user supplied location.
3616 * We can fast path the write if there is no pending
3617 * buffered data and there is at least a full records worth
3618 * of data to be written.
3620 if (session
->ns_mover
.md_w_index
== 0 &&
3621 length
- count
>= session
->ns_mover
.md_record_size
) {
3622 n
= mover_tape_write_v3(session
, &data
[count
],
3623 session
->ns_mover
.md_record_size
);
3625 ndmpd_mover_error(session
,
3626 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
3627 NDMP_MOVER_HALT_MEDIA_ERROR
));
3631 session
->ns_mover
.md_position
+= n
;
3632 session
->ns_mover
.md_data_written
+= n
;
3633 session
->ns_mover
.md_record_num
++;
3638 /* Buffer the data */
3639 len
= length
- count
;
3640 if (len
> session
->ns_mover
.md_record_size
-
3641 session
->ns_mover
.md_w_index
)
3642 len
= session
->ns_mover
.md_record_size
-
3643 session
->ns_mover
.md_w_index
;
3645 (void) memcpy(&session
->ns_mover
.md_buf
[session
->
3646 ns_mover
.md_w_index
], &data
[count
], len
);
3647 session
->ns_mover
.md_w_index
+= len
;
3650 /* Write the buffer if its full */
3651 if (session
->ns_mover
.md_w_index
==
3652 session
->ns_mover
.md_record_size
) {
3653 n
= mover_tape_write_v3(session
,
3654 session
->ns_mover
.md_buf
,
3655 session
->ns_mover
.md_record_size
);
3657 ndmpd_mover_error(session
,
3658 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
3659 NDMP_MOVER_HALT_MEDIA_ERROR
));
3663 session
->ns_mover
.md_position
+= n
;
3664 session
->ns_mover
.md_data_written
+= n
;
3665 session
->ns_mover
.md_record_num
++;
3666 session
->ns_mover
.md_w_index
= 0;
3675 * mover_data_read_v3
3677 * Reads backup data from the data connection and writes the
3678 * received data to the tape device.
3681 * cookie (input) - session pointer.
3682 * fd (input) - file descriptor.
3683 * mode (input) - select mode.
3690 mover_data_read_v3(void *cookie
, int fd
, ulong_t mode
)
3692 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
3696 n
= read(fd
, &session
->ns_mover
.md_buf
[session
->ns_mover
.md_w_index
],
3697 session
->ns_mover
.md_record_size
- session
->ns_mover
.md_w_index
);
3700 * Since this function is only called when select believes data
3701 * is available to be read, a return of zero indicates the
3702 * connection has been closed.
3706 NDMP_LOG(LOG_DEBUG
, "Data connection closed");
3707 ndmpd_mover_error(session
,
3708 NDMP_MOVER_HALT_CONNECT_CLOSED
);
3710 /* Socket is non-blocking, perhaps there are no data */
3711 if (errno
== EAGAIN
) {
3712 NDMP_LOG(LOG_ERR
, "No data to read");
3716 NDMP_LOG(LOG_ERR
, "Failed to read from socket: %m");
3717 ndmpd_mover_error(session
,
3718 NDMP_MOVER_HALT_INTERNAL_ERROR
);
3721 /* Save the index since mover_tape_flush_v3 resets it. */
3722 index
= session
->ns_mover
.md_w_index
;
3724 /* Flush any buffered data to tape. */
3725 if (mover_tape_flush_v3(session
) > 0) {
3726 session
->ns_mover
.md_data_written
+= index
;
3727 session
->ns_mover
.md_record_num
++;
3733 NDMP_LOG(LOG_DEBUG
, "n %d", n
);
3735 session
->ns_mover
.md_w_index
+= n
;
3737 if (session
->ns_mover
.md_w_index
== session
->ns_mover
.md_record_size
) {
3738 n
= mover_tape_write_v3(session
, session
->ns_mover
.md_buf
,
3739 session
->ns_mover
.md_record_size
);
3741 ndmpd_mover_error(session
,
3742 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
3743 NDMP_MOVER_HALT_MEDIA_ERROR
));
3747 session
->ns_mover
.md_position
+= n
;
3748 session
->ns_mover
.md_w_index
= 0;
3749 session
->ns_mover
.md_data_written
+= n
;
3750 session
->ns_mover
.md_record_num
++;
3755 * mover_tape_read_v3
3757 * Reads a data record from tape. Detects and handles EOT conditions.
3760 * session (input) - session pointer.
3761 * data (input) - location to read data to.
3764 * 0 - operation aborted.
3765 * TAPE_READ_ERR - tape read IO error.
3766 * TAPE_NO_WRITER_ERR - no writer is running during tape read
3767 * otherwise - number of bytes read.
3770 mover_tape_read_v3(ndmpd_session_t
*session
, char *data
)
3777 count
= session
->ns_mover
.md_record_size
;
3779 pause_reason
= NDMP_MOVER_PAUSE_NA
;
3781 n
= read(session
->ns_tape
.td_fd
, data
, count
);
3784 * If at beginning of file and read fails with EIO,
3785 * then it's repeated attempt to read at EOT.
3787 if (errno
== EIO
&& tape_is_at_bof(session
)) {
3788 NDMP_LOG(LOG_DEBUG
, "Repeated read at EOT");
3789 pause_reason
= NDMP_MOVER_PAUSE_EOM
;
3790 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
3792 "End of tape reached. Load next tape");
3795 * According to NDMPv4 spec preferred error code when
3796 * trying to read from blank tape is NDMP_EOM_ERR.
3798 else if (errno
== EIO
&& tape_is_at_bot(session
)) {
3800 "Blank tape detected, returning EOM");
3801 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
3803 "Blank tape. Load another tape");
3804 pause_reason
= NDMP_MOVER_PAUSE_EOM
;
3806 NDMP_LOG(LOG_ERR
, "Tape read error: %m.");
3807 return (TAPE_READ_ERR
);
3813 session
->ns_tape
.td_record_count
++;
3815 if (!is_writer_running_v3(session
))
3816 return (TAPE_NO_WRITER_ERR
);
3819 * End of file or media reached. Notify client and
3820 * wait for the client to either abort the data
3821 * operation or continue the operation after changing
3824 if (tape_is_at_bof(session
)) {
3825 NDMP_LOG(LOG_DEBUG
, "EOT detected");
3826 pause_reason
= NDMP_MOVER_PAUSE_EOM
;
3827 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
3828 ++ndmp_log_msg_id
, "End of medium reached");
3830 NDMP_LOG(LOG_DEBUG
, "EOF detected");
3831 /* reposition the tape to BOT side of FM */
3833 pause_reason
= NDMP_MOVER_PAUSE_EOF
;
3834 NDMP_APILOG((void*)session
, NDMP_LOG_NORMAL
,
3835 ++ndmp_log_msg_id
, "End of file reached.");
3839 if (pause_reason
!= NDMP_MOVER_PAUSE_NA
) {
3840 err
= mover_pause_v3(session
, pause_reason
);
3842 /* Operation aborted or connection terminated? */
3846 /* Retry the read from new location */
3849 return (session
->ns_mover
.md_record_size
);
3854 * mover_data_write_v3
3856 * Reads backup data from the tape device and writes the
3857 * data to the data connection.
3858 * This function is called by ndmpd_select when the data connection
3859 * is ready for more data to be written.
3862 * cookie (input) - session pointer.
3863 * fd (input) - file descriptor.
3864 * mode (input) - select mode.
3871 mover_data_write_v3(void *cookie
, int fd
, ulong_t mode
)
3873 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
3877 ndmp_notify_mover_paused_request pause_request
;
3880 * If the end of the mover window has been reached,
3881 * then notify the client that a seek is needed.
3882 * Remove the file handler to prevent this function from
3883 * being called. The handler will be reinstalled in
3884 * ndmpd_mover_continue.
3886 if (session
->ns_mover
.md_position
>= session
->ns_mover
.md_window_offset
3887 + session
->ns_mover
.md_window_length
) {
3889 "MOVER_PAUSE_SEEK(%llu)", session
->ns_mover
.md_position
);
3891 session
->ns_mover
.md_w_index
= 0;
3892 session
->ns_mover
.md_r_index
= 0;
3894 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_PAUSED
;
3895 session
->ns_mover
.md_pause_reason
= NDMP_MOVER_PAUSE_SEEK
;
3896 pause_request
.reason
= NDMP_MOVER_PAUSE_SEEK
;
3897 pause_request
.seek_position
=
3898 long_long_to_quad(session
->ns_mover
.md_position
);
3899 session
->ns_mover
.md_seek_position
=
3900 session
->ns_mover
.md_position
;
3902 (void) ndmpd_remove_file_handler(session
, fd
);
3904 if (ndmp_send_request(session
->ns_connection
,
3905 NDMP_NOTIFY_MOVER_PAUSED
, NDMP_NO_ERR
,
3906 (void *)&pause_request
, 0) < 0) {
3908 "Sending notify_mover_paused request");
3909 ndmpd_mover_error(session
,
3910 NDMP_MOVER_HALT_INTERNAL_ERROR
);
3916 * Read more data into the tape buffer if the buffer is empty.
3918 if (session
->ns_mover
.md_w_index
== 0) {
3919 n
= mover_tape_read_v3(session
, session
->ns_mover
.md_buf
);
3922 "read %u bytes from tape", n
);
3925 ndmpd_mover_error(session
, (n
== 0 ?
3926 NDMP_MOVER_HALT_ABORTED
3927 : NDMP_MOVER_HALT_MEDIA_ERROR
));
3932 * Discard data if the current data stream position is
3933 * prior to the seek position. This is necessary if a seek
3934 * request set the seek pointer to a position that is not a
3935 * record boundary. The seek request handler can only position
3936 * to the start of a record.
3938 if (session
->ns_mover
.md_position
<
3939 session
->ns_mover
.md_seek_position
) {
3940 session
->ns_mover
.md_r_index
=
3941 session
->ns_mover
.md_seek_position
-
3942 session
->ns_mover
.md_position
;
3943 session
->ns_mover
.md_position
=
3944 session
->ns_mover
.md_seek_position
;
3947 session
->ns_mover
.md_w_index
= n
;
3948 session
->ns_mover
.md_record_num
++;
3952 * The limit on the total amount of data to be sent can be
3953 * dictated by either the end of the mover window or the end of the
3955 * First determine which window applies and then determine if the
3956 * send length needs to be less than a full record to avoid
3957 * exceeding the window.
3959 if (session
->ns_mover
.md_position
+
3960 session
->ns_mover
.md_bytes_left_to_read
>
3961 session
->ns_mover
.md_window_offset
+
3962 session
->ns_mover
.md_window_length
)
3963 wlen
= session
->ns_mover
.md_window_offset
+
3964 session
->ns_mover
.md_window_length
-
3965 session
->ns_mover
.md_position
;
3967 wlen
= session
->ns_mover
.md_bytes_left_to_read
;
3969 NDMP_LOG(LOG_DEBUG
, "wlen window restrictions: %llu", wlen
);
3972 * Now limit the length to the amount of data in the buffer.
3974 if (wlen
> session
->ns_mover
.md_w_index
- session
->ns_mover
.md_r_index
)
3975 wlen
= session
->ns_mover
.md_w_index
-
3976 session
->ns_mover
.md_r_index
;
3978 len
= wlen
& 0xffffffff;
3980 "buffer restrictions: wlen %llu len %u", wlen
, len
);
3983 * Write the data to the data connection.
3985 n
= write(session
->ns_mover
.md_sock
,
3986 &session
->ns_mover
.md_buf
[session
->ns_mover
.md_r_index
], len
);
3989 /* Socket is non-blocking, perhaps the write queue is full */
3990 if (errno
== EAGAIN
) {
3991 NDMP_LOG(LOG_ERR
, "Cannot write to socket");
3994 NDMP_LOG(LOG_ERR
, "Failed to write to socket: %m");
3995 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_CLOSED
);
4000 "wrote %u of %u bytes to data connection position %llu r_index %lu",
4001 n
, len
, session
->ns_mover
.md_position
,
4002 session
->ns_mover
.md_r_index
);
4004 session
->ns_mover
.md_r_index
+= n
;
4005 session
->ns_mover
.md_position
+= n
;
4006 session
->ns_mover
.md_bytes_left_to_read
-= n
;
4009 * If all data in the buffer has been written,
4010 * zero the buffer indices. The next call to this function
4011 * will read more data from the tape device into the buffer.
4013 if (session
->ns_mover
.md_r_index
== session
->ns_mover
.md_w_index
) {
4014 session
->ns_mover
.md_r_index
= 0;
4015 session
->ns_mover
.md_w_index
= 0;
4019 * If the read limit has been reached,
4020 * then remove the file handler to prevent this
4021 * function from getting called. The next mover_read request
4022 * will reinstall the handler.
4024 if (session
->ns_mover
.md_bytes_left_to_read
== 0)
4025 (void) ndmpd_remove_file_handler(session
, fd
);
4030 * accept_connection_v3
4032 * Accept a data connection from a data server.
4033 * Called by ndmpd_select when a connection is pending on
4034 * the mover listen socket.
4037 * cookie (input) - session pointer.
4038 * fd (input) - file descriptor.
4039 * mode (input) - select mode.
4046 accept_connection_v3(void *cookie
, int fd
, ulong_t mode
)
4048 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
4050 struct sockaddr_in from
;
4052 from_len
= sizeof (from
);
4053 session
->ns_mover
.md_sock
= accept(fd
, (struct sockaddr
*)&from
,
4056 NDMP_LOG(LOG_DEBUG
, "sin: port %d addr %s", ntohs(from
.sin_port
),
4057 inet_ntoa(IN_ADDR(from
.sin_addr
.s_addr
)));
4059 (void) ndmpd_remove_file_handler(session
, fd
);
4060 (void) close(session
->ns_mover
.md_listen_sock
);
4061 session
->ns_mover
.md_listen_sock
= -1;
4063 if (session
->ns_mover
.md_sock
< 0) {
4064 NDMP_LOG(LOG_DEBUG
, "Accept error: %m");
4065 ndmpd_mover_error(session
, NDMP_MOVER_HALT_CONNECT_ERROR
);
4070 * Save the peer address.
4072 session
->ns_mover
.md_data_addr
.tcp_ip_v3
= from
.sin_addr
.s_addr
;
4073 session
->ns_mover
.md_data_addr
.tcp_port_v3
= ntohs(from
.sin_port
);
4075 /* Set the parameter of the new socket */
4076 set_socket_options(session
->ns_mover
.md_sock
);
4079 * Backup/restore is handled by a callback called from main event loop,
4080 * which reads/writes data to md_sock socket. IO on socket must be
4081 * non-blocking, otherwise ndmpd would be unable to process other
4082 * incoming requests.
4084 if (!set_socket_nonblock(session
->ns_mover
.md_sock
)) {
4085 NDMP_LOG(LOG_ERR
, "Could not set non-blocking mode "
4087 ndmpd_mover_error(session
, NDMP_MOVER_HALT_INTERNAL_ERROR
);
4091 NDMP_LOG(LOG_DEBUG
, "sock fd: %d", session
->ns_mover
.md_sock
);
4093 if (session
->ns_mover
.md_mode
== NDMP_MOVER_MODE_READ
) {
4094 if (ndmpd_add_file_handler(session
, (void*)session
,
4095 session
->ns_mover
.md_sock
, NDMPD_SELECT_MODE_READ
,
4096 HC_MOVER
, mover_data_read_v3
) < 0) {
4097 ndmpd_mover_error(session
,
4098 NDMP_MOVER_HALT_INTERNAL_ERROR
);
4101 NDMP_LOG(LOG_DEBUG
, "Backup connection established by %s:%d",
4102 inet_ntoa(IN_ADDR(from
.sin_addr
.s_addr
)),
4103 ntohs(from
.sin_port
));
4105 NDMP_LOG(LOG_DEBUG
, "Restore connection established by %s:%d",
4106 inet_ntoa(IN_ADDR(from
.sin_addr
.s_addr
)),
4107 ntohs(from
.sin_port
));
4110 session
->ns_mover
.md_state
= NDMP_MOVER_STATE_ACTIVE
;
4115 * create_listen_socket_v3
4117 * Creates a socket for listening for accepting data connections.
4120 * session (input) - session pointer.
4121 * addr (output) - location to store address of socket.
4122 * port (output) - location to store port of socket.
4129 create_listen_socket_v3(ndmpd_session_t
*session
, ulong_t
*addr
, ushort_t
*port
)
4131 session
->ns_mover
.md_listen_sock
= ndmp_create_socket(addr
, port
);
4132 if (session
->ns_mover
.md_listen_sock
< 0)
4136 * Add a file handler for the listen socket.
4137 * ndmpd_select will call accept_connection when a
4138 * connection is ready to be accepted.
4140 if (ndmpd_add_file_handler(session
, (void *) session
,
4141 session
->ns_mover
.md_listen_sock
, NDMPD_SELECT_MODE_READ
, HC_MOVER
,
4142 accept_connection_v3
) < 0) {
4143 (void) close(session
->ns_mover
.md_listen_sock
);
4144 session
->ns_mover
.md_listen_sock
= -1;
4147 NDMP_LOG(LOG_DEBUG
, "IP %s port %d",
4148 inet_ntoa(*(struct in_addr
*)addr
), ntohs(*port
));
4154 * mover_connect_sock
4156 * Connect the mover to the specified address
4159 * session (input) - session pointer.
4160 * mode (input) - mover mode.
4161 * addr (output) - location to store address of socket.
4162 * port (output) - location to store port of socket.
4168 mover_connect_sock(ndmpd_session_t
*session
, ndmp_mover_mode mode
,
4169 ulong_t addr
, ushort_t port
)
4173 sock
= ndmp_connect_sock_v3(addr
, port
);
4175 return (NDMP_CONNECT_ERR
);
4178 * Backup/restore is handled by a callback called from main event loop,
4179 * which reads/writes data to md_sock socket. IO on socket must be
4180 * non-blocking, otherwise ndmpd would be unable to process other
4181 * incoming requests.
4183 if (!set_socket_nonblock(sock
)) {
4184 NDMP_LOG(LOG_ERR
, "Could not set non-blocking mode "
4187 return (NDMP_CONNECT_ERR
);
4190 if (mode
== NDMP_MOVER_MODE_READ
) {
4191 if (ndmpd_add_file_handler(session
, (void*)session
, sock
,
4192 NDMPD_SELECT_MODE_READ
, HC_MOVER
, mover_data_read_v3
) < 0) {
4194 return (NDMP_CONNECT_ERR
);
4197 session
->ns_mover
.md_sock
= sock
;
4198 session
->ns_mover
.md_data_addr
.addr_type
= NDMP_ADDR_TCP
;
4199 session
->ns_mover
.md_data_addr
.tcp_ip_v3
= ntohl(addr
);
4200 session
->ns_mover
.md_data_addr
.tcp_port_v3
= port
;
4201 return (NDMP_NO_ERR
);
4206 * ndmpd_local_read_v3
4208 * Reads data from the local tape device.
4209 * Full tape records are read and buffered.
4212 * session (input) - session pointer.
4213 * data (input) - location to store data.
4214 * length (input) - data length.
4217 * 1 - no read error but no writer running
4218 * 0 - data successfully read.
4222 ndmpd_local_read_v3(ndmpd_session_t
*session
, char *data
, ulong_t length
)
4229 if (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_IDLE
||
4230 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_LISTEN
||
4231 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_HALTED
) {
4232 NDMP_LOG(LOG_DEBUG
, "Invalid mover state to read data");
4237 * Automatically increase the seek window if necessary.
4238 * This is needed in the event the module attempts to read
4239 * past a seek window set via a prior call to ndmpd_seek() or
4240 * the module has not issued a seek. If no seek was issued then
4241 * pretend that a seek was issued to read the entire tape.
4243 if (length
> session
->ns_mover
.md_bytes_left_to_read
) {
4244 /* ndmpd_seek() never called? */
4245 if (session
->ns_data
.dd_read_length
== 0) {
4246 session
->ns_mover
.md_bytes_left_to_read
= ~0LL;
4247 session
->ns_data
.dd_read_offset
= 0LL;
4248 session
->ns_data
.dd_read_length
= ~0LL;
4250 session
->ns_mover
.md_bytes_left_to_read
= length
;
4251 session
->ns_data
.dd_read_offset
=
4252 session
->ns_mover
.md_position
;
4253 session
->ns_data
.dd_read_length
= length
;
4258 * Read as many records as necessary to satisfy the request.
4260 while (count
< length
) {
4262 * If the end of the mover window has been reached,
4263 * then notify the client that a new data window is needed.
4265 if (session
->ns_mover
.md_position
>=
4266 session
->ns_mover
.md_window_offset
+
4267 session
->ns_mover
.md_window_length
) {
4268 if (mover_pause_v3(session
,
4269 NDMP_MOVER_PAUSE_SEEK
) < 0) {
4270 ndmpd_mover_error(session
,
4271 NDMP_MOVER_HALT_INTERNAL_ERROR
);
4277 len
= length
- count
;
4280 * Prevent reading past the end of the window.
4282 if (len
> session
->ns_mover
.md_window_offset
+
4283 session
->ns_mover
.md_window_length
-
4284 session
->ns_mover
.md_position
)
4285 len
= session
->ns_mover
.md_window_offset
+
4286 session
->ns_mover
.md_window_length
-
4287 session
->ns_mover
.md_position
;
4290 * Copy from the data buffer first.
4292 if (session
->ns_mover
.md_w_index
-
4293 session
->ns_mover
.md_r_index
!= 0) {
4295 * Limit the copy to the amount of data in the buffer.
4297 if (len
> session
->ns_mover
.md_w_index
-
4298 session
->ns_mover
.md_r_index
)
4299 len
= session
->ns_mover
.md_w_index
-
4300 session
->ns_mover
.md_r_index
;
4301 (void) memcpy((void*)&data
[count
],
4302 &session
->ns_mover
.md_buf
[session
->
4303 ns_mover
.md_r_index
], len
);
4305 session
->ns_mover
.md_r_index
+= len
;
4306 session
->ns_mover
.md_bytes_left_to_read
-= len
;
4307 session
->ns_mover
.md_position
+= len
;
4312 * Determine if data needs to be buffered or
4313 * can be read directly to user supplied location.
4314 * We can fast path the read if at least a full record
4315 * needs to be read and there is no seek pending.
4316 * This is done to eliminate a buffer copy.
4318 if (len
>= session
->ns_mover
.md_record_size
&&
4319 session
->ns_mover
.md_position
>=
4320 session
->ns_mover
.md_seek_position
) {
4321 n
= mover_tape_read_v3(session
, &data
[count
]);
4323 if (n
== TAPE_NO_WRITER_ERR
)
4326 ndmpd_mover_error(session
,
4327 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
4328 NDMP_MOVER_HALT_MEDIA_ERROR
));
4329 return ((n
== 0) ? 1 : -1);
4333 session
->ns_mover
.md_bytes_left_to_read
-= n
;
4334 session
->ns_mover
.md_position
+= n
;
4335 session
->ns_mover
.md_record_num
++;
4339 /* Read the next record into the buffer. */
4340 n
= mover_tape_read_v3(session
, session
->ns_mover
.md_buf
);
4342 if (n
== TAPE_NO_WRITER_ERR
)
4345 ndmpd_mover_error(session
,
4346 (n
== 0 ? NDMP_MOVER_HALT_ABORTED
:
4347 NDMP_MOVER_HALT_MEDIA_ERROR
));
4348 return ((n
== 0) ? 1 : -1);
4351 session
->ns_mover
.md_w_index
= n
;
4352 session
->ns_mover
.md_r_index
= 0;
4353 session
->ns_mover
.md_record_num
++;
4355 NDMP_LOG(LOG_DEBUG
, "n: %d", n
);
4358 * Discard data if the current data stream position is
4359 * prior to the seek position. This is necessary if a seek
4360 * request set the seek pointer to a position that is not a
4361 * record boundary. The seek request handler can only position
4362 * to the start of a record.
4364 if (session
->ns_mover
.md_position
<
4365 session
->ns_mover
.md_seek_position
) {
4366 session
->ns_mover
.md_r_index
=
4367 session
->ns_mover
.md_seek_position
-
4368 session
->ns_mover
.md_position
;
4369 session
->ns_mover
.md_position
=
4370 session
->ns_mover
.md_seek_position
;