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