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