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