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