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 41 #include <sys/ioctl.h> 42 #include <sys/types.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <netinet/in.h> 46 #include <arpa/inet.h> 47 #include <net/if.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <netdb.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <string.h> 54 #include "ndmpd_common.h" 55 #include "ndmpd.h" 56 #include <sys/mtio.h> 57 58 /* 59 * Maximum mover record size 60 */ 61 #define MAX_MOVER_RECSIZE (512*KILOBYTE) 62 63 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, 64 ushort_t *port); 65 static int tape_write(ndmpd_session_t *session, char *data, ssize_t length); 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_write_eom 1358 * 1359 * Write end-of-media magic string. This is called after hitting the LEOT. 1360 */ 1361 void 1362 ndmpd_write_eom(int fd) 1363 { 1364 int n; 1365 1366 (void) ndmp_mtioctl(fd, MTWEOF, 1); 1367 n = write(fd, NDMP_EOM_MAGIC, strlen(NDMP_EOM_MAGIC)); 1368 1369 NDMP_LOG(LOG_DEBUG, "%d EOM bytes wrote", n); 1370 (void) ndmp_mtioctl(fd, MTWEOF, 1); 1371 1372 /* 1373 * Rewind to the previous file since the last two files are used 1374 * as the indicator for logical EOM. 1375 */ 1376 (void) ndmp_mtioctl(fd, MTBSF, 2); 1377 } 1378 1379 1380 /* 1381 * ndmpd_local_write 1382 * 1383 * Writes data to the mover. 1384 * Buffers and write data to the tape device. 1385 * A full tape record is buffered before being written. 1386 * 1387 * Parameters: 1388 * session (input) - session pointer. 1389 * data (input) - data to be written. 1390 * length (input) - data length. 1391 * 1392 * Returns: 1393 * 0 - data successfully written. 1394 * -1 - error. 1395 */ 1396 int 1397 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length) 1398 { 1399 ulong_t count = 0; 1400 ssize_t n; 1401 ulong_t len; 1402 1403 /* 1404 * A length of 0 indicates that any buffered data should be 1405 * flushed to tape. 1406 */ 1407 if (length == 0) { 1408 if (session->ns_mover.md_w_index == 0) 1409 return (0); 1410 1411 (void) memset( 1412 &session->ns_mover.md_buf[session->ns_mover.md_w_index], 1413 0, session->ns_mover.md_record_size - 1414 session->ns_mover.md_w_index); 1415 1416 n = tape_write(session, session->ns_mover.md_buf, 1417 session->ns_mover.md_record_size); 1418 if (n <= 0) { 1419 ndmpd_mover_error(session, 1420 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 1421 NDMP_MOVER_HALT_INTERNAL_ERROR)); 1422 return (-1); 1423 } 1424 session->ns_mover.md_position += n; 1425 session->ns_mover.md_data_written += 1426 session->ns_mover.md_w_index; 1427 session->ns_mover.md_record_num++; 1428 session->ns_mover.md_w_index = 0; 1429 return (0); 1430 } 1431 /* Break the data into records. */ 1432 while (count < length) { 1433 /* 1434 * Determine if data needs to be buffered or 1435 * can be written directly from user supplied location. 1436 * We can fast path the write if there is no pending 1437 * buffered data and there is at least a full record's worth 1438 * of data to be written. 1439 */ 1440 if (session->ns_mover.md_w_index == 0 && 1441 length - count >= session->ns_mover.md_record_size) { 1442 n = tape_write(session, &data[count], 1443 session->ns_mover.md_record_size); 1444 if (n <= 0) { 1445 ndmpd_mover_error(session, 1446 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 1447 NDMP_MOVER_HALT_INTERNAL_ERROR)); 1448 return (-1); 1449 } 1450 session->ns_mover.md_position += n; 1451 session->ns_mover.md_data_written += n; 1452 session->ns_mover.md_record_num++; 1453 count += n; 1454 continue; 1455 } 1456 /* Buffer the data */ 1457 len = length - count; 1458 if (len > session->ns_mover.md_record_size - 1459 session->ns_mover.md_w_index) 1460 len = session->ns_mover.md_record_size - 1461 session->ns_mover.md_w_index; 1462 1463 (void) memcpy( 1464 &session->ns_mover.md_buf[session->ns_mover.md_w_index], 1465 &data[count], len); 1466 session->ns_mover.md_w_index += len; 1467 count += len; 1468 1469 /* Write the buffer if its full */ 1470 if (session->ns_mover.md_w_index == 1471 session->ns_mover.md_record_size) { 1472 n = tape_write(session, session->ns_mover.md_buf, 1473 session->ns_mover.md_record_size); 1474 if (n < 0) { 1475 ndmpd_mover_error(session, 1476 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 1477 NDMP_MOVER_HALT_INTERNAL_ERROR)); 1478 return (-1); 1479 } 1480 session->ns_mover.md_position += n; 1481 session->ns_mover.md_data_written += n; 1482 session->ns_mover.md_record_num++; 1483 session->ns_mover.md_w_index = 0; 1484 } 1485 } 1486 1487 return (0); 1488 } 1489 1490 1491 /* 1492 * ndmpd_remote_write 1493 * 1494 * Writes data to the remote mover. 1495 * 1496 * Parameters: 1497 * session (input) - session pointer. 1498 * data (input) - data to be written. 1499 * length (input) - data length. 1500 * 1501 * Returns: 1502 * 0 - data successfully written. 1503 * -1 - error. 1504 */ 1505 int 1506 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length) 1507 { 1508 ssize_t n; 1509 ulong_t count = 0; 1510 1511 while (count < length) { 1512 if (session->ns_eof == TRUE || 1513 session->ns_data.dd_abort == TRUE) 1514 return (-1); 1515 1516 if ((n = write(session->ns_data.dd_sock, &data[count], 1517 length - count)) < 0) { 1518 NDMP_LOG(LOG_ERR, "Socket write error: %m."); 1519 return (-1); 1520 } 1521 count += n; 1522 } 1523 1524 return (0); 1525 } 1526 1527 /* 1528 * ndmpd_local_read 1529 * 1530 * Reads data from the local tape device. 1531 * Full tape records are read and buffered. 1532 * 1533 * Parameters: 1534 * session (input) - session pointer. 1535 * data (input) - location to store data. 1536 * length (input) - data length. 1537 * 1538 * Returns: 1539 * 0 - data successfully read. 1540 * -1 - error. 1541 * 1 - session terminated or operation aborted. 1542 */ 1543 int 1544 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length) 1545 { 1546 ulong_t count = 0; 1547 ssize_t n; 1548 ulong_t len; 1549 ndmp_notify_mover_paused_request pause_request; 1550 1551 /* 1552 * Automatically increase the seek window if necessary. 1553 * This is needed in the event the module attempts to read 1554 * past a seek window set via a prior call to ndmpd_seek() or 1555 * the module has not issued a seek. If no seek was issued then 1556 * pretend that a seek was issued to read the entire tape. 1557 */ 1558 if (length > session->ns_mover.md_bytes_left_to_read) { 1559 /* ndmpd_seek() never called? */ 1560 if (session->ns_data.dd_read_length == 0) { 1561 session->ns_mover.md_bytes_left_to_read = ~0LL; 1562 session->ns_data.dd_read_offset = 0LL; 1563 session->ns_data.dd_read_length = ~0LL; 1564 } else { 1565 session->ns_mover.md_bytes_left_to_read = length; 1566 session->ns_data.dd_read_offset = 1567 session->ns_mover.md_position; 1568 session->ns_data.dd_read_length = length; 1569 } 1570 } 1571 /* 1572 * Read as many records as necessary to satisfy the request. 1573 */ 1574 while (count < length) { 1575 /* 1576 * If the end of the mover window has been reached, 1577 * then notify the client that a new data window is needed. 1578 */ 1579 if (session->ns_mover.md_position >= 1580 session->ns_mover.md_window_offset + 1581 session->ns_mover.md_window_length) { 1582 1583 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 1584 session->ns_mover.md_pause_reason = 1585 NDMP_MOVER_PAUSE_SEEK; 1586 pause_request.reason = NDMP_MOVER_PAUSE_SEEK; 1587 pause_request.seek_position = 1588 long_long_to_quad(session->ns_mover.md_position); 1589 1590 if (ndmp_send_request(session->ns_connection, 1591 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR, 1592 (void *) &pause_request, 0) < 0) { 1593 NDMP_LOG(LOG_DEBUG, 1594 "Sending notify_mover_paused request"); 1595 ndmpd_mover_error(session, 1596 NDMP_MOVER_HALT_INTERNAL_ERROR); 1597 return (-1); 1598 } 1599 /* 1600 * Wait until the state is changed by 1601 * an abort or continue request. 1602 */ 1603 nlp_ref_nw(session); 1604 for (; ; ) { 1605 nlp_wait_nw(session); 1606 1607 if (session->ns_eof == TRUE) { 1608 nlp_unref_nw(session); 1609 return (1); 1610 } 1611 1612 switch (session->ns_mover.md_state) { 1613 case NDMP_MOVER_STATE_ACTIVE: 1614 break; 1615 1616 case NDMP_MOVER_STATE_PAUSED: 1617 continue; 1618 1619 default: 1620 nlp_unref_nw(session); 1621 return (-1); 1622 } 1623 } 1624 } 1625 len = length - count; 1626 1627 /* 1628 * Prevent reading past the end of the window. 1629 */ 1630 if (len > 1631 session->ns_mover.md_window_offset + 1632 session->ns_mover.md_window_length - 1633 session->ns_mover.md_position) 1634 len = session->ns_mover.md_window_offset + 1635 session->ns_mover.md_window_length - 1636 session->ns_mover.md_position; 1637 1638 /* 1639 * Copy from the data buffer first. 1640 */ 1641 if (session->ns_mover.md_w_index - 1642 session->ns_mover.md_r_index != 0) { 1643 /* 1644 * Limit the copy to the amount of data in the buffer. 1645 */ 1646 if (len > session->ns_mover.md_w_index - 1647 session->ns_mover.md_r_index) 1648 len = session->ns_mover.md_w_index 1649 - session->ns_mover.md_r_index; 1650 1651 (void) memcpy((void *) &data[count], 1652 &session->ns_mover.md_buf[session-> 1653 ns_mover.md_r_index], len); 1654 count += len; 1655 session->ns_mover.md_r_index += len; 1656 session->ns_mover.md_bytes_left_to_read -= len; 1657 session->ns_mover.md_position += len; 1658 continue; 1659 } 1660 /* 1661 * Determine if data needs to be buffered or 1662 * can be read directly to user supplied location. 1663 * We can fast path the read if at least a full record 1664 * needs to be read and there is no seek pending. 1665 * This is done to eliminate a buffer copy. 1666 */ 1667 if (len >= session->ns_mover.md_record_size && 1668 session->ns_mover.md_position >= 1669 session->ns_mover.md_seek_position) { 1670 n = tape_read(session, &data[count]); 1671 if (n <= 0) { 1672 if (n == TAPE_NO_WRITER_ERR) 1673 return (1); 1674 1675 ndmpd_mover_error(session, 1676 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 1677 NDMP_MOVER_HALT_INTERNAL_ERROR)); 1678 return (n == 0) ? (1) : (-1); 1679 } 1680 count += n; 1681 session->ns_mover.md_bytes_left_to_read -= n; 1682 session->ns_mover.md_position += n; 1683 continue; 1684 } 1685 /* Read the next record into the buffer. */ 1686 n = tape_read(session, session->ns_mover.md_buf); 1687 if (n <= 0) { 1688 if (n == TAPE_NO_WRITER_ERR) 1689 return (1); 1690 1691 ndmpd_mover_error(session, 1692 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 1693 NDMP_MOVER_HALT_INTERNAL_ERROR)); 1694 return (n == 0) ? (1) : (-1); 1695 } 1696 session->ns_mover.md_w_index = n; 1697 session->ns_mover.md_r_index = 0; 1698 1699 NDMP_LOG(LOG_DEBUG, "n: %d", n); 1700 1701 /* 1702 * Discard data if the current data stream position is 1703 * prior to the seek position. This is necessary if a seek 1704 * request set the seek pointer to a position that is not a 1705 * record boundary. The seek request handler can only position 1706 * to the start of a record. 1707 */ 1708 if (session->ns_mover.md_position < 1709 session->ns_mover.md_seek_position) { 1710 session->ns_mover.md_r_index = 1711 session->ns_mover.md_seek_position - 1712 session->ns_mover.md_position; 1713 session->ns_mover.md_position = 1714 session->ns_mover.md_seek_position; 1715 } 1716 } 1717 1718 return (0); 1719 } 1720 1721 1722 /* 1723 * ndmpd_remote_read 1724 * 1725 * Reads data from the remote mover. 1726 * 1727 * Parameters: 1728 * session (input) - session pointer. 1729 * data (input) - data to be written. 1730 * length (input) - data length. 1731 * 1732 * Returns: 1733 * 0 - data successfully read. 1734 * -1 - error. 1735 * 1 - session terminated or operation aborted. 1736 */ 1737 int 1738 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length) 1739 { 1740 ulong_t count = 0; 1741 ssize_t n; 1742 ulong_t len; 1743 ndmp_notify_data_read_request request; 1744 1745 while (count < length) { 1746 len = length - count; 1747 1748 /* 1749 * If the end of the seek window has been reached then 1750 * send an ndmp_read request to the client. 1751 * The NDMP client will then send a mover_data_read request to 1752 * the remote mover and the mover will send more data. 1753 * This condition can occur if the module attempts to read past 1754 * a seek window set via a prior call to ndmpd_seek() or 1755 * the module has not issued a seek. If no seek was issued then 1756 * pretend that a seek was issued to read the entire tape. 1757 */ 1758 if (session->ns_mover.md_bytes_left_to_read == 0) { 1759 /* ndmpd_seek() never called? */ 1760 if (session->ns_data.dd_read_length == 0) { 1761 session->ns_mover.md_bytes_left_to_read = ~0LL; 1762 session->ns_data.dd_read_offset = 0LL; 1763 session->ns_data.dd_read_length = ~0LL; 1764 } else { 1765 session->ns_mover.md_bytes_left_to_read = len; 1766 session->ns_data.dd_read_offset = 1767 session->ns_mover.md_position; 1768 session->ns_data.dd_read_length = len; 1769 } 1770 1771 request.offset = 1772 long_long_to_quad(session->ns_data.dd_read_offset); 1773 request.length = 1774 long_long_to_quad(session->ns_data.dd_read_length); 1775 1776 if (ndmp_send_request_lock(session->ns_connection, 1777 NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR, 1778 (void *) &request, 0) < 0) { 1779 NDMP_LOG(LOG_DEBUG, 1780 "Sending notify_data_read request"); 1781 return (-1); 1782 } 1783 } 1784 if (session->ns_eof == TRUE || 1785 session->ns_data.dd_abort == TRUE) 1786 return (1); 1787 1788 /* 1789 * If the module called ndmpd_seek() prior to reading all of the 1790 * data that the remote mover was requested to send, then the 1791 * excess data from the seek has to be discardd. 1792 */ 1793 if (session->ns_mover.md_discard_length != 0) { 1794 n = discard_data(session, 1795 (ulong_t)session->ns_mover.md_discard_length); 1796 if (n < 0) 1797 return (-1); 1798 session->ns_mover.md_discard_length -= n; 1799 continue; 1800 } 1801 /* 1802 * Don't attempt to read more data than the remote is sending. 1803 */ 1804 if (len > session->ns_mover.md_bytes_left_to_read) 1805 len = session->ns_mover.md_bytes_left_to_read; 1806 1807 NDMP_LOG(LOG_DEBUG, "len: %u", len); 1808 1809 if ((n = read(session->ns_data.dd_sock, &data[count], 1810 len)) < 0) { 1811 NDMP_LOG(LOG_ERR, "Socket read error: %m."); 1812 return (-1); 1813 } 1814 /* read returns 0 if the connection was closed */ 1815 if (n == 0) 1816 return (-1); 1817 1818 count += n; 1819 session->ns_mover.md_bytes_left_to_read -= n; 1820 session->ns_mover.md_position += n; 1821 } 1822 1823 return (0); 1824 } 1825 1826 /* *** ndmpd internal functions ***************************************** */ 1827 1828 /* 1829 * ndmpd_mover_init 1830 * 1831 * Initialize mover specific session variables. 1832 * Don't initialize variables such as record_size that need to 1833 * persist across data operations. A client may open a connection and 1834 * do multiple backups after setting the record_size. 1835 * 1836 * Parameters: 1837 * session (input) - session pointer. 1838 * 1839 * Returns: 1840 * 0 - success. 1841 * -1 - error. 1842 */ 1843 int 1844 ndmpd_mover_init(ndmpd_session_t *session) 1845 { 1846 session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE; 1847 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA; 1848 session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA; 1849 session->ns_mover.md_data_written = 0LL; 1850 session->ns_mover.md_seek_position = 0LL; 1851 session->ns_mover.md_bytes_left_to_read = 0LL; 1852 session->ns_mover.md_window_offset = 0LL; 1853 session->ns_mover.md_window_length = MAX_WINDOW_SIZE; 1854 session->ns_mover.md_position = 0LL; 1855 session->ns_mover.md_discard_length = 0; 1856 session->ns_mover.md_record_num = 0; 1857 session->ns_mover.md_record_size = 0; 1858 session->ns_mover.md_listen_sock = -1; 1859 session->ns_mover.md_pre_cond = FALSE; 1860 session->ns_mover.md_sock = -1; 1861 session->ns_mover.md_r_index = 0; 1862 session->ns_mover.md_w_index = 0; 1863 session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE); 1864 if (!session->ns_mover.md_buf) 1865 return (-1); 1866 1867 if (ndmp_get_version(session->ns_connection) == NDMPV3) { 1868 session->ns_mover.md_mode = NDMP_MOVER_MODE_READ; 1869 (void) memset(&session->ns_mover.md_data_addr, 0, 1870 sizeof (ndmp_addr_v3)); 1871 } 1872 return (0); 1873 } 1874 1875 1876 /* 1877 * ndmpd_mover_shut_down 1878 * 1879 * Shutdown the mover. It closes all the sockets. 1880 * 1881 * Parameters: 1882 * session (input) - session pointer. 1883 * 1884 * Returns: 1885 * void 1886 */ 1887 void 1888 ndmpd_mover_shut_down(ndmpd_session_t *session) 1889 { 1890 if (session->ns_mover.md_listen_sock != -1) { 1891 NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d", 1892 session->ns_mover.md_listen_sock); 1893 (void) ndmpd_remove_file_handler(session, 1894 session->ns_mover.md_listen_sock); 1895 (void) close(session->ns_mover.md_listen_sock); 1896 session->ns_mover.md_listen_sock = -1; 1897 } 1898 if (session->ns_mover.md_sock != -1) { 1899 NDMP_LOG(LOG_DEBUG, "mover.sock: %d", 1900 session->ns_mover.md_sock); 1901 (void) ndmpd_remove_file_handler(session, 1902 session->ns_mover.md_sock); 1903 (void) close(session->ns_mover.md_sock); 1904 session->ns_mover.md_sock = -1; 1905 } 1906 } 1907 1908 1909 /* 1910 * ndmpd_mover_cleanup 1911 * 1912 * Parameters: 1913 * session (input) - session pointer. 1914 * 1915 * Returns: 1916 * void 1917 */ 1918 void 1919 ndmpd_mover_cleanup(ndmpd_session_t *session) 1920 { 1921 NDMP_FREE(session->ns_mover.md_buf); 1922 } 1923 1924 1925 /* 1926 * ndmpd_mover_connect 1927 * Create a connection to the specified mover. 1928 * 1929 * Parameters: 1930 * session (input) - session pointer 1931 * 1932 * Returns: 1933 * error code. 1934 */ 1935 ndmp_error 1936 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode) 1937 { 1938 ndmp_mover_addr *mover = &session->ns_data.dd_mover; 1939 struct sockaddr_in sin; 1940 int sock = -1; 1941 int flag = 1; 1942 1943 if (mover->addr_type == NDMP_ADDR_TCP) { 1944 if (mover->ndmp_mover_addr_u.addr.ip_addr) { 1945 (void) memset((void *) &sin, 0, sizeof (sin)); 1946 sin.sin_family = AF_INET; 1947 sin.sin_addr.s_addr = 1948 htonl(mover->ndmp_mover_addr_u.addr.ip_addr); 1949 sin.sin_port = 1950 htons(mover->ndmp_mover_addr_u.addr.port); 1951 1952 /* 1953 * If the address type is TCP but both the address and 1954 * the port number are zero, we have to use a different 1955 * socket than the mover socket. This can happen when 1956 * using NDMP disk to disk copy (AKA D2D copy). 1957 * The NDMPCopy client will send a zero address to 1958 * direct the server to use the mover socket as the 1959 * data socket to receive the recovery data. 1960 */ 1961 if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) { 1962 session->ns_data.dd_sock = 1963 session->ns_mover.md_sock; 1964 return (NDMP_NO_ERR); 1965 } 1966 1967 NDMP_LOG(LOG_DEBUG, "addr: %u port: %u", 1968 mover->ndmp_mover_addr_u.addr.ip_addr, 1969 (ulong_t)sin.sin_port); 1970 1971 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 1972 NDMP_LOG(LOG_DEBUG, "Socket error: %m"); 1973 return (NDMP_IO_ERR); 1974 } 1975 if (connect(sock, (struct sockaddr *)&sin, 1976 sizeof (sin)) < 0) { 1977 NDMP_LOG(LOG_DEBUG, "Connect error: %m"); 1978 (void) close(sock); 1979 return (NDMP_IO_ERR); 1980 } 1981 1982 if (ndmp_sbs > 0) 1983 ndmp_set_socket_snd_buf(sock, 1984 ndmp_sbs * KILOBYTE); 1985 if (ndmp_rbs > 0) 1986 ndmp_set_socket_rcv_buf(sock, 1987 ndmp_rbs * KILOBYTE); 1988 1989 ndmp_set_socket_nodelay(sock); 1990 (void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag, 1991 sizeof (flag)); 1992 } else { 1993 if ((session->ns_mover.md_state != 1994 NDMP_MOVER_STATE_ACTIVE) || 1995 (session->ns_mover.md_sock == -1)) { 1996 1997 NDMP_LOG(LOG_DEBUG, 1998 "Not in active state mover" 1999 " state = %d or Invalid mover sock=%d", 2000 session->ns_mover.md_state, 2001 session->ns_mover.md_sock); 2002 return (NDMP_ILLEGAL_STATE_ERR); 2003 } 2004 2005 sock = session->ns_mover.md_sock; 2006 NDMP_LOG(LOG_DEBUG, 2007 "session: 0x%x setting data sock fd: %d to be" 2008 " same as listen_sock", session, sock); 2009 } 2010 2011 NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock); 2012 2013 session->ns_data.dd_sock = sock; 2014 2015 NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock); 2016 2017 return (NDMP_NO_ERR); 2018 } 2019 /* Local mover connection. */ 2020 2021 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) { 2022 NDMP_LOG(LOG_DEBUG, "Mover is not in listen state"); 2023 return (NDMP_ILLEGAL_STATE_ERR); 2024 } 2025 if (session->ns_tape.td_fd == -1) { 2026 NDMP_LOG(LOG_DEBUG, "Tape device not open"); 2027 return (NDMP_DEV_NOT_OPEN_ERR); 2028 } 2029 if (mover_mode == NDMP_MOVER_MODE_READ && 2030 session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) { 2031 NDMP_LOG(LOG_ERR, "Write protected device."); 2032 return (NDMP_WRITE_PROTECT_ERR); 2033 } 2034 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE; 2035 session->ns_mover.md_mode = mover_mode; 2036 2037 return (NDMP_NO_ERR); 2038 } 2039 2040 2041 2042 /* 2043 * ndmpd_mover_seek 2044 * 2045 * Seek to the requested data stream position. 2046 * If the requested offset is outside of the current window, 2047 * the mover is paused and a notify_mover_paused request is sent 2048 * notifying the client that a seek is required. 2049 * If the requested offest is within the window but not within the 2050 * current record, then the tape is positioned to the record containing 2051 * the requested offest. 2052 * The requested amount of data is then read from the tape device and 2053 * written to the data connection. 2054 * 2055 * Parameters: 2056 * session (input) - session pointer. 2057 * offset (input) - data stream position to seek to. 2058 * length (input) - amount of data that will be read. 2059 * 2060 * Returns: 2061 * 1 - seek pending completion by the NDMP client. 2062 * 0 - seek successfully completed. 2063 * -1 - error. 2064 */ 2065 int 2066 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset, 2067 u_longlong_t length) 2068 { 2069 int ctlcmd; 2070 int ctlcnt; 2071 u_longlong_t tape_position; 2072 u_longlong_t buf_position; 2073 ndmp_notify_mover_paused_request pause_request; 2074 2075 session->ns_mover.md_seek_position = offset; 2076 session->ns_mover.md_bytes_left_to_read = length; 2077 2078 /* 2079 * If the requested position is outside of the window, 2080 * notify the client that a seek is required. 2081 */ 2082 if (session->ns_mover.md_seek_position < 2083 session->ns_mover.md_window_offset || 2084 session->ns_mover.md_seek_position >= 2085 session->ns_mover.md_window_offset + 2086 session->ns_mover.md_window_length) { 2087 NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)", 2088 session->ns_mover.md_seek_position); 2089 2090 session->ns_mover.md_w_index = 0; 2091 session->ns_mover.md_r_index = 0; 2092 2093 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 2094 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK; 2095 pause_request.reason = NDMP_MOVER_PAUSE_SEEK; 2096 pause_request.seek_position = long_long_to_quad(offset); 2097 2098 if (ndmp_send_request(session->ns_connection, 2099 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR, 2100 (void *) &pause_request, 0) < 0) { 2101 NDMP_LOG(LOG_DEBUG, 2102 "Sending notify_mover_paused request"); 2103 return (-1); 2104 } 2105 return (1); 2106 } 2107 /* 2108 * Determine the data stream position of the first byte in the 2109 * data buffer. 2110 */ 2111 buf_position = session->ns_mover.md_position - 2112 (session->ns_mover.md_position % session->ns_mover.md_record_size); 2113 2114 /* 2115 * Determine the data stream position of the next byte that 2116 * will be read from tape. 2117 */ 2118 tape_position = buf_position; 2119 if (session->ns_mover.md_w_index != 0) 2120 tape_position += session->ns_mover.md_record_size; 2121 2122 /* 2123 * Check if requested position is for data that has been read and is 2124 * in the buffer. 2125 */ 2126 if (offset >= buf_position && offset < tape_position) { 2127 session->ns_mover.md_position = offset; 2128 session->ns_mover.md_r_index = session->ns_mover.md_position - 2129 buf_position; 2130 2131 NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u", 2132 session->ns_mover.md_position, 2133 session->ns_mover.md_r_index); 2134 2135 return (0); 2136 } 2137 2138 ctlcmd = 0; 2139 if (tape_position > session->ns_mover.md_seek_position) { 2140 /* Need to seek backward. */ 2141 ctlcmd = MTBSR; 2142 ctlcnt = (int)((tape_position - offset - 1) 2143 / session->ns_mover.md_record_size) + 1; 2144 tape_position -= ((u_longlong_t)(((tape_position - offset - 1) / 2145 session->ns_mover.md_record_size) + 1) * 2146 (u_longlong_t)session->ns_mover.md_record_size); 2147 2148 } else if (offset >= tape_position + session->ns_mover.md_record_size) { 2149 /* Need to seek forward. */ 2150 ctlcmd = MTFSR; 2151 ctlcnt = (int)((offset - tape_position) 2152 / session->ns_mover.md_record_size); 2153 tape_position += ((u_longlong_t)(((offset - tape_position) / 2154 session->ns_mover.md_record_size)) * 2155 (u_longlong_t)session->ns_mover.md_record_size); 2156 } 2157 /* Reposition the tape if necessary. */ 2158 if (ctlcmd) { 2159 NDMP_LOG(LOG_DEBUG, "cmd %d count %d", 2160 ctlcmd, ctlcnt); 2161 (void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt); 2162 } 2163 2164 session->ns_mover.md_position = tape_position; 2165 session->ns_mover.md_r_index = 0; 2166 session->ns_mover.md_w_index = 0; 2167 2168 NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position); 2169 2170 return (0); 2171 } 2172 2173 2174 /* ** static functions ************************************************** */ 2175 2176 /* 2177 * create_listen_socket_v2 2178 * 2179 * Creates a socket for listening for accepting data connections. 2180 * 2181 * Parameters: 2182 * session (input) - session pointer. 2183 * addr (output) - location to store address of socket. 2184 * port (output) - location to store port of socket. 2185 * 2186 * Returns: 2187 * 0 - success. 2188 * -1 - error. 2189 */ 2190 static int 2191 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port) 2192 { 2193 session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port); 2194 if (session->ns_mover.md_listen_sock < 0) 2195 return (-1); 2196 2197 /* 2198 * Add a file handler for the listen socket. 2199 * ndmpd_select will call accept_connection when a 2200 * connection is ready to be accepted. 2201 */ 2202 if (ndmpd_add_file_handler(session, (void *) session, 2203 session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER, 2204 accept_connection) < 0) { 2205 (void) close(session->ns_mover.md_listen_sock); 2206 session->ns_mover.md_listen_sock = -1; 2207 return (-1); 2208 } 2209 2210 NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port); 2211 return (0); 2212 } 2213 2214 2215 /* 2216 * accept_connection 2217 * 2218 * Accept a data connection from a data server. 2219 * Called by ndmpd_select when a connection is pending on 2220 * the mover listen socket. 2221 * 2222 * Parameters: 2223 * cookie (input) - session pointer. 2224 * fd (input) - file descriptor. 2225 * mode (input) - select mode. 2226 * 2227 * Returns: 2228 * void. 2229 */ 2230 /*ARGSUSED*/ 2231 static void 2232 accept_connection(void *cookie, int fd, ulong_t mode) 2233 { 2234 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 2235 struct sockaddr_in from; 2236 int from_len; 2237 int flag = 1; 2238 2239 from_len = sizeof (from); 2240 session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from, 2241 &from_len); 2242 2243 (void) ndmpd_remove_file_handler(session, fd); 2244 (void) close(session->ns_mover.md_listen_sock); 2245 session->ns_mover.md_listen_sock = -1; 2246 2247 if (session->ns_mover.md_sock < 0) { 2248 NDMP_LOG(LOG_DEBUG, "Accept error: %m"); 2249 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR); 2250 return; 2251 } 2252 2253 (void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE, 2254 &flag, sizeof (flag)); 2255 ndmp_set_socket_nodelay(session->ns_mover.md_sock); 2256 ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 60 * KILOBYTE); 2257 ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 60 * KILOBYTE); 2258 2259 NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock); 2260 2261 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) { 2262 if (start_mover_for_backup(session) < 0) { 2263 ndmpd_mover_error(session, 2264 NDMP_MOVER_HALT_INTERNAL_ERROR); 2265 return; 2266 } 2267 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d", 2268 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)), 2269 ntohs(from.sin_port)); 2270 } else { 2271 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d", 2272 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)), 2273 ntohs(from.sin_port)); 2274 } 2275 2276 NDMP_LOG(LOG_DEBUG, "Received connection"); 2277 2278 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE; 2279 } 2280 2281 /* 2282 * tape_write 2283 * 2284 * Writes a data record to tape. Detects and handles EOT conditions. 2285 * 2286 * Parameters: 2287 * session (input) - session pointer. 2288 * data (input) - data to be written. 2289 * length (input) - length of data to be written. 2290 * 2291 * Returns: 2292 * 0 - operation aborted by client. 2293 * -1 - error. 2294 * otherwise - number of bytes written. 2295 */ 2296 static int 2297 tape_write(ndmpd_session_t *session, char *data, ssize_t length) 2298 { 2299 ssize_t n; 2300 int err; 2301 2302 for (; ; ) { 2303 /* 2304 * Refer to the comment at the top of ndmpd_tape.c file for 2305 * Mammoth2 tape drives. 2306 */ 2307 if (session->ns_tape.td_eom_seen) { 2308 NDMP_LOG(LOG_DEBUG, "eom_seen"); 2309 session->ns_tape.td_eom_seen = FALSE; 2310 /* 2311 * End of media reached. 2312 * Notify client and wait for the client to 2313 * either abort the operation or continue the 2314 * operation after changing the tape. 2315 */ 2316 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 2317 ++ndmp_log_msg_id, 2318 "End of tape reached. Load next tape.\n"); 2319 2320 err = change_tape(session); 2321 2322 /* Operation aborted or connection terminated? */ 2323 if (err < 0) 2324 return (-1); 2325 2326 continue; 2327 } 2328 2329 n = write(session->ns_tape.td_fd, data, length); 2330 if (n < 0) { 2331 NDMP_LOG(LOG_ERR, "Tape write error: %m."); 2332 return (-1); 2333 } 2334 NS_ADD(wtape, n); 2335 2336 if (n == 0 || n != length) { 2337 if (n != 0) { 2338 NDMP_LOG(LOG_DEBUG, "LEOT n: %d", n); 2339 2340 NDMP_LOG(LOG_DEBUG, "Backup one record"); 2341 (void) ndmp_mtioctl(session->ns_tape.td_fd, 2342 MTBSR, 1); 2343 2344 /* setting logical EOM */ 2345 ndmpd_write_eom(session->ns_tape.td_fd); 2346 } 2347 2348 /* 2349 * End of media reached. 2350 * Notify client and wait for the client to 2351 * either abort the operation or continue the 2352 * operation after changing the tape. 2353 */ 2354 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 2355 ++ndmp_log_msg_id, 2356 "End of tape reached. Load next tape.\n"); 2357 2358 err = change_tape(session); 2359 2360 /* Operation aborted or connection terminated? */ 2361 if (err < 0) 2362 return (-1); 2363 2364 /* Retry the write to the new tape. */ 2365 continue; 2366 } 2367 2368 session->ns_tape.td_record_count++; 2369 return (n); 2370 } 2371 } 2372 2373 2374 /* 2375 * tape_read 2376 * 2377 * Reads a data record from tape. Detects and handles EOT conditions. 2378 * 2379 * Parameters: 2380 * session (input) - session pointer. 2381 * data (input) - location to read data to. 2382 * 2383 * Returns: 2384 * 0 - operation aborted. 2385 * -1 - tape read error. 2386 * otherwise - number of bytes read. 2387 */ 2388 static int 2389 tape_read(ndmpd_session_t *session, char *data) 2390 { 2391 ssize_t n; 2392 int err; 2393 int count = session->ns_mover.md_record_size; 2394 2395 for (; ; ) { 2396 n = read(session->ns_tape.td_fd, data, count); 2397 if (n < 0) { 2398 NDMP_LOG(LOG_ERR, "Tape read error: %m."); 2399 return (TAPE_READ_ERR); 2400 } 2401 NS_ADD(rtape, n); 2402 2403 if (n == 0) { 2404 if (!is_writer_running(session)) 2405 return (TAPE_NO_WRITER_ERR); 2406 2407 /* 2408 * End of media reached. 2409 * Notify client and wait for the client to 2410 * either abort the data operation or continue the 2411 * operation after changing the tape. 2412 */ 2413 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 2414 ++ndmp_log_msg_id, 2415 "End of tape reached. Load next tape"); 2416 2417 NDMP_LOG(LOG_DEBUG, 2418 "End of tape reached. Load next tape"); 2419 2420 err = change_tape(session); 2421 2422 /* Operation aborted or connection terminated? */ 2423 if (err < 0) { 2424 /* 2425 * K.L. Go back one record if it is read 2426 * but not used. 2427 */ 2428 2429 if (count != session->ns_mover.md_record_size) { 2430 (void) ndmp_mtioctl( 2431 session->ns_tape.td_fd, MTBSR, 1); 2432 } 2433 return (0); 2434 } 2435 /* Retry the read from the new tape. */ 2436 continue; 2437 } 2438 2439 /* Change to pass Veritas Netbackup prequal test. */ 2440 data += n; 2441 count -= n; 2442 if (count <= 0) { 2443 session->ns_mover.md_record_num++; 2444 session->ns_tape.td_record_count++; 2445 return (n); 2446 } 2447 } 2448 } 2449 2450 /* 2451 * change_tape 2452 * 2453 * Send a notify_pause request (protocol version 1) or 2454 * notify_mover_pause request (protocol version 2) to the 2455 * NDMP client to inform 2456 * the client that a tape volume change is required. 2457 * Process messages until the data/mover operation is either aborted 2458 * or continued. 2459 * 2460 * Parameters: 2461 * client_data (input) - session pointer. 2462 * 2463 * Returns: 2464 * 0 - operation has been continued. 2465 * -1 - operation has been aborted. 2466 */ 2467 static int 2468 change_tape(ndmpd_session_t *session) 2469 { 2470 ndmp_notify_mover_paused_request request; 2471 2472 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 2473 2474 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) 2475 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM; 2476 else 2477 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF; 2478 2479 request.reason = session->ns_mover.md_pause_reason; 2480 request.seek_position = long_long_to_quad(0LL); 2481 2482 NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d", 2483 session->ns_mover.md_pause_reason); 2484 2485 if (ndmp_send_request(session->ns_connection, 2486 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR, 2487 (void *) &request, 0) < 0) { 2488 NDMP_LOG(LOG_DEBUG, 2489 "Sending notify_mover_paused request"); 2490 return (-1); 2491 } 2492 /* 2493 * Wait for until the state is changed by 2494 * an abort or continue request. 2495 */ 2496 nlp_ref_nw(session); 2497 for (; ; ) { 2498 NDMP_LOG(LOG_DEBUG, "calling nlp_wait_nw()"); 2499 2500 nlp_wait_nw(session); 2501 2502 if (nlp_event_rv_get(session) < 0) { 2503 nlp_unref_nw(session); 2504 return (-1); 2505 } 2506 2507 if (session->ns_eof == TRUE) { 2508 NDMP_LOG(LOG_DEBUG, "session->ns_eof == TRUE"); 2509 nlp_unref_nw(session); 2510 return (-1); 2511 } 2512 2513 switch (session->ns_mover.md_state) { 2514 case NDMP_MOVER_STATE_ACTIVE: 2515 NDMP_LOG(LOG_DEBUG, 2516 "mover.state: NDMP_MOVER_STATE_ACTIVE"); 2517 2518 nlp_unref_nw(session); 2519 session->ns_tape.td_record_count = 0; 2520 return (0); 2521 2522 case NDMP_MOVER_STATE_PAUSED: 2523 NDMP_LOG(LOG_DEBUG, 2524 "mover.state: NDMP_MOVER_STATE_PAUSED"); 2525 continue; 2526 2527 default: 2528 NDMP_LOG(LOG_DEBUG, "default"); 2529 nlp_unref_nw(session); 2530 return (-1); 2531 } 2532 } 2533 2534 /* nlp_unref_nw(session); - statement never reached */ 2535 } 2536 2537 2538 /* 2539 * discard_data 2540 * 2541 * Read and discard data from the data connection. 2542 * Called when a module has called ndmpd_seek() prior to 2543 * reading all of the data from the previous seek. 2544 * 2545 * Parameters: 2546 * session (input) - session pointer. 2547 * 2548 * Returns: 2549 * number of bytes read and discarded. 2550 * -1 - error. 2551 */ 2552 static int 2553 discard_data(ndmpd_session_t *session, ulong_t length) 2554 { 2555 int n; 2556 char *addr; 2557 2558 if ((addr = ndmp_malloc(length)) == NULL) 2559 return (-1); 2560 2561 /* Read and discard the data. */ 2562 n = read(session->ns_mover.md_sock, addr, length); 2563 if (n < 0) { 2564 NDMP_LOG(LOG_ERR, "Socket read error: %m."); 2565 free(addr); 2566 return (-1); 2567 } 2568 2569 free(addr); 2570 return (n); 2571 } 2572 2573 2574 /* 2575 * mover_tape_read_one_buf 2576 * 2577 * Read one buffer from the tape. This is used by mover_tape_reader 2578 * 2579 * Parameters: 2580 * session (input) - session pointer. 2581 * buf (input) - buffer read 2582 * 2583 * Returns: 2584 * 0: on success 2585 * -1: otherwise 2586 */ 2587 static int 2588 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf) 2589 { 2590 int n; 2591 2592 tlm_buffer_mark_empty(buf); 2593 2594 /* 2595 * If the end of the mover window has been reached, 2596 * then notify the client that a seek is needed. 2597 * Remove the file handler to prevent this function from 2598 * being called. The handler will be reinstalled in 2599 * ndmpd_mover_continue. 2600 */ 2601 2602 if (session->ns_mover.md_position >= 2603 session->ns_mover.md_window_offset + 2604 session->ns_mover.md_window_length) { 2605 ndmp_notify_mover_paused_request pause_request; 2606 2607 NDMP_LOG(LOG_DEBUG, "end of mover window"); 2608 2609 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 2610 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK; 2611 pause_request.reason = NDMP_MOVER_PAUSE_SEEK; 2612 pause_request.seek_position = 2613 long_long_to_quad(session->ns_mover.md_position); 2614 2615 if (ndmp_send_request(session->ns_connection, 2616 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR, 2617 (void *) &pause_request, 0) < 0) { 2618 NDMP_LOG(LOG_DEBUG, 2619 "Sending notify_mover_paused request"); 2620 ndmpd_mover_error(session, 2621 NDMP_MOVER_HALT_INTERNAL_ERROR); 2622 } 2623 buf->tb_errno = EIO; 2624 return (TAPE_READ_ERR); 2625 } 2626 2627 n = tape_read(session, buf->tb_buffer_data); 2628 2629 NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n); 2630 2631 if (n <= 0) { 2632 if (n < 0) 2633 ndmpd_mover_error(session, 2634 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 2635 NDMP_MOVER_HALT_INTERNAL_ERROR)); 2636 return (TAPE_READ_ERR); 2637 } 2638 2639 buf->tb_full = TRUE; 2640 buf->tb_buffer_size = session->ns_mover.md_record_size; 2641 2642 /* 2643 * Discard data if the current data stream position is 2644 * prior to the seek position. This is necessary if a seek 2645 * request set the seek pointer to a position that is not a 2646 * record boundary. The seek request handler can only position 2647 * to the start of a record. 2648 */ 2649 if (session->ns_mover.md_position < session->ns_mover.md_seek_position) 2650 session->ns_mover.md_position = 2651 session->ns_mover.md_seek_position; 2652 2653 return (0); 2654 } 2655 2656 2657 /* 2658 * mover_tape_reader 2659 * 2660 * Mover tape reader thread. It is launched when the mover is started 2661 * for restore. 2662 * 2663 * Parameters: 2664 * session (input) - session pointer. 2665 * 2666 * Returns: 2667 * 0: on success 2668 * -1: otherwise 2669 */ 2670 int 2671 mover_tape_reader(ndmpd_session_t *session) 2672 { 2673 int bidx; /* buffer index */ 2674 int rv; 2675 ndmp_lbr_params_t *nlp; 2676 tlm_buffer_t *buf; 2677 tlm_buffers_t *bufs; 2678 tlm_cmd_t *lcmd; /* Local command */ 2679 tlm_commands_t *cmds; /* Commands structure */ 2680 2681 if ((nlp = ndmp_get_nlp(session)) == NULL) { 2682 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2683 return (-1); 2684 } 2685 2686 cmds = &nlp->nlp_cmds; 2687 lcmd = cmds->tcs_command; 2688 bufs = lcmd->tc_buffers; 2689 2690 lcmd->tc_ref++; 2691 cmds->tcs_reader_count++; 2692 2693 /* 2694 * Let our parent thread know that we are running. 2695 */ 2696 tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER); 2697 2698 buf = tlm_buffer_in_buf(bufs, &bidx); 2699 while (cmds->tcs_reader == TLM_RESTORE_RUN && 2700 lcmd->tc_reader == TLM_RESTORE_RUN) { 2701 buf = tlm_buffer_in_buf(bufs, NULL); 2702 2703 if (buf->tb_full) { 2704 NDMP_LOG(LOG_DEBUG, "R%d", bidx); 2705 /* 2706 * The buffer is still full, wait for the consumer 2707 * thread to use it. 2708 */ 2709 tlm_buffer_out_buf_timed_wait(bufs, 100); 2710 2711 } else { 2712 NDMP_LOG(LOG_DEBUG, "r%d", bidx); 2713 2714 rv = mover_tape_read_one_buf(session, buf); 2715 /* 2716 * If there was an error while reading, such as 2717 * end of stream. 2718 */ 2719 if (rv < 0) { 2720 NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv); 2721 break; 2722 } 2723 2724 /* 2725 * Can we do more buffering? 2726 */ 2727 if (is_buffer_erroneous(buf)) { 2728 NDMP_LOG(LOG_DEBUG, 2729 "Exiting, errno: %d, eot: %d, eof: %d", 2730 buf->tb_errno, buf->tb_eot, buf->tb_eof); 2731 break; 2732 } 2733 2734 (void) tlm_buffer_advance_in_idx(bufs); 2735 tlm_buffer_release_in_buf(bufs); 2736 bidx = bufs->tbs_buffer_in; 2737 } 2738 } 2739 2740 /* If the consumer is waiting for us, wake it up. */ 2741 tlm_buffer_release_in_buf(bufs); 2742 2743 /* 2744 * Clean up. 2745 */ 2746 cmds->tcs_reader_count--; 2747 lcmd->tc_ref--; 2748 lcmd->tc_writer = TLM_STOP; 2749 return (0); 2750 } 2751 2752 2753 /* 2754 * mover_socket_write_one_buf 2755 * 2756 * Write one buffer to the network socket. This is used by mover_socket_writer 2757 * 2758 * Parameters: 2759 * session (input) - session pointer. 2760 * buf (input) - buffer read 2761 * 2762 * Returns: 2763 * 0: on success 2764 * -1: otherwise 2765 */ 2766 static int 2767 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf) 2768 { 2769 int n; 2770 2771 /* Write the data to the data connection. */ 2772 errno = 0; 2773 n = write(session->ns_mover.md_sock, buf->tb_buffer_data, 2774 buf->tb_buffer_size); 2775 2776 NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size); 2777 2778 if (n < 0) { 2779 NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n); 2780 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED); 2781 return (-1); 2782 } 2783 2784 session->ns_mover.md_position += n; 2785 session->ns_mover.md_bytes_left_to_read -= n; 2786 tlm_buffer_mark_empty(buf); 2787 2788 /* 2789 * If the read limit has been reached, 2790 * then remove the file handler to prevent this 2791 * function from getting called. The next mover_read request 2792 * will reinstall the handler. 2793 */ 2794 if (session->ns_mover.md_bytes_left_to_read == 0) { 2795 NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0"); 2796 (void) ndmpd_remove_file_handler(session, 2797 session->ns_mover.md_sock); 2798 return (-1); 2799 } 2800 2801 return (0); 2802 } 2803 2804 2805 2806 /* 2807 * mover_socket_writer 2808 * 2809 * Mover's socket writer thread. This thread sends the read buffer 2810 * from the tape to the data server through the network socket. 2811 * 2812 * Parameters: 2813 * session (input) - session pointer. 2814 * 2815 * Returns: 2816 * 0: on success 2817 * -1: otherwise 2818 */ 2819 int 2820 mover_socket_writer(ndmpd_session_t *session) 2821 { 2822 int bidx; /* buffer index */ 2823 ndmp_lbr_params_t *nlp; 2824 tlm_buffer_t *buf; 2825 tlm_buffers_t *bufs; 2826 tlm_cmd_t *lcmd; /* Local command */ 2827 tlm_commands_t *cmds; /* Commands structure */ 2828 2829 if ((nlp = ndmp_get_nlp(session)) == NULL) { 2830 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2831 return (-1); 2832 } 2833 2834 cmds = &nlp->nlp_cmds; 2835 lcmd = cmds->tcs_command; 2836 bufs = lcmd->tc_buffers; 2837 2838 lcmd->tc_ref++; 2839 cmds->tcs_writer_count++; 2840 2841 /* 2842 * Let our parent thread know that we are running. 2843 */ 2844 tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER); 2845 2846 bidx = bufs->tbs_buffer_out; 2847 while (cmds->tcs_writer != (int)TLM_ABORT && 2848 lcmd->tc_writer != (int)TLM_ABORT) { 2849 buf = &bufs->tbs_buffer[bidx]; 2850 2851 if (buf->tb_full) { 2852 NDMP_LOG(LOG_DEBUG, "w%d", bidx); 2853 2854 if (mover_socket_write_one_buf(session, buf) < 0) { 2855 NDMP_LOG(LOG_DEBUG, 2856 "mover_socket_write_one_buf() < 0"); 2857 break; 2858 } 2859 2860 (void) tlm_buffer_advance_out_idx(bufs); 2861 tlm_buffer_release_out_buf(bufs); 2862 bidx = bufs->tbs_buffer_out; 2863 } else { 2864 if (lcmd->tc_writer != TLM_RESTORE_RUN) { 2865 /* No more data is coming, time to exit */ 2866 NDMP_LOG(LOG_DEBUG, "Time to exit"); 2867 break; 2868 } 2869 NDMP_LOG(LOG_DEBUG, "W%d", bidx); 2870 /* 2871 * The buffer is not full, wait for the producer 2872 * thread to fill it. 2873 */ 2874 tlm_buffer_in_buf_timed_wait(bufs, 100); 2875 } 2876 } 2877 2878 if (cmds->tcs_writer == (int)TLM_ABORT) 2879 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT"); 2880 if (lcmd->tc_writer == (int)TLM_ABORT) 2881 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT"); 2882 2883 /* If the producer is waiting for us, wake it up. */ 2884 tlm_buffer_release_out_buf(bufs); 2885 2886 /* 2887 * Clean up. 2888 */ 2889 cmds->tcs_writer_count--; 2890 lcmd->tc_ref--; 2891 lcmd->tc_reader = TLM_STOP; 2892 return (0); 2893 } 2894 2895 2896 /* 2897 * start_mover_for_restore 2898 * 2899 * Creates the mover tape reader and network writer threads for 2900 * the mover to perform the 3-way restore. 2901 * 2902 * Parameters: 2903 * session (input) - session pointer. 2904 * 2905 * Returns: 2906 * 0: on success 2907 * -1: otherwise 2908 */ 2909 static int 2910 start_mover_for_restore(ndmpd_session_t *session) 2911 { 2912 ndmp_lbr_params_t *nlp; 2913 tlm_commands_t *cmds; 2914 long xfer_size; 2915 int rc; 2916 2917 if ((nlp = ndmp_get_nlp(session)) == NULL) { 2918 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2919 return (-1); 2920 } 2921 2922 cmds = &nlp->nlp_cmds; 2923 (void) memset(cmds, 0, sizeof (*cmds)); 2924 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 2925 xfer_size = ndmp_buffer_get_size(session); 2926 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); 2927 if (cmds->tcs_command == NULL) 2928 return (-1); 2929 2930 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 2931 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 2932 2933 /* 2934 * We intentionnally don't wait for the threads to start since the 2935 * reply of the request (which resulted in calling this function) 2936 * must be sent to the client before probable errors are sent 2937 * to the client. 2938 */ 2939 rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session); 2940 if (rc == 0) { 2941 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER); 2942 } else { 2943 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s", 2944 strerror(rc)); 2945 return (-1); 2946 } 2947 2948 rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session); 2949 if (rc == 0) { 2950 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER); 2951 } else { 2952 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s", 2953 strerror(rc)); 2954 return (-1); 2955 } 2956 2957 tlm_release_reader_writer_ipc(cmds->tcs_command); 2958 return (0); 2959 } 2960 2961 2962 /* 2963 * mover_socket_read_one_buf 2964 * 2965 * Read one buffer from the network socket for the mover. This is used 2966 * by mover_socket_reader 2967 * 2968 * Parameters: 2969 * session (input) - session pointer. 2970 * buf (input) - buffer read 2971 * read_size (input) - size to be read 2972 * 2973 * Returns: 2974 * 0: on success 2975 * -1: otherwise 2976 */ 2977 static int 2978 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf, 2979 long read_size) 2980 { 2981 int n, index; 2982 long toread; 2983 2984 tlm_buffer_mark_empty(buf); 2985 for (index = 0, toread = read_size; toread > 0; ) { 2986 errno = 0; 2987 NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread); 2988 2989 n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index], 2990 toread); 2991 if (n == 0) { 2992 NDMP_LOG(LOG_DEBUG, "n: %d", n); 2993 break; 2994 } else if (n > 0) { 2995 NDMP_LOG(LOG_DEBUG, "n: %d", n); 2996 index += n; 2997 toread -= n; 2998 } else { 2999 buf->tb_eof = TRUE; 3000 buf->tb_errno = errno; 3001 buf->tb_buffer_size = 0; 3002 NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n); 3003 return (-1); 3004 } 3005 } 3006 3007 if (index > 0) { 3008 buf->tb_full = TRUE; 3009 buf->tb_buffer_size = read_size; 3010 if (read_size > 0) 3011 (void) memset(&buf->tb_buffer_data[index], 0, 3012 read_size - index); 3013 } else { 3014 buf->tb_eof = TRUE; 3015 buf->tb_buffer_size = 0; 3016 } 3017 3018 NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d," 3019 " errno: %d, size: %d, data: 0x%x", 3020 buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno, 3021 buf->tb_buffer_size, buf->tb_buffer_data); 3022 3023 return (0); 3024 } 3025 3026 3027 3028 /* 3029 * mover_socket_reader 3030 * 3031 * Mover socket reader thread. This is used when reading data from the 3032 * network socket for performing remote backups. 3033 * 3034 * Parameters: 3035 * session (input) - session pointer. 3036 * 3037 * Returns: 3038 * 0: on success 3039 * -1: otherwise 3040 */ 3041 int 3042 mover_socket_reader(ndmpd_session_t *session) 3043 { 3044 int bidx; /* buffer index */ 3045 ndmp_lbr_params_t *nlp; 3046 tlm_buffer_t *buf; 3047 tlm_buffers_t *bufs; 3048 tlm_cmd_t *lcmd; /* Local command */ 3049 tlm_commands_t *cmds; /* Commands structure */ 3050 static int nr = 0; 3051 3052 if ((nlp = ndmp_get_nlp(session)) == NULL) { 3053 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 3054 return (-1); 3055 } 3056 3057 cmds = &nlp->nlp_cmds; 3058 lcmd = cmds->tcs_command; 3059 bufs = lcmd->tc_buffers; 3060 3061 lcmd->tc_ref++; 3062 cmds->tcs_reader_count++; 3063 3064 /* 3065 * Let our parent thread know that we are running. 3066 */ 3067 tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER); 3068 3069 bidx = bufs->tbs_buffer_in; 3070 while (cmds->tcs_reader == TLM_BACKUP_RUN && 3071 lcmd->tc_reader == TLM_BACKUP_RUN) { 3072 buf = &bufs->tbs_buffer[bidx]; 3073 3074 if (buf->tb_full) { 3075 NDMP_LOG(LOG_DEBUG, "R%d", bidx); 3076 /* 3077 * The buffer is still full, wait for the consumer 3078 * thread to use it. 3079 */ 3080 tlm_buffer_out_buf_timed_wait(bufs, 100); 3081 } else { 3082 NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr); 3083 3084 (void) mover_socket_read_one_buf(session, buf, 3085 bufs->tbs_data_transfer_size); 3086 3087 /* 3088 * Can we do more buffering? 3089 */ 3090 if (is_buffer_erroneous(buf)) { 3091 NDMP_LOG(LOG_DEBUG, 3092 "Exiting, errno: %d, eot: %d, eof: %d", 3093 buf->tb_errno, buf->tb_eot, buf->tb_eof); 3094 break; 3095 } 3096 3097 (void) tlm_buffer_advance_in_idx(bufs); 3098 tlm_buffer_release_in_buf(bufs); 3099 bidx = bufs->tbs_buffer_in; 3100 } 3101 } 3102 3103 if (cmds->tcs_reader != TLM_BACKUP_RUN) 3104 NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN"); 3105 if (lcmd->tc_reader != TLM_BACKUP_RUN) 3106 NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN"); 3107 NDMP_LOG(LOG_DEBUG, "nr: %d", nr); 3108 3109 /* If the consumer is waiting for us, wake it up. */ 3110 tlm_buffer_release_in_buf(bufs); 3111 3112 /* 3113 * Clean up. 3114 */ 3115 cmds->tcs_reader_count--; 3116 lcmd->tc_ref--; 3117 lcmd->tc_writer = TLM_STOP; 3118 return (0); 3119 } 3120 3121 3122 /* 3123 * mover_tape_writer_one_buf 3124 * 3125 * Write one buffer for the mover to the local tape device. This is 3126 * used by mover_tape_writer thread. 3127 * 3128 * Parameters: 3129 * session (input) - session pointer. 3130 * buf (input) - buffer read 3131 * 3132 * Returns: 3133 * 0: on success 3134 * -1: otherwise 3135 */ 3136 static int 3137 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf) 3138 { 3139 int n; 3140 3141 NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d," 3142 " errno: %d, size: %d, data: 0x%x", 3143 buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno, 3144 buf->tb_buffer_size, buf->tb_buffer_data); 3145 3146 n = tape_write(session, buf->tb_buffer_data, buf->tb_buffer_size); 3147 3148 NDMP_LOG(LOG_DEBUG, "n: %d", n); 3149 3150 if (n <= 0) { 3151 ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED 3152 : NDMP_MOVER_HALT_INTERNAL_ERROR)); 3153 return (-1); 3154 } 3155 session->ns_mover.md_position += n; 3156 session->ns_mover.md_data_written += n; 3157 session->ns_mover.md_record_num++; 3158 3159 NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)"); 3160 tlm_buffer_mark_empty(buf); 3161 3162 return (0); 3163 } 3164 3165 3166 /* 3167 * mover_tape_writer 3168 * 3169 * Mover tape writer thread. This is used for performing remote backups 3170 * in a 3-way configuration. It writes the data from network socket to 3171 * the locally attached tape device. 3172 * 3173 * Parameters: 3174 * session (input) - session pointer. 3175 * 3176 * Returns: 3177 * 0: on success 3178 * -1: otherwise 3179 */ 3180 int 3181 mover_tape_writer(ndmpd_session_t *session) 3182 { 3183 int bidx; 3184 ndmp_lbr_params_t *nlp; 3185 tlm_buffer_t *buf; 3186 tlm_buffers_t *bufs; 3187 tlm_cmd_t *lcmd; 3188 tlm_commands_t *cmds; 3189 static int nw = 0; 3190 3191 if ((nlp = ndmp_get_nlp(session)) == NULL) { 3192 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 3193 return (-1); 3194 } 3195 3196 cmds = &nlp->nlp_cmds; 3197 lcmd = cmds->tcs_command; 3198 bufs = lcmd->tc_buffers; 3199 3200 lcmd->tc_ref++; 3201 cmds->tcs_writer_count++; 3202 3203 /* 3204 * Let our parent thread know that we are running. 3205 */ 3206 tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER); 3207 3208 bidx = bufs->tbs_buffer_out; 3209 buf = &bufs->tbs_buffer[bidx]; 3210 while (cmds->tcs_writer != (int)TLM_ABORT && 3211 lcmd->tc_writer != (int)TLM_ABORT) { 3212 if (buf->tb_full) { 3213 NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw); 3214 3215 if (mover_tape_write_one_buf(session, buf) < 0) { 3216 NDMP_LOG(LOG_DEBUG, 3217 "mover_tape_write_one_buf() failed"); 3218 break; 3219 } 3220 3221 (void) tlm_buffer_advance_out_idx(bufs); 3222 tlm_buffer_release_out_buf(bufs); 3223 bidx = bufs->tbs_buffer_out; 3224 buf = &bufs->tbs_buffer[bidx]; 3225 } else { 3226 if (lcmd->tc_writer != TLM_BACKUP_RUN) { 3227 /* No more data is coming, time to exit */ 3228 NDMP_LOG(LOG_DEBUG, "Time to exit"); 3229 break; 3230 } 3231 NDMP_LOG(LOG_DEBUG, "W%d", bidx); 3232 /* 3233 * The buffer is not full, wait for the producer 3234 * thread to fill it. 3235 */ 3236 tlm_buffer_in_buf_timed_wait(bufs, 100); 3237 } 3238 } 3239 3240 if (cmds->tcs_writer == (int)TLM_ABORT) 3241 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT"); 3242 if (lcmd->tc_writer == (int)TLM_ABORT) 3243 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT"); 3244 NDMP_LOG(LOG_DEBUG, "nw: %d", nw); 3245 3246 if (buf->tb_errno == 0) { 3247 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED); 3248 } else { 3249 NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno); 3250 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR); 3251 } 3252 3253 /* If the producer is waiting for us, wake it up. */ 3254 tlm_buffer_release_out_buf(bufs); 3255 3256 /* 3257 * Clean up. 3258 */ 3259 cmds->tcs_writer_count--; 3260 lcmd->tc_ref--; 3261 lcmd->tc_reader = TLM_STOP; 3262 return (0); 3263 } 3264 3265 3266 /* 3267 * start_mover_for_backup 3268 * 3269 * Starts a remote backup by running socket reader and tape 3270 * writer threads. The mover runs a remote backup in a 3-way backup 3271 * configuration. 3272 * 3273 * Parameters: 3274 * session (input) - session pointer. 3275 * 3276 * Returns: 3277 * 0: on success 3278 * -1: otherwise 3279 */ 3280 static int 3281 start_mover_for_backup(ndmpd_session_t *session) 3282 { 3283 ndmp_lbr_params_t *nlp; 3284 tlm_commands_t *cmds; 3285 int rc; 3286 3287 if ((nlp = ndmp_get_nlp(session)) == NULL) { 3288 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 3289 return (-1); 3290 } 3291 3292 cmds = &nlp->nlp_cmds; 3293 (void) memset(cmds, 0, sizeof (*cmds)); 3294 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN; 3295 cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, 3296 session->ns_mover.md_record_size); 3297 if (cmds->tcs_command == NULL) 3298 return (-1); 3299 3300 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN; 3301 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN; 3302 3303 /* 3304 * We intentionally don't wait for the threads to start since the 3305 * reply of the request (which resulted in calling this function) 3306 * must be sent to the client before probable errors are sent 3307 * to the client. 3308 */ 3309 rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session); 3310 if (rc == 0) { 3311 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER); 3312 } else { 3313 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s", 3314 strerror(rc)); 3315 return (-1); 3316 } 3317 3318 rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session); 3319 if (rc == 0) { 3320 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER); 3321 } else { 3322 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s", 3323 strerror(rc)); 3324 return (-1); 3325 } 3326 3327 tlm_release_reader_writer_ipc(cmds->tcs_command); 3328 return (0); 3329 } 3330 3331 3332 /* 3333 * is_writer_running 3334 * 3335 * Find out if the writer thread has started or not. 3336 * 3337 * Parameters: 3338 * session (input) - session pointer. 3339 * 3340 * Returns: 3341 * 0: not started 3342 * non-zero: started 3343 * Note: non-zero is also returned if the backup type is 3344 * neither TAR nor DUMP. I.e. the is_writer_running() 3345 * check does not apply in this case and things should 3346 * appear successful. 3347 */ 3348 static boolean_t 3349 is_writer_running(ndmpd_session_t *session) 3350 { 3351 boolean_t rv; 3352 ndmp_lbr_params_t *nlp; 3353 3354 if (session && (session->ns_butype > NDMP_BUTYPE_DUMP)) 3355 return (1); 3356 3357 if (session == NULL) 3358 rv = 0; 3359 else if ((nlp = ndmp_get_nlp(session)) == NULL) 3360 rv = 0; 3361 else 3362 rv = (nlp->nlp_cmds.tcs_writer_count > 0); 3363 3364 return (rv); 3365 } 3366 3367 3368 /* 3369 * is_writer_running_v3 3370 * 3371 * Find out if the writer thread has started or not. 3372 * 3373 * Parameters: 3374 * session (input) - session pointer. 3375 * 3376 * Returns: 3377 * 0: not started 3378 * non-zero: started 3379 * Note: non-zero is also returned if the backup type is 3380 * neither TAR nor DUMP. I.e. the is_writer_running() 3381 * check does not apply in this case and things should 3382 * appear successful. 3383 */ 3384 static boolean_t 3385 is_writer_running_v3(ndmpd_session_t *session) 3386 { 3387 boolean_t rv; 3388 ndmp_lbr_params_t *nlp; 3389 3390 if (session && (session->ns_butype > NDMP_BUTYPE_DUMP)) 3391 return (1); 3392 3393 if (session == NULL) 3394 rv = 0; 3395 else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) 3396 rv = 1; 3397 else if ((nlp = ndmp_get_nlp(session)) == NULL) 3398 rv = 0; 3399 else 3400 rv = (nlp->nlp_cmds.tcs_writer_count > 0); 3401 3402 return (rv); 3403 } 3404 3405 3406 /* 3407 * ndmpd_mover_wait_v3 3408 * 3409 * Take the mover state to PAUSED state 3410 * 3411 * Parameters: 3412 * session (input) - session pointer. 3413 * 3414 * Returns: 3415 * 0: on success 3416 * -1: otherwise 3417 */ 3418 int 3419 ndmpd_mover_wait_v3(ndmpd_session_t *session) 3420 { 3421 int rv = 0; 3422 3423 nlp_ref_nw(session); 3424 for (; ; ) { 3425 nlp_wait_nw(session); 3426 3427 if (nlp_event_rv_get(session) < 0) { 3428 rv = -1; 3429 break; 3430 } 3431 if (session->ns_eof) { 3432 NDMP_LOG(LOG_DEBUG, "session->ns_eof"); 3433 rv = -1; 3434 break; 3435 } 3436 if (session->ns_data.dd_abort) { 3437 NDMP_LOG(LOG_DEBUG, "data.abort"); 3438 rv = -1; 3439 break; 3440 } 3441 if (session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) { 3442 NDMP_LOG(LOG_DEBUG, 3443 "mover.state: NDMP_MOVER_STATE_ACTIVE"); 3444 session->ns_tape.td_record_count = 0; 3445 rv = 0; 3446 break; 3447 } else if (session->ns_mover.md_state == 3448 NDMP_MOVER_STATE_PAUSED) { 3449 NDMP_LOG(LOG_DEBUG, 3450 "mover.state: NDMP_MOVER_STATE_PAUSED"); 3451 } else { 3452 NDMP_LOG(LOG_DEBUG, "default"); 3453 rv = -1; 3454 break; 3455 } 3456 } 3457 3458 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA; 3459 nlp_unref_nw(session); 3460 return (rv); 3461 } 3462 3463 /* 3464 * ndmpd_mover_error_send 3465 * 3466 * This function sends the notify message to the client. 3467 * 3468 * Parameters: 3469 * session (input) - session pointer. 3470 * reason (input) - halt reason. 3471 * 3472 * Returns: 3473 * Error code 3474 */ 3475 int 3476 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason) 3477 { 3478 ndmp_notify_mover_halted_request req; 3479 3480 req.reason = reason; 3481 req.text_reason = ""; 3482 3483 return (ndmp_send_request(session->ns_connection, 3484 NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0)); 3485 } 3486 3487 3488 /* 3489 * ndmpd_mover_error_send_v4 3490 * 3491 * This function sends the notify message to the client. 3492 * 3493 * Parameters: 3494 * session (input) - session pointer. 3495 * reason (input) - halt reason. 3496 * 3497 * Returns: 3498 * Error code 3499 */ 3500 int 3501 ndmpd_mover_error_send_v4(ndmpd_session_t *session, 3502 ndmp_mover_halt_reason reason) 3503 { 3504 ndmp_notify_mover_halted_request_v4 req; 3505 3506 req.reason = reason; 3507 3508 return (ndmp_send_request(session->ns_connection, 3509 NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0)); 3510 } 3511 3512 3513 /* 3514 * ndmpd_mover_error 3515 * 3516 * This function is called when an unrecoverable mover error 3517 * has been detected. A notify message is sent to the client and the 3518 * mover is placed into the halted state. 3519 * 3520 * Parameters: 3521 * session (input) - session pointer. 3522 * reason (input) - halt reason. 3523 * 3524 * Returns: 3525 * void. 3526 */ 3527 void 3528 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason) 3529 { 3530 if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED || 3531 (session->ns_protocol_version > NDMPV2 && 3532 session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE)) 3533 return; 3534 3535 if (session->ns_protocol_version == NDMPV4) { 3536 if (ndmpd_mover_error_send_v4(session, reason) < 0) 3537 NDMP_LOG(LOG_DEBUG, 3538 "Error sending notify_mover_halted request"); 3539 } else { 3540 /* No media error in V3 */ 3541 if (reason == NDMP_MOVER_HALT_MEDIA_ERROR) 3542 reason = NDMP_MOVER_HALT_INTERNAL_ERROR; 3543 if (ndmpd_mover_error_send(session, reason) < 0) 3544 NDMP_LOG(LOG_DEBUG, 3545 "Error sending notify_mover_halted request"); 3546 } 3547 3548 if (session->ns_mover.md_listen_sock != -1) { 3549 (void) ndmpd_remove_file_handler(session, 3550 session->ns_mover.md_listen_sock); 3551 (void) close(session->ns_mover.md_listen_sock); 3552 session->ns_mover.md_listen_sock = -1; 3553 } 3554 if (session->ns_mover.md_sock != -1) { 3555 (void) ndmpd_remove_file_handler(session, 3556 session->ns_mover.md_sock); 3557 (void) close(session->ns_mover.md_sock); 3558 session->ns_mover.md_sock = -1; 3559 } 3560 3561 session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED; 3562 session->ns_mover.md_halt_reason = reason; 3563 } 3564 3565 3566 /* 3567 * mover_pause_v3 3568 * 3569 * Send an ndmp_notify_mover_paused request to the 3570 * NDMP client to inform the client that its attention is required. 3571 * Process messages until the data/mover operation is either aborted 3572 * or continued. 3573 * 3574 * Parameters: 3575 * client_data (input) - session pointer. 3576 * reason (input) - pause reason. 3577 * 3578 * Returns: 3579 * 0 - operation has been continued. 3580 * -1 - operation has been aborted. 3581 */ 3582 static int 3583 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason) 3584 { 3585 int rv; 3586 ndmp_notify_mover_paused_request request; 3587 3588 rv = 0; 3589 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 3590 session->ns_mover.md_pause_reason = reason; 3591 session->ns_mover.md_pre_cond = FALSE; 3592 3593 request.reason = session->ns_mover.md_pause_reason; 3594 request.seek_position = 3595 long_long_to_quad(session->ns_mover.md_position); 3596 3597 if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED, 3598 NDMP_NO_ERR, (void *)&request, 0) < 0) { 3599 NDMP_LOG(LOG_DEBUG, 3600 "Error sending notify_mover_paused_request"); 3601 return (-1); 3602 } 3603 3604 /* 3605 * 3-way operations are single-thread. The same thread 3606 * should process the messages. 3607 * 3608 * 2-way operations are multi-thread. The main thread 3609 * processes the messages. We just need to wait and 3610 * see if the mover state changes or the operation aborts. 3611 */ 3612 if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) { 3613 /* 3614 * Process messages until the state is changed by 3615 * an abort, continue, or close request . 3616 */ 3617 for (; ; ) { 3618 if (ndmpd_select(session, TRUE, HC_CLIENT) < 0) 3619 return (-1); 3620 3621 if (session->ns_eof == TRUE) 3622 return (-1); 3623 3624 switch (session->ns_mover.md_state) { 3625 case NDMP_MOVER_STATE_ACTIVE: 3626 session->ns_tape.td_record_count = 0; 3627 return (0); 3628 3629 case NDMP_MOVER_STATE_PAUSED: 3630 continue; 3631 3632 default: 3633 return (-1); 3634 } 3635 } 3636 3637 } else { 3638 if (session->ns_mover.md_data_addr.addr_type == 3639 NDMP_ADDR_LOCAL) { 3640 rv = ndmpd_mover_wait_v3(session); 3641 } else { 3642 NDMP_LOG(LOG_DEBUG, "Invalid address type %d", 3643 session->ns_mover.md_data_addr.addr_type); 3644 rv = -1; 3645 } 3646 } 3647 3648 return (rv); 3649 } 3650 3651 3652 /* 3653 * mover_tape_write_v3 3654 * 3655 * Writes a data record to tape. Detects and handles EOT conditions. 3656 * 3657 * Parameters: 3658 * session (input) - session pointer. 3659 * data (input) - data to be written. 3660 * length (input) - length of data to be written. 3661 * 3662 * Returns: 3663 * 0 - operation aborted by client. 3664 * -1 - error. 3665 * otherwise - number of bytes written. 3666 */ 3667 static int 3668 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length) 3669 { 3670 ssize_t n; 3671 int err; 3672 3673 for (; ; ) { 3674 /* 3675 * Refer to the comment at the top of ndmpd_tape.c file for 3676 * Mammoth2 tape drives. 3677 */ 3678 if (session->ns_tape.td_eom_seen) { 3679 NDMP_LOG(LOG_DEBUG, "eom_seen"); 3680 3681 session->ns_tape.td_eom_seen = FALSE; 3682 /* 3683 * End of media reached. 3684 * Notify client and wait for the client to 3685 * either abort the operation or continue the 3686 * operation after changing the tape. 3687 */ 3688 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 3689 ++ndmp_log_msg_id, 3690 "End of tape reached. Load next tape"); 3691 3692 err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM); 3693 3694 /* Operation aborted or connection terminated? */ 3695 if (err < 0) 3696 return (-1); 3697 3698 /* Retry the write to the new tape. */ 3699 continue; 3700 } 3701 3702 /* 3703 * Enforce mover window on write. 3704 */ 3705 if (session->ns_mover.md_position >= 3706 session->ns_mover.md_window_offset + 3707 session->ns_mover.md_window_length) { 3708 NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW"); 3709 3710 err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW); 3711 /* Operation aborted or connection terminated? */ 3712 if (err < 0) 3713 return (-1); 3714 3715 } 3716 3717 n = write(session->ns_tape.td_fd, data, length); 3718 if (n < 0) { 3719 NDMP_LOG(LOG_ERR, "Tape write error: %m."); 3720 return (-1); 3721 } 3722 NS_ADD(wtape, n); 3723 3724 if (n == 0 || n != length) { 3725 if (n != 0) { 3726 /* 3727 * Backup one record since the record 3728 * hits the EOM. 3729 */ 3730 NDMP_LOG(LOG_DEBUG, "Back up one record"); 3731 (void) ndmp_mtioctl(session->ns_tape.td_fd, 3732 MTBSR, 1); 3733 3734 /* setting logical EOM */ 3735 ndmpd_write_eom(session->ns_tape.td_fd); 3736 } 3737 3738 /* 3739 * End of media reached. 3740 * Notify client and wait for the client to 3741 * either abort the operation or continue the 3742 * operation after changing the tape. 3743 */ 3744 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 3745 ++ndmp_log_msg_id, 3746 "End of tape reached. Load next tape"); 3747 3748 err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM); 3749 3750 /* Operation aborted or connection terminated? */ 3751 if (err < 0) 3752 return (-1); 3753 3754 /* Retry the write to the new tape. */ 3755 continue; 3756 } 3757 3758 session->ns_tape.td_record_count++; 3759 return (n); 3760 } 3761 } 3762 3763 3764 /* 3765 * mover_tape_flush_v3 3766 * 3767 * Writes all remaining buffered data to tape. A partial record is 3768 * padded out to a full record with zeros. 3769 * 3770 * Parameters: 3771 * session (input) - session pointer. 3772 * data (input) - data to be written. 3773 * length (input) - length of data to be written. 3774 * 3775 * Returns: 3776 * -1 - error. 3777 * otherwise - number of bytes written. 3778 */ 3779 static int 3780 mover_tape_flush_v3(ndmpd_session_t *session) 3781 { 3782 int n; 3783 3784 if (session->ns_mover.md_w_index == 0) 3785 return (0); 3786 3787 (void) memset((void*)&session->ns_mover.md_buf[session-> 3788 ns_mover.md_w_index], 0, 3789 session->ns_mover.md_record_size - session->ns_mover.md_w_index); 3790 3791 n = mover_tape_write_v3(session, session->ns_mover.md_buf, 3792 session->ns_mover.md_record_size); 3793 if (n < 0) { 3794 NDMP_LOG(LOG_ERR, "Tape write error: %m."); 3795 return (-1); 3796 } 3797 3798 session->ns_mover.md_w_index = 0; 3799 session->ns_mover.md_position += n; 3800 return (n); 3801 } 3802 3803 3804 /* 3805 * ndmpd_local_write_v3 3806 * 3807 * Buffers and writes data to the tape device. 3808 * A full tape record is buffered before being written. 3809 * 3810 * Parameters: 3811 * session (input) - session pointer. 3812 * data (input) - data to be written. 3813 * length (input) - data length. 3814 * 3815 * Returns: 3816 * 0 - data successfully written. 3817 * -1 - error. 3818 */ 3819 int 3820 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length) 3821 { 3822 ulong_t count = 0; 3823 ssize_t n; 3824 ulong_t len; 3825 3826 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE || 3827 session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN || 3828 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) { 3829 NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data"); 3830 return (-1); 3831 } 3832 3833 /* 3834 * A length of 0 indicates that any buffered data should be 3835 * flushed to tape. 3836 */ 3837 if (length == 0) { 3838 if (session->ns_mover.md_w_index == 0) 3839 return (0); 3840 3841 (void) memset((void*)&session->ns_mover.md_buf[session-> 3842 ns_mover.md_w_index], 0, session->ns_mover.md_record_size - 3843 session->ns_mover.md_w_index); 3844 3845 n = mover_tape_write_v3(session, session->ns_mover.md_buf, 3846 session->ns_mover.md_record_size); 3847 if (n <= 0) { 3848 ndmpd_mover_error(session, 3849 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 3850 NDMP_MOVER_HALT_MEDIA_ERROR)); 3851 return (-1); 3852 } 3853 3854 session->ns_mover.md_position += n; 3855 session->ns_mover.md_data_written += 3856 session->ns_mover.md_w_index; 3857 session->ns_mover.md_record_num++; 3858 session->ns_mover.md_w_index = 0; 3859 return (0); 3860 } 3861 3862 /* Break the data into records. */ 3863 while (count < length) { 3864 /* 3865 * Determine if data needs to be buffered or 3866 * can be written directly from user supplied location. 3867 * We can fast path the write if there is no pending 3868 * buffered data and there is at least a full records worth 3869 * of data to be written. 3870 */ 3871 if (session->ns_mover.md_w_index == 0 && 3872 length - count >= session->ns_mover.md_record_size) { 3873 n = mover_tape_write_v3(session, &data[count], 3874 session->ns_mover.md_record_size); 3875 if (n <= 0) { 3876 ndmpd_mover_error(session, 3877 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 3878 NDMP_MOVER_HALT_MEDIA_ERROR)); 3879 return (-1); 3880 } 3881 3882 session->ns_mover.md_position += n; 3883 session->ns_mover.md_data_written += n; 3884 session->ns_mover.md_record_num++; 3885 count += n; 3886 continue; 3887 } 3888 3889 /* Buffer the data */ 3890 len = length - count; 3891 if (len > session->ns_mover.md_record_size - 3892 session->ns_mover.md_w_index) 3893 len = session->ns_mover.md_record_size - 3894 session->ns_mover.md_w_index; 3895 3896 (void) memcpy(&session->ns_mover.md_buf[session-> 3897 ns_mover.md_w_index], &data[count], len); 3898 session->ns_mover.md_w_index += len; 3899 count += len; 3900 3901 /* Write the buffer if its full */ 3902 if (session->ns_mover.md_w_index == 3903 session->ns_mover.md_record_size) { 3904 n = mover_tape_write_v3(session, 3905 session->ns_mover.md_buf, 3906 session->ns_mover.md_record_size); 3907 if (n < 0) { 3908 ndmpd_mover_error(session, 3909 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 3910 NDMP_MOVER_HALT_MEDIA_ERROR)); 3911 return (-1); 3912 } 3913 3914 session->ns_mover.md_position += n; 3915 session->ns_mover.md_data_written += n; 3916 session->ns_mover.md_record_num++; 3917 session->ns_mover.md_w_index = 0; 3918 } 3919 } 3920 3921 return (0); 3922 } 3923 3924 3925 /* 3926 * mover_data_read_v3 3927 * 3928 * Reads backup data from the data connection and writes the 3929 * received data to the tape device. 3930 * 3931 * Parameters: 3932 * cookie (input) - session pointer. 3933 * fd (input) - file descriptor. 3934 * mode (input) - select mode. 3935 * 3936 * Returns: 3937 * void. 3938 */ 3939 /*ARGSUSED*/ 3940 static void 3941 mover_data_read_v3(void *cookie, int fd, ulong_t mode) 3942 { 3943 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 3944 int n; 3945 ulong_t index; 3946 3947 n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index], 3948 session->ns_mover.md_record_size - session->ns_mover.md_w_index); 3949 3950 /* 3951 * Since this function is only called when select believes data 3952 * is available to be read, a return of zero indicates the 3953 * connection has been closed. 3954 */ 3955 if (n <= 0) { 3956 if (n < 0 && errno == EWOULDBLOCK) { 3957 NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno); 3958 return; 3959 } 3960 NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno); 3961 3962 /* Save the index since mover_tape_flush_v3 resets it. */ 3963 index = session->ns_mover.md_w_index; 3964 3965 /* Flush any buffered data to tape. */ 3966 if (mover_tape_flush_v3(session) > 0) { 3967 session->ns_mover.md_data_written += index; 3968 session->ns_mover.md_record_num++; 3969 } 3970 3971 if (n == 0) 3972 ndmpd_mover_error(session, 3973 NDMP_MOVER_HALT_CONNECT_CLOSED); 3974 else 3975 ndmpd_mover_error(session, 3976 NDMP_MOVER_HALT_INTERNAL_ERROR); 3977 3978 return; 3979 } 3980 3981 NDMP_LOG(LOG_DEBUG, "n %d", n); 3982 3983 session->ns_mover.md_w_index += n; 3984 3985 if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) { 3986 n = mover_tape_write_v3(session, session->ns_mover.md_buf, 3987 session->ns_mover.md_record_size); 3988 if (n <= 0) { 3989 ndmpd_mover_error(session, 3990 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 3991 NDMP_MOVER_HALT_MEDIA_ERROR)); 3992 return; 3993 } 3994 3995 session->ns_mover.md_position += n; 3996 session->ns_mover.md_w_index = 0; 3997 session->ns_mover.md_data_written += n; 3998 session->ns_mover.md_record_num++; 3999 } 4000 } 4001 4002 /* 4003 * mover_tape_read_v3 4004 * 4005 * Reads a data record from tape. Detects and handles EOT conditions. 4006 * 4007 * Parameters: 4008 * session (input) - session pointer. 4009 * data (input) - location to read data to. 4010 * 4011 * Returns: 4012 * 0 - operation aborted. 4013 * TAPE_READ_ERR - tape read IO error. 4014 * TAPE_NO_WRITER_ERR - no writer is running during tape read 4015 * otherwise - number of bytes read. 4016 */ 4017 static int 4018 mover_tape_read_v3(ndmpd_session_t *session, char *data) 4019 { 4020 ssize_t n; 4021 int err; 4022 int count; 4023 4024 count = session->ns_mover.md_record_size; 4025 for (; ; ) { 4026 n = read(session->ns_tape.td_fd, data, count); 4027 if (n < 0) { 4028 NDMP_LOG(LOG_ERR, "Tape read error: %m."); 4029 return (TAPE_READ_ERR); 4030 } 4031 NS_ADD(rtape, n); 4032 4033 if (n == 0) { 4034 if (!is_writer_running_v3(session)) 4035 return (TAPE_NO_WRITER_ERR); 4036 4037 /* 4038 * End of media reached. 4039 * Notify client and wait for the client to 4040 * either abort the data operation or continue the 4041 * operation after changing the tape. 4042 */ 4043 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL, 4044 ++ndmp_log_msg_id, 4045 "End of tape reached. Load next tape"); 4046 4047 err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOF); 4048 4049 /* Operation aborted or connection terminated? */ 4050 if (err < 0) { 4051 /* 4052 * Back up one record if it's read but not 4053 * used. 4054 */ 4055 if (count != session->ns_mover.md_record_size) 4056 (void) ndmp_mtioctl( 4057 session->ns_tape.td_fd, MTBSR, 1); 4058 return (0); 4059 } 4060 4061 /* Retry the read from the new tape. */ 4062 continue; 4063 } 4064 4065 data += n; 4066 count -= n; 4067 if (count <= 0) { 4068 session->ns_mover.md_record_num++; 4069 session->ns_tape.td_record_count++; 4070 return (n); 4071 } 4072 } 4073 } 4074 4075 4076 /* 4077 * mover_data_write_v3 4078 * 4079 * Reads backup data from the tape device and writes the 4080 * data to the data connection. 4081 * This function is called by ndmpd_select when the data connection 4082 * is ready for more data to be written. 4083 * 4084 * Parameters: 4085 * cookie (input) - session pointer. 4086 * fd (input) - file descriptor. 4087 * mode (input) - select mode. 4088 * 4089 * Returns: 4090 * void. 4091 */ 4092 /*ARGSUSED*/ 4093 static void 4094 mover_data_write_v3(void *cookie, int fd, ulong_t mode) 4095 { 4096 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 4097 int n; 4098 ulong_t len; 4099 u_longlong_t wlen; 4100 ndmp_notify_mover_paused_request pause_request; 4101 4102 /* 4103 * If the end of the mover window has been reached, 4104 * then notify the client that a seek is needed. 4105 * Remove the file handler to prevent this function from 4106 * being called. The handler will be reinstalled in 4107 * ndmpd_mover_continue. 4108 */ 4109 if (session->ns_mover.md_position >= session->ns_mover.md_window_offset 4110 + session->ns_mover.md_window_length) { 4111 NDMP_LOG(LOG_DEBUG, 4112 "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position); 4113 4114 session->ns_mover.md_w_index = 0; 4115 session->ns_mover.md_r_index = 0; 4116 4117 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED; 4118 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK; 4119 pause_request.reason = NDMP_MOVER_PAUSE_SEEK; 4120 pause_request.seek_position = 4121 long_long_to_quad(session->ns_mover.md_position); 4122 session->ns_mover.md_seek_position = 4123 session->ns_mover.md_position; 4124 4125 (void) ndmpd_remove_file_handler(session, fd); 4126 4127 if (ndmp_send_request(session->ns_connection, 4128 NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR, 4129 (void *)&pause_request, 0) < 0) { 4130 NDMP_LOG(LOG_DEBUG, 4131 "Sending notify_mover_paused request"); 4132 ndmpd_mover_error(session, 4133 NDMP_MOVER_HALT_INTERNAL_ERROR); 4134 } 4135 return; 4136 } 4137 4138 /* 4139 * Read more data into the tape buffer if the buffer is empty. 4140 */ 4141 if (session->ns_mover.md_w_index == 0) { 4142 n = mover_tape_read_v3(session, session->ns_mover.md_buf); 4143 4144 NDMP_LOG(LOG_DEBUG, 4145 "read %u bytes from tape", n); 4146 4147 if (n <= 0) { 4148 ndmpd_mover_error(session, (n == 0 ? 4149 NDMP_MOVER_HALT_ABORTED 4150 : NDMP_MOVER_HALT_MEDIA_ERROR)); 4151 return; 4152 } 4153 4154 /* 4155 * Discard data if the current data stream position is 4156 * prior to the seek position. This is necessary if a seek 4157 * request set the seek pointer to a position that is not a 4158 * record boundary. The seek request handler can only position 4159 * to the start of a record. 4160 */ 4161 if (session->ns_mover.md_position < 4162 session->ns_mover.md_seek_position) { 4163 session->ns_mover.md_r_index = 4164 session->ns_mover.md_seek_position - 4165 session->ns_mover.md_position; 4166 session->ns_mover.md_position = 4167 session->ns_mover.md_seek_position; 4168 } 4169 4170 session->ns_mover.md_w_index = n; 4171 } 4172 4173 /* 4174 * The limit on the total amount of data to be sent can be 4175 * dictated by either the end of the mover window or the end of the 4176 * seek window. 4177 * First determine which window applies and then determine if the 4178 * send length needs to be less than a full record to avoid 4179 * exceeding the window. 4180 */ 4181 if (session->ns_mover.md_position + 4182 session->ns_mover.md_bytes_left_to_read > 4183 session->ns_mover.md_window_offset + 4184 session->ns_mover.md_window_length) 4185 wlen = session->ns_mover.md_window_offset + 4186 session->ns_mover.md_window_length - 4187 session->ns_mover.md_position; 4188 else 4189 wlen = session->ns_mover.md_bytes_left_to_read; 4190 4191 NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen); 4192 4193 /* 4194 * Now limit the length to the amount of data in the buffer. 4195 */ 4196 if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index) 4197 wlen = session->ns_mover.md_w_index - 4198 session->ns_mover.md_r_index; 4199 4200 len = wlen & 0xffffffff; 4201 NDMP_LOG(LOG_DEBUG, 4202 "buffer restrictions: wlen %llu len %u", wlen, len); 4203 4204 /* 4205 * Write the data to the data connection. 4206 */ 4207 n = write(session->ns_mover.md_sock, 4208 &session->ns_mover.md_buf[session->ns_mover.md_r_index], len); 4209 4210 if (n < 0) { 4211 if (errno == EWOULDBLOCK) { 4212 NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno); 4213 return; 4214 } 4215 4216 NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno); 4217 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED); 4218 return; 4219 } 4220 4221 NDMP_LOG(LOG_DEBUG, 4222 "wrote %u of %u bytes to data connection position %llu r_index %lu", 4223 n, len, session->ns_mover.md_position, 4224 session->ns_mover.md_r_index); 4225 4226 session->ns_mover.md_r_index += n; 4227 session->ns_mover.md_position += n; 4228 session->ns_mover.md_bytes_left_to_read -= n; 4229 4230 /* 4231 * If all data in the buffer has been written, 4232 * zero the buffer indices. The next call to this function 4233 * will read more data from the tape device into the buffer. 4234 */ 4235 if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) { 4236 session->ns_mover.md_r_index = 0; 4237 session->ns_mover.md_w_index = 0; 4238 } 4239 4240 /* 4241 * If the read limit has been reached, 4242 * then remove the file handler to prevent this 4243 * function from getting called. The next mover_read request 4244 * will reinstall the handler. 4245 */ 4246 if (session->ns_mover.md_bytes_left_to_read == 0) 4247 (void) ndmpd_remove_file_handler(session, fd); 4248 } 4249 4250 4251 /* 4252 * accept_connection_v3 4253 * 4254 * Accept a data connection from a data server. 4255 * Called by ndmpd_select when a connection is pending on 4256 * the mover listen socket. 4257 * 4258 * Parameters: 4259 * cookie (input) - session pointer. 4260 * fd (input) - file descriptor. 4261 * mode (input) - select mode. 4262 * 4263 * Returns: 4264 * void. 4265 */ 4266 /*ARGSUSED*/ 4267 static void 4268 accept_connection_v3(void *cookie, int fd, ulong_t mode) 4269 { 4270 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 4271 int from_len; 4272 struct sockaddr_in from; 4273 int flag = 1; 4274 4275 from_len = sizeof (from); 4276 session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from, 4277 &from_len); 4278 4279 NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port), 4280 inet_ntoa(IN_ADDR(from.sin_addr.s_addr))); 4281 4282 (void) ndmpd_remove_file_handler(session, fd); 4283 (void) close(session->ns_mover.md_listen_sock); 4284 session->ns_mover.md_listen_sock = -1; 4285 4286 if (session->ns_mover.md_sock < 0) { 4287 NDMP_LOG(LOG_DEBUG, "Accept error: %m"); 4288 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR); 4289 return; 4290 } 4291 4292 /* 4293 * Save the peer address. 4294 */ 4295 session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr; 4296 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port); 4297 4298 /* 4299 * Set the parameter of the new socket. 4300 */ 4301 (void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE, 4302 &flag, sizeof (flag)); 4303 4304 ndmp_set_socket_nodelay(session->ns_mover.md_sock); 4305 if (ndmp_sbs > 0) 4306 ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 4307 ndmp_sbs*KILOBYTE); 4308 if (ndmp_rbs > 0) 4309 ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 4310 ndmp_rbs*KILOBYTE); 4311 4312 NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock); 4313 4314 if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) { 4315 if (ndmpd_add_file_handler(session, (void*)session, 4316 session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ, 4317 HC_MOVER, mover_data_read_v3) < 0) { 4318 ndmpd_mover_error(session, 4319 NDMP_MOVER_HALT_INTERNAL_ERROR); 4320 return; 4321 } 4322 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d", 4323 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)), 4324 ntohs(from.sin_port)); 4325 } else { 4326 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d", 4327 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)), 4328 ntohs(from.sin_port)); 4329 } 4330 4331 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE; 4332 } 4333 4334 4335 /* 4336 * create_listen_socket_v3 4337 * 4338 * Creates a socket for listening for accepting data connections. 4339 * 4340 * Parameters: 4341 * session (input) - session pointer. 4342 * addr (output) - location to store address of socket. 4343 * port (output) - location to store port of socket. 4344 * 4345 * Returns: 4346 * 0 - success. 4347 * -1 - error. 4348 */ 4349 static int 4350 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port) 4351 { 4352 session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port); 4353 if (session->ns_mover.md_listen_sock < 0) 4354 return (-1); 4355 4356 /* 4357 * Add a file handler for the listen socket. 4358 * ndmpd_select will call accept_connection when a 4359 * connection is ready to be accepted. 4360 */ 4361 if (ndmpd_add_file_handler(session, (void *) session, 4362 session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER, 4363 accept_connection_v3) < 0) { 4364 (void) close(session->ns_mover.md_listen_sock); 4365 session->ns_mover.md_listen_sock = -1; 4366 return (-1); 4367 } 4368 NDMP_LOG(LOG_DEBUG, "IP %s port %d", 4369 inet_ntoa(*(struct in_addr *)addr), ntohs(*port)); 4370 return (0); 4371 } 4372 4373 4374 /* 4375 * mover_connect_sock_v3 4376 * 4377 * Connect the mover to the specified address 4378 * 4379 * Parameters: 4380 * session (input) - session pointer. 4381 * mode (input) - mover mode. 4382 * addr (output) - location to store address of socket. 4383 * port (output) - location to store port of socket. 4384 * 4385 * Returns: 4386 * error code. 4387 */ 4388 static ndmp_error 4389 mover_connect_sock_v3(ndmpd_session_t *session, ndmp_mover_mode mode, 4390 ulong_t addr, ushort_t port) 4391 { 4392 int sock; 4393 4394 sock = ndmp_connect_sock_v3(addr, port); 4395 if (sock < 0) 4396 return (NDMP_CONNECT_ERR); 4397 4398 if (mode == NDMP_MOVER_MODE_READ) { 4399 if (ndmpd_add_file_handler(session, (void*)session, sock, 4400 NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) { 4401 (void) close(sock); 4402 return (NDMP_CONNECT_ERR); 4403 } 4404 } 4405 session->ns_mover.md_sock = sock; 4406 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP; 4407 session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr); 4408 session->ns_mover.md_data_addr.tcp_port_v3 = port; 4409 return (NDMP_NO_ERR); 4410 } 4411 4412 4413 /* 4414 * ndmpd_local_read_v3 4415 * 4416 * Reads data from the local tape device. 4417 * Full tape records are read and buffered. 4418 * 4419 * Parameters: 4420 * session (input) - session pointer. 4421 * data (input) - location to store data. 4422 * length (input) - data length. 4423 * 4424 * Returns: 4425 * 1 - no read error but no writer running 4426 * 0 - data successfully read. 4427 * -1 - error. 4428 */ 4429 int 4430 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length) 4431 { 4432 ulong_t count; 4433 ulong_t len; 4434 ssize_t n; 4435 4436 count = 0; 4437 if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE || 4438 session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN || 4439 session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) { 4440 NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data"); 4441 return (-1); 4442 } 4443 4444 /* 4445 * Automatically increase the seek window if necessary. 4446 * This is needed in the event the module attempts to read 4447 * past a seek window set via a prior call to ndmpd_seek() or 4448 * the module has not issued a seek. If no seek was issued then 4449 * pretend that a seek was issued to read the entire tape. 4450 */ 4451 if (length > session->ns_mover.md_bytes_left_to_read) { 4452 /* ndmpd_seek() never called? */ 4453 if (session->ns_data.dd_read_length == 0) { 4454 session->ns_mover.md_bytes_left_to_read = ~0LL; 4455 session->ns_data.dd_read_offset = 0LL; 4456 session->ns_data.dd_read_length = ~0LL; 4457 } else { 4458 session->ns_mover.md_bytes_left_to_read = length; 4459 session->ns_data.dd_read_offset = 4460 session->ns_mover.md_position; 4461 session->ns_data.dd_read_length = length; 4462 } 4463 } 4464 4465 /* 4466 * Read as many records as necessary to satisfy the request. 4467 */ 4468 while (count < length) { 4469 /* 4470 * If the end of the mover window has been reached, 4471 * then notify the client that a new data window is needed. 4472 */ 4473 if (session->ns_mover.md_position >= 4474 session->ns_mover.md_window_offset + 4475 session->ns_mover.md_window_length) { 4476 if (mover_pause_v3(session, 4477 NDMP_MOVER_PAUSE_SEEK) < 0) { 4478 ndmpd_mover_error(session, 4479 NDMP_MOVER_HALT_INTERNAL_ERROR); 4480 return (-1); 4481 } 4482 continue; 4483 } 4484 4485 len = length - count; 4486 4487 /* 4488 * Prevent reading past the end of the window. 4489 */ 4490 if (len > session->ns_mover.md_window_offset + 4491 session->ns_mover.md_window_length - 4492 session->ns_mover.md_position) 4493 len = session->ns_mover.md_window_offset + 4494 session->ns_mover.md_window_length - 4495 session->ns_mover.md_position; 4496 4497 /* 4498 * Copy from the data buffer first. 4499 */ 4500 if (session->ns_mover.md_w_index - 4501 session->ns_mover.md_r_index != 0) { 4502 /* 4503 * Limit the copy to the amount of data in the buffer. 4504 */ 4505 if (len > session->ns_mover.md_w_index - 4506 session->ns_mover.md_r_index) 4507 len = session->ns_mover.md_w_index - 4508 session->ns_mover.md_r_index; 4509 (void) memcpy((void*)&data[count], 4510 &session->ns_mover.md_buf[session-> 4511 ns_mover.md_r_index], len); 4512 count += len; 4513 session->ns_mover.md_r_index += len; 4514 session->ns_mover.md_bytes_left_to_read -= len; 4515 session->ns_mover.md_position += len; 4516 continue; 4517 } 4518 4519 /* 4520 * Determine if data needs to be buffered or 4521 * can be read directly to user supplied location. 4522 * We can fast path the read if at least a full record 4523 * needs to be read and there is no seek pending. 4524 * This is done to eliminate a buffer copy. 4525 */ 4526 if (len >= session->ns_mover.md_record_size && 4527 session->ns_mover.md_position >= 4528 session->ns_mover.md_seek_position) { 4529 n = mover_tape_read_v3(session, &data[count]); 4530 if (n <= 0) { 4531 if (n == TAPE_NO_WRITER_ERR) 4532 return (1); 4533 4534 ndmpd_mover_error(session, 4535 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 4536 NDMP_MOVER_HALT_MEDIA_ERROR)); 4537 return ((n == 0) ? 1 : -1); 4538 } 4539 4540 count += n; 4541 session->ns_mover.md_bytes_left_to_read -= n; 4542 session->ns_mover.md_position += n; 4543 continue; 4544 } 4545 4546 /* Read the next record into the buffer. */ 4547 n = mover_tape_read_v3(session, session->ns_mover.md_buf); 4548 if (n <= 0) { 4549 if (n == TAPE_NO_WRITER_ERR) 4550 return (1); 4551 4552 ndmpd_mover_error(session, 4553 (n == 0 ? NDMP_MOVER_HALT_ABORTED : 4554 NDMP_MOVER_HALT_MEDIA_ERROR)); 4555 return ((n == 0) ? 1 : -1); 4556 } 4557 4558 session->ns_mover.md_w_index = n; 4559 session->ns_mover.md_r_index = 0; 4560 4561 NDMP_LOG(LOG_DEBUG, "n: %d", n); 4562 4563 /* 4564 * Discard data if the current data stream position is 4565 * prior to the seek position. This is necessary if a seek 4566 * request set the seek pointer to a position that is not a 4567 * record boundary. The seek request handler can only position 4568 * to the start of a record. 4569 */ 4570 if (session->ns_mover.md_position < 4571 session->ns_mover.md_seek_position) { 4572 session->ns_mover.md_r_index = 4573 session->ns_mover.md_seek_position - 4574 session->ns_mover.md_position; 4575 session->ns_mover.md_position = 4576 session->ns_mover.md_seek_position; 4577 } 4578 } 4579 4580 return (0); 4581 } 4582