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