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