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