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