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