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