1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * kRPC Server for sndr
28 */
29
30 #include <sys/types.h>
31 #include <sys/ksynch.h>
32 #include <sys/cmn_err.h>
33 #include <sys/kmem.h>
34 #include <sys/cred.h>
35 #include <sys/conf.h>
36 #include <sys/stream.h>
37 #include <sys/errno.h>
38
39 #include <sys/unistat/spcs_s.h>
40 #include <sys/unistat/spcs_s_k.h>
41 #include <sys/unistat/spcs_errors.h>
42
43 #ifdef _SunOS_2_6
44 /*
45 * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
46 * define enum_t here as it is all we need from rpc/types.h
47 * anyway and make it look like we included it. Yuck.
48 */
49 #define _RPC_TYPES_H
50 typedef int enum_t;
51 #else
52 #ifndef DS_DDICT
53 #include <rpc/types.h>
54 #endif
55 #endif /* _SunOS_2_6 */
56
57 #ifndef DS_DDICT
58 #include <rpc/auth.h>
59 #include <rpc/svc.h>
60 #include <rpc/xdr.h>
61 #endif
62 #include <sys/ddi.h>
63 #include <sys/nsc_thread.h>
64 #ifdef DS_DDICT
65 #include <sys/nsctl/contract.h>
66 #endif
67 #include <sys/nsctl/nsctl.h>
68 #include <sys/ncall/ncall.h>
69
70 #include <sys/sdt.h> /* dtrace is S10 or later */
71
72 #include "rdc_io.h"
73 #include "rdc_bitmap.h"
74 #include "rdcsrv.h"
75
76 static rdc_sleepq_t *rdc_newsleepq();
77 static void rdc_delsleepq(rdc_sleepq_t *);
78 static int rdc_sleepq(rdc_group_t *, rdc_sleepq_t *);
79 static int rdc_combywrite(rdc_k_info_t *, nsc_buf_t *);
80 static int rdc_writemaxfba(rdc_k_info_t *, rdc_u_info_t *,
81 rdc_net_dataset_t *, uint_t, int);
82 static void rdc_setbitind(int *, net_pendvec_t *, rdc_net_dataset_t *, uint_t,
83 int, int);
84 static void rdc_dopending(rdc_group_t *, netwriteres *);
85 static nsc_vec_t *rdc_dset2vec(rdc_net_dataset_t *);
86 static int rdc_combyread(rdc_k_info_t *, rdc_u_info_t *, nsc_buf_t *);
87 static int rdc_readmaxfba(int, nsc_off_t, nsc_size_t, int);
88 static int rdc_dsetcopy(rdc_net_dataset_t *, nsc_vec_t *, nsc_off_t, nsc_size_t,
89 char *, int, int);
90
91 /* direction for dsetcopy() */
92 #define COPY_IN 1 /* copy data into the rpc buffer */
93 #define COPY_OUT 2 /* copy data out of the rpc buffer */
94
95 #define MAX_EINTR_COUNT 1000
96
97 static int rdc_rread_slow;
98 static rdcsrv_t rdc_srvtab[];
99
100 #ifdef DEBUG
101 static int rdc_netwrite6;
102 static int rdc_stall0;
103 static int rdc_sleepcnt;
104 int rdc_datasetcnt;
105 #endif
106
107
108 int
_rdc_sync_event_notify(int operation,char * volume,char * group)109 _rdc_sync_event_notify(int operation, char *volume, char *group)
110 {
111 int ack = 0;
112 clock_t time;
113
114 mutex_enter(&rdc_sync_mutex);
115 mutex_enter(&rdc_sync_event.mutex);
116
117 if (rdc_sync_event.daemon_waiting) {
118 rdc_sync_event.daemon_waiting = 0;
119 rdc_sync_event.event = operation;
120 (void) strncpy(rdc_sync_event.master, volume, NSC_MAXPATH);
121 (void) strncpy(rdc_sync_event.group, group, NSC_MAXPATH);
122
123 cv_signal(&rdc_sync_event.cv);
124
125 rdc_sync_event.kernel_waiting = 1;
126 time = cv_reltimedwait_sig(&rdc_sync_event.done_cv,
127 &rdc_sync_event.mutex, rdc_sync_event_timeout,
128 TR_CLOCK_TICK);
129 if (time == (clock_t)0 || time == (clock_t)-1) {
130 /* signalled or timed out */
131 ack = 0;
132 } else {
133 if (rdc_sync_event.ack)
134 ack = 1;
135 else
136 ack = -1;
137 }
138 }
139 mutex_exit(&rdc_sync_event.mutex);
140 mutex_exit(&rdc_sync_mutex);
141 return (ack);
142 }
143
144
145 int
_rdc_sync_event_wait(void * arg0,void * arg1,int mode,spcs_s_info_t kstatus,int * rvp)146 _rdc_sync_event_wait(void *arg0, void *arg1, int mode, spcs_s_info_t kstatus,
147 int *rvp)
148 {
149 int rc = 0;
150 static char master[NSC_MAXPATH];
151
152 master[0] = '\0';
153 *rvp = 0;
154 if (ddi_copyin(arg0, master, NSC_MAXPATH, mode))
155 return (EFAULT);
156
157 mutex_enter(&rdc_sync_event.mutex);
158
159 if (rdc_sync_event.kernel_waiting &&
160 (rdc_sync_event.lbolt - nsc_lbolt() < rdc_sync_event_timeout)) {
161 /* We haven't been away too long */
162 if (master[0])
163 rdc_sync_event.ack = 1;
164 else
165 rdc_sync_event.ack = 0;
166 rdc_sync_event.kernel_waiting = 0;
167 cv_signal(&rdc_sync_event.done_cv);
168 }
169
170 rdc_sync_event.daemon_waiting = 1;
171 if (cv_wait_sig(&rdc_sync_event.cv, &rdc_sync_event.mutex) == 0) {
172 rdc_sync_event.daemon_waiting = 0;
173 rc = EAGAIN;
174 spcs_s_add(kstatus, rc);
175 } else {
176 (void) ddi_copyout(rdc_sync_event.master, arg0, NSC_MAXPATH,
177 mode);
178 (void) ddi_copyout(rdc_sync_event.group, arg1, NSC_MAXPATH,
179 mode);
180 *rvp = rdc_sync_event.event;
181 }
182 rdc_sync_event.lbolt = nsc_lbolt();
183 mutex_exit(&rdc_sync_event.mutex);
184
185 return (rc);
186 }
187
188
189 static int
rdc_allow_sec_sync(rdc_u_info_t * urdc,int option)190 rdc_allow_sec_sync(rdc_u_info_t *urdc, int option)
191 {
192 rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
193 rdc_k_info_t *ktmp;
194 rdc_u_info_t *utmp;
195
196 if (!IS_MULTI(krdc))
197 return (0);
198
199 rdc_many_enter(krdc);
200
201 krdc = krdc->multi_next;
202 urdc = &rdc_u_info[krdc->index];
203
204 if (!IS_ENABLED(urdc)) {
205 rdc_many_exit(krdc);
206 return (0);
207 }
208
209 if (option == CCIO_RSYNC) {
210
211 /* Reverse sync */
212
213 if (rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED) {
214 /*
215 * Reverse sync needed or in progress.
216 */
217 rdc_many_exit(krdc);
218 return (-1);
219 }
220 } else {
221 ASSERT(option == CCIO_SLAVE);
222
223 /* Forward sync */
224
225 if (rdc_get_mflags(urdc) & RDC_SLAVE) {
226 /*
227 * Reverse syncing is bad, as that means that data
228 * is already flowing to the target of the requested
229 * sync operation.
230 */
231 rdc_many_exit(krdc);
232 return (-1);
233 }
234
235 /*
236 * Clear "reverse sync needed" on all 1-many volumes.
237 * The data on them will be updated from the primary of this
238 * requested sync operation, so the aborted reverse sync need
239 * not be completed.
240 */
241
242 if ((rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED) ||
243 (rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
244 rdc_clr_mflags(urdc, RDC_RSYNC_NEEDED);
245 rdc_clr_flags(urdc, RDC_VOL_FAILED);
246 rdc_write_state(urdc);
247 }
248 if (IS_MANY(krdc)) {
249 for (ktmp = krdc->many_next; ktmp != krdc;
250 ktmp = ktmp->many_next) {
251 utmp = &rdc_u_info[ktmp->index];
252 if (!IS_ENABLED(utmp))
253 continue;
254 if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) {
255 rdc_clr_mflags(utmp, RDC_RSYNC_NEEDED);
256 rdc_write_state(utmp);
257 }
258 }
259 }
260 }
261
262 rdc_many_exit(krdc);
263
264 return (0);
265 }
266
267
268 /*
269 * r_net_null
270 * Proc 0 Null action
271 */
272 static void
r_net_null(SVCXPRT * xprt)273 r_net_null(SVCXPRT *xprt)
274 {
275 (void) svc_sendreply(xprt, xdr_void, 0);
276 }
277
278 /*
279 * r_net_read
280 */
281 static void
r_net_read(SVCXPRT * xprt)282 r_net_read(SVCXPRT *xprt)
283 {
284 readres resp;
285 rdc_u_info_t *urdc;
286 struct rread diskio;
287 char *buffer = NULL;
288 uchar_t *sv_addr;
289 nsc_vec_t *vec;
290 int pos, st;
291 int nocache;
292 int sv_len;
293 nsc_vec_t *vector = NULL;
294 rdc_net_dataset_t *dset = NULL;
295 int vecsz = 0;
296
297 st = SVC_GETARGS(xprt, xdr_rread, (char *)&diskio);
298 if (!st) {
299 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
300 return;
301 }
302 nocache = (diskio.flag & RDC_RREAD_FAIL) ? 0 : NSC_NOCACHE;
303
304 if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
305 resp.rr_status = RDCERR_NOENT;
306 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
307 #ifdef DEBUG
308 cmn_err(CE_NOTE,
309 "!r_net_read: EPROTO cd out or not enabled");
310 #endif
311 return;
312 }
313
314 urdc = &rdc_u_info[diskio.cd];
315
316 if (diskio.flag & RDC_RREAD_START) {
317 /* setup rpc */
318 if (!IS_ENABLED(urdc)) {
319 st = 0;
320 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
321 return;
322 }
323 st = rdc_readmaxfba(diskio.cd, diskio.pos, diskio.len,
324 nocache);
325
326 if (!svc_sendreply(xprt, xdr_int, (char *)&st)) {
327 if (st != 0) {
328 rdc_net_dataset_t *dset;
329 if (dset = rdc_net_get_set(diskio.cd, st)) {
330 rdc_net_del_set(diskio.cd, dset);
331 } else {
332 cmn_err(CE_NOTE, "!r_net_read: get_set "
333 "has failed in cleanup");
334 }
335 }
336 }
337 return;
338 }
339
340 /* data rpc */
341
342 #ifdef DEBUG
343 if ((diskio.flag & RDC_RREAD_DATA) == 0) {
344 cmn_err(CE_WARN, "!r_net_read: received non-DATA rpc! flag %x",
345 diskio.flag);
346 }
347 #endif
348
349 dset = rdc_net_get_set(diskio.cd, diskio.idx);
350 if (dset) {
351 vector = rdc_dset2vec(dset);
352 }
353 if (vector == NULL) {
354 resp.rr_status = RDCERR_NOMEM;
355 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
356 goto cleanup;
357 }
358 vecsz = (dset->nitems + 1) * sizeof (nsc_vec_t);
359
360 if (!IS_ENABLED(urdc)) {
361 resp.rr_status = RDCERR_NOENT;
362 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
363 goto cleanup;
364 }
365 resp.rr_status = RDC_OK;
366
367 /* find place in vector */
368 vec = vector;
369 pos = diskio.pos - dset->pos;
370
371 for (; pos >= FBA_NUM(vec->sv_len); vec++)
372 pos -= FBA_NUM(vec->sv_len);
373
374 sv_addr = vec->sv_addr + FBA_SIZE(pos);
375 sv_len = vec->sv_len - FBA_SIZE(pos);
376
377 /*
378 * IF the data is in a single sb_vec entry
379 * THEN
380 * we can just point to that
381 * ELSE
382 * we have to alloc a local buffer,
383 * copy the data in and the point to
384 * the local buffer.
385 */
386
387 if (sv_len >= FBA_SIZE(diskio.len)) {
388 /* fast */
389 resp.rr_data = (char *)sv_addr;
390 resp.rr_bufsize = FBA_SIZE(diskio.len);
391 } else {
392 /* slow */
393 rdc_rread_slow++; /* rough count */
394 resp.rr_bufsize = FBA_SIZE(diskio.len);
395 buffer = kmem_alloc(resp.rr_bufsize, KM_NOSLEEP);
396 if (!buffer) {
397 resp.rr_status = RDCERR_NOMEM;
398 } else {
399 resp.rr_data = buffer;
400 if (!rdc_dsetcopy(dset, vector, diskio.pos, diskio.len,
401 resp.rr_data, resp.rr_bufsize, COPY_IN)) {
402 resp.rr_status = RDCERR_NOMEM; /* ??? */
403 }
404 }
405 }
406
407 st = svc_sendreply(xprt, xdr_readres, (char *)&resp); /* send data */
408
409 cleanup:
410
411 if (dset) {
412 if (!st ||
413 (diskio.flag & RDC_RREAD_END) ||
414 (resp.rr_status != RDC_OK)) {
415 /*
416 * RPC reply failed, OR
417 * Last RPC for this IO operation, OR
418 * We are failing this IO operation.
419 *
420 * Do cleanup.
421 */
422 rdc_net_del_set(diskio.cd, dset);
423 } else {
424 rdc_net_put_set(diskio.cd, dset);
425 }
426 }
427
428 if (buffer)
429 kmem_free(buffer, resp.rr_bufsize);
430 if (vector) {
431 kmem_free(vector, vecsz);
432 RDC_DSMEMUSE(-vecsz);
433 }
434 }
435
436 /*
437 * r_net_read (v6)
438 */
439 static void
r_net_read6(SVCXPRT * xprt)440 r_net_read6(SVCXPRT *xprt)
441 {
442 readres resp;
443 rdc_u_info_t *urdc;
444 struct rread6 diskio;
445 char *buffer = NULL;
446 uchar_t *sv_addr;
447 nsc_vec_t *vec;
448 int pos, st;
449 int nocache;
450 int sv_len;
451 nsc_vec_t *vector = NULL;
452 rdc_net_dataset_t *dset = NULL;
453 int vecsz = 0;
454
455 st = SVC_GETARGS(xprt, xdr_rread6, (char *)&diskio);
456 if (!st) {
457 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
458 return;
459 }
460 nocache = (diskio.flag & RDC_RREAD_FAIL) ? 0 : NSC_NOCACHE;
461
462 if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
463 resp.rr_status = RDCERR_NOENT;
464 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
465 #ifdef DEBUG
466 cmn_err(CE_NOTE, "!r_net_read6: EPROTO cd out or not enabled");
467 #endif
468 return;
469 }
470
471 urdc = &rdc_u_info[diskio.cd];
472
473 if (diskio.flag & RDC_RREAD_START) {
474 /* setup rpc */
475 if (!IS_ENABLED(urdc)) {
476 st = 0;
477 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
478 return;
479 }
480 st = rdc_readmaxfba(diskio.cd, diskio.pos, diskio.len,
481 nocache);
482
483 if (!svc_sendreply(xprt, xdr_int, (char *)&st)) {
484 if (st != 0) {
485 rdc_net_dataset_t *dset;
486 if (dset = rdc_net_get_set(diskio.cd, st)) {
487 rdc_net_del_set(diskio.cd, dset);
488 } else {
489 cmn_err(CE_NOTE, "!read6: get_set "
490 "has failed in cleanup");
491 }
492 }
493 }
494 return;
495 }
496
497 /* data rpc */
498
499 #ifdef DEBUG
500 if ((diskio.flag & RDC_RREAD_DATA) == 0) {
501 cmn_err(CE_WARN, "!read6: received non-DATA rpc! flag %x",
502 diskio.flag);
503 }
504 #endif
505
506 dset = rdc_net_get_set(diskio.cd, diskio.idx);
507 if (dset) {
508 vector = rdc_dset2vec(dset);
509 }
510 if (vector == NULL) {
511 resp.rr_status = RDCERR_NOMEM;
512 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
513 goto cleanup;
514 }
515 vecsz = (dset->nitems + 1) * sizeof (nsc_vec_t);
516
517 if (!IS_ENABLED(urdc)) {
518 resp.rr_status = RDCERR_NOENT;
519 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
520 goto cleanup;
521 }
522 resp.rr_status = RDC_OK;
523
524 /* find place in vector */
525 vec = vector;
526 pos = diskio.pos - dset->pos;
527
528 for (; pos >= FBA_NUM(vec->sv_len); vec++)
529 pos -= FBA_NUM(vec->sv_len);
530
531 sv_addr = vec->sv_addr + FBA_SIZE(pos);
532 sv_len = vec->sv_len - FBA_SIZE(pos);
533
534 /*
535 * IF the data is in a single sb_vec entry
536 * THEN
537 * we can just point to that
538 * ELSE
539 * we have to alloc a local buffer,
540 * copy the data in and the point to
541 * the local buffer.
542 */
543
544 if (sv_len >= FBA_SIZE(diskio.len)) {
545 /* fast */
546 resp.rr_data = (char *)sv_addr;
547 resp.rr_bufsize = FBA_SIZE(diskio.len);
548 } else {
549 /* slow */
550 rdc_rread_slow++; /* rough count */
551 resp.rr_bufsize = FBA_SIZE(diskio.len);
552 buffer = kmem_alloc(resp.rr_bufsize, KM_NOSLEEP);
553 if (!buffer) {
554 resp.rr_status = RDCERR_NOMEM;
555 } else {
556 resp.rr_data = buffer;
557 if (!rdc_dsetcopy(dset, vector, diskio.pos, diskio.len,
558 resp.rr_data, resp.rr_bufsize, COPY_IN)) {
559 resp.rr_status = RDCERR_NOMEM; /* ??? */
560 }
561 }
562 }
563
564 st = svc_sendreply(xprt, xdr_readres, (char *)&resp); /* send data */
565
566 cleanup:
567
568 if (dset) {
569 if (!st ||
570 (diskio.flag & RDC_RREAD_END) ||
571 (resp.rr_status != RDC_OK)) {
572 /*
573 * RPC reply failed, OR
574 * Last RPC for this IO operation, OR
575 * We are failing this IO operation.
576 *
577 * Do cleanup.
578 */
579 rdc_net_del_set(diskio.cd, dset);
580 } else {
581 rdc_net_put_set(diskio.cd, dset);
582 }
583 }
584
585 if (buffer)
586 kmem_free(buffer, resp.rr_bufsize);
587 if (vector) {
588 kmem_free(vector, vecsz);
589 RDC_DSMEMUSE(-vecsz);
590 }
591 }
592
593 /*
594 * r_net_write (Version 5)
595 * 0 reply indicates error
596 * >0 reply indicates a net handle index
597 * <0 reply indicates errno
598 * ret net handle index
599 * ret2 general error
600 * ret3 multi-hop errors (never returned)
601 */
602 static void
r_net_write5(SVCXPRT * xprt)603 r_net_write5(SVCXPRT *xprt)
604 {
605 rdc_k_info_t *krdc;
606 rdc_u_info_t *urdc;
607 struct net_data5 diskio;
608 rdc_net_dataset_t *dset;
609 rdc_net_dataitem_t *ditem;
610 int nocache;
611 int ret = 0;
612 int ret2 = 0;
613 int st;
614
615 krdc = NULL;
616 diskio.data.data_val = kmem_alloc(RDC_MAXDATA, KM_NOSLEEP);
617
618 if (!diskio.data.data_val) {
619 ret2 = ENOMEM;
620 goto out;
621 }
622 RDC_DSMEMUSE(RDC_MAXDATA);
623 st = SVC_GETARGS(xprt, xdr_net_data5, (char *)&diskio);
624 if (!st) {
625 ret2 = ENOMEM;
626 #ifdef DEBUG
627 cmn_err(CE_NOTE, "!r_net_write5:SVC_GETARGS failed: st %d", st);
628 #endif
629 goto out;
630 }
631 if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
632 ret2 = EPROTO;
633 #ifdef DEBUG
634 cmn_err(CE_NOTE, "!r_net_write6: EPROTO cd out or not enabled");
635 #endif
636 goto out;
637 }
638
639 nocache = (diskio.flag & RDC_RWRITE_FAIL) ? 0 : NSC_NOCACHE;
640 krdc = &rdc_k_info[diskio.cd];
641 urdc = &rdc_u_info[diskio.cd];
642
643 if (!IS_ENABLED(urdc) || IS_STATE(urdc, RDC_LOGGING)) {
644 ret2 = EPROTO;
645 #ifdef DEBUG
646 cmn_err(CE_NOTE, "!r_net_write6: cd logging / not enabled (%x)",
647 rdc_get_vflags(urdc));
648 #endif
649 krdc = NULL; /* so we don't try to unqueue kstat entry */
650 goto out;
651 }
652
653 if (krdc->io_kstats) {
654 mutex_enter(krdc->io_kstats->ks_lock);
655 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
656 mutex_exit(krdc->io_kstats->ks_lock);
657 }
658
659
660 /* -1 index says allocate a buffer */
661 if (diskio.idx < 0) {
662 dset = rdc_net_add_set(diskio.cd);
663 if (dset == NULL) {
664 #ifdef DEBUG
665 cmn_err(CE_NOTE, "!r_net_write5: "
666 "failed to add dataset");
667 #endif
668 ret2 = EIO;
669 goto out;
670 } else {
671 ret = dset->id;
672 dset->pos = diskio.pos;
673 dset->fbalen = diskio.len;
674 diskio.idx = ret;
675 }
676 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
677 if (ditem == NULL) {
678 ret2 = ENOMEM;
679 goto out;
680 }
681 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
682 /*
683 * If this is a single transfer, then we don't
684 * need to allocate any memory for the data,
685 * just point the ditem data pointer to the
686 * existing buffer.
687 */
688 ditem->next = NULL;
689 if (diskio.endoblk) {
690 ditem->dptr = diskio.data.data_val;
691 /*
692 * So we don't free it twice.
693 */
694 diskio.data.data_val = NULL;
695 ditem->len = diskio.data.data_len;
696 ditem->mlen = RDC_MAXDATA;
697 } else {
698 /*
699 * Allocate the memory for the complete
700 * transfer.
701 */
702 ditem->dptr = kmem_alloc(FBA_SIZE(diskio.len),
703 KM_NOSLEEP);
704 if (ditem->dptr == NULL) {
705 ret2 = ENOMEM;
706 goto out;
707 }
708 RDC_DSMEMUSE(FBA_SIZE(diskio.len));
709 ditem->len = FBA_SIZE(diskio.len);
710 ditem->mlen = ditem->len;
711
712 /*
713 * Copy the data to the new buffer.
714 */
715 ASSERT(diskio.data.data_len == FBA_SIZE(diskio.nfba));
716 bcopy(diskio.data.data_val, ditem->dptr,
717 diskio.data.data_len);
718 /*
719 * free the old data buffer.
720 */
721 kmem_free(diskio.data.data_val, RDC_MAXDATA);
722 RDC_DSMEMUSE(-RDC_MAXDATA);
723 diskio.data.data_val = NULL;
724 }
725 dset->head = ditem;
726 dset->tail = ditem;
727 dset->nitems++;
728 } else {
729 ret = diskio.idx;
730 dset = rdc_net_get_set(diskio.cd, diskio.idx);
731 if (dset == NULL) {
732 ret2 = EPROTO;
733 #ifdef DEBUG
734 cmn_err(CE_NOTE,
735 "!r_net_write5: net_get_set failed cd %d idx %d",
736 diskio.cd, diskio.idx);
737 #endif
738 goto out;
739 }
740 /*
741 * We have to copy the data from the rpc buffer
742 * to the data in ditem.
743 */
744 ditem = dset->head;
745 bcopy(diskio.data.data_val, (char *)ditem->dptr +
746 FBA_SIZE(diskio.sfba - diskio.pos), diskio.data.data_len);
747
748 kmem_free(diskio.data.data_val, RDC_MAXDATA);
749 RDC_DSMEMUSE(-RDC_MAXDATA);
750 diskio.data.data_val = NULL;
751 }
752 ASSERT(dset);
753
754 if (diskio.endoblk) {
755 ret2 = rdc_writemaxfba(krdc, urdc, dset, diskio.seq, nocache);
756 rdc_net_del_set(diskio.cd, dset);
757 dset = NULL;
758 }
759 out:
760 if (!RDC_SUCCESS(ret2)) {
761 if (ret2 > 0)
762 ret2 = -ret2;
763 DTRACE_PROBE1(rdc_svcwrite5_err_ret2, int, ret2);
764 st = svc_sendreply(xprt, xdr_int, (char *)&ret2);
765 } else
766 st = svc_sendreply(xprt, xdr_int, (char *)&ret);
767
768 if (krdc && krdc->io_kstats && ret2 != ENOMEM) {
769 mutex_enter(krdc->io_kstats->ks_lock);
770 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
771 mutex_exit(krdc->io_kstats->ks_lock);
772 }
773 /*
774 * On Error we must cleanup.
775 * If we have a handle, free it.
776 * If we have a network handle, free it.
777 */
778 if (!st || !RDC_SUCCESS(ret2)) {
779 #ifdef DEBUG
780 cmn_err(CE_WARN, "!r_net_write5 error case? st %x ret %d",
781 st, ret2);
782 #endif
783 if (dset) {
784 rdc_net_del_set(diskio.cd, dset);
785 }
786
787 } else {
788 if (dset) {
789 rdc_net_put_set(diskio.cd, dset);
790 }
791 }
792 if (diskio.data.data_val) {
793 kmem_free(diskio.data.data_val, RDC_MAXDATA);
794 RDC_DSMEMUSE(-RDC_MAXDATA);
795 }
796 }
797
798 /*
799 * r_net_write (Version 6)
800 * index 0 = error, or net handle index.
801 * result = 0 , ok.
802 * result = 1, pending write.
803 * result < 0 error, and is the -errno.
804 * ret net handle index.
805 * ret2 general error.
806 */
807 static void
r_net_write6(SVCXPRT * xprt)808 r_net_write6(SVCXPRT *xprt)
809 {
810 rdc_k_info_t *krdc;
811 rdc_u_info_t *urdc;
812 rdc_group_t *group;
813 struct net_data6 diskio;
814 struct netwriteres netret;
815 rdc_net_dataset_t *dset;
816 rdc_net_dataitem_t *ditem;
817 int ret = 0;
818 int ret2 = 0;
819 int st;
820 int nocache;
821
822 netret.vecdata.vecdata_val = NULL;
823 netret.vecdata.vecdata_len = 0;
824 dset = NULL;
825 krdc = NULL;
826 diskio.data.data_val = kmem_alloc(RDC_MAXDATA, KM_NOSLEEP);
827
828 if (!diskio.data.data_val) {
829 ret2 = ENOMEM;
830 goto out;
831 }
832 RDC_DSMEMUSE(RDC_MAXDATA);
833 st = SVC_GETARGS(xprt, xdr_net_data6, (char *)&diskio);
834 if (!st) {
835 ret2 = ENOMEM;
836 #ifdef DEBUG
837 cmn_err(CE_NOTE,
838 "!r_net_write6:SVC_GETARGS failed: st %d", st);
839 #endif
840 goto out;
841 }
842
843 if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
844 ret2 = EPROTO;
845 #ifdef DEBUG
846 cmn_err(CE_NOTE, "!r_net_write6: EPROTO cd out or not enabled");
847 #endif
848 goto out;
849 }
850
851 nocache = (diskio.flag & RDC_RWRITE_FAIL) ? 0 : NSC_NOCACHE;
852 netret.seq = diskio.seq;
853
854 krdc = &rdc_k_info[diskio.cd];
855 urdc = &rdc_u_info[diskio.cd];
856
857 if (!IS_ENABLED(urdc) || IS_STATE(urdc, RDC_LOGGING)) {
858 ret2 = EPROTO;
859 #ifdef DEBUG
860 cmn_err(CE_NOTE,
861 "!r_net_write6: cd logging or not enabled (%x)",
862 rdc_get_vflags(urdc));
863 #endif
864 krdc = NULL; /* so we don't try to unqueue kstat entry */
865 goto out;
866 }
867
868 group = krdc->group;
869 if (group == NULL) {
870 ret2 = EIO;
871 #ifdef DEBUG
872 cmn_err(CE_NOTE,
873 "!r_net_write6: No group structure for set %s:%s",
874 urdc->secondary.intf, urdc->secondary.file);
875 #endif
876 krdc = NULL; /* so we don't try to unqueue kstat entry */
877 goto out;
878 }
879
880 #ifdef DEBUG
881 if (rdc_netwrite6) {
882 cmn_err(CE_NOTE,
883 "!r_net_write6: idx %d seq %u current seq %u pos %llu "
884 "len %d sfba %llu nfba %d endoblk %d",
885 diskio.idx, diskio.seq, group->seq,
886 (unsigned long long)diskio.pos, diskio.len,
887 (unsigned long long)diskio.sfba, diskio.nfba,
888 diskio.endoblk);
889 }
890 #endif
891
892 if (krdc->io_kstats) {
893 mutex_enter(krdc->io_kstats->ks_lock);
894 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
895 mutex_exit(krdc->io_kstats->ks_lock);
896 }
897
898 /* -1 index says allocate a net dataset */
899 if (diskio.idx < 0) {
900 dset = rdc_net_add_set(diskio.cd);
901 if (dset == NULL) {
902 #ifdef DEBUG
903 cmn_err(CE_NOTE,
904 "!r_net_write6: failed to add dataset");
905 #endif
906 ret2 = EIO;
907 goto out;
908 } else {
909 ret = dset->id;
910 dset->pos = (nsc_off_t)diskio.pos; /* 64bit! */
911 dset->fbalen = diskio.len;
912 diskio.idx = ret;
913 }
914 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
915 if (ditem == NULL) {
916 ret2 = ENOMEM;
917 goto out;
918 }
919 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
920 /*
921 * If this is a single transfer, then we don't
922 * need to allocate any memory for the data,
923 * just point the ditem data pointer to the
924 * existing buffer.
925 */
926 ditem->next = NULL;
927 if (diskio.endoblk) {
928 ditem->dptr = diskio.data.data_val;
929 /*
930 * So we don't free it twice.
931 */
932 diskio.data.data_val = NULL;
933 ditem->len = diskio.data.data_len;
934 ditem->mlen = RDC_MAXDATA;
935 } else {
936 /*
937 * Allocate the memory for the complete
938 * transfer.
939 */
940 ditem->dptr = kmem_alloc(FBA_SIZE(diskio.len),
941 KM_NOSLEEP);
942 if (ditem->dptr == NULL) {
943 ret2 = ENOMEM;
944 goto out;
945 }
946 RDC_DSMEMUSE(FBA_SIZE(diskio.len));
947 ditem->len = FBA_SIZE(diskio.len);
948 ditem->mlen = ditem->len;
949
950 /*
951 * Copy the data to the new buffer.
952 */
953 ASSERT(diskio.data.data_len == FBA_SIZE(diskio.nfba));
954 bcopy(diskio.data.data_val, ditem->dptr,
955 diskio.data.data_len);
956 /*
957 * free the old data buffer.
958 */
959 kmem_free(diskio.data.data_val, RDC_MAXDATA);
960 RDC_DSMEMUSE(-RDC_MAXDATA);
961 diskio.data.data_val = NULL;
962 }
963 dset->head = ditem;
964 dset->tail = ditem;
965 dset->nitems++;
966 } else {
967 ret = diskio.idx;
968 dset = rdc_net_get_set(diskio.cd, diskio.idx);
969 if (dset == NULL) {
970 ret2 = EPROTO;
971 #ifdef DEBUG
972 cmn_err(CE_NOTE,
973 "!r_net_write6: net_get_set failed cd %d idx %d "
974 "packet sequence %u expected seq %u",
975 diskio.cd, diskio.idx, diskio.seq, group->seq);
976 #endif
977 goto out;
978 }
979 /*
980 * We have to copy the data from the rpc buffer
981 * to the data in ditem.
982 */
983 ditem = dset->head;
984 bcopy(diskio.data.data_val, (char *)ditem->dptr +
985 FBA_SIZE(diskio.sfba - diskio.pos), diskio.data.data_len);
986
987 kmem_free(diskio.data.data_val, RDC_MAXDATA);
988 RDC_DSMEMUSE(-RDC_MAXDATA);
989 diskio.data.data_val = NULL;
990 }
991 ASSERT(dset);
992
993 if (diskio.endoblk) {
994 #ifdef DEBUG
995 if (diskio.seq == (RDC_NEWSEQ + 1)) {
996 rdc_stallzero(2);
997 }
998 #endif
999 if (diskio.seq == RDC_NEWSEQ) {
1000 /*
1001 * magic marker, start of sequence.
1002 */
1003 mutex_enter(&group->ra_queue.net_qlock);
1004 /*
1005 * see if some threads are stuck.
1006 */
1007 if (group->sleepq) {
1008 rdc_sleepqdiscard(group);
1009 }
1010 group->seqack = RDC_NEWSEQ;
1011 mutex_exit(&group->ra_queue.net_qlock);
1012 }
1013
1014 if ((diskio.seq != RDC_NOSEQ) && (diskio.seq != RDC_NEWSEQ)) {
1015 /*
1016 * see if we are allowed through here to
1017 * do the write, or if we have to q the
1018 * request and send back a pending reply.
1019 */
1020 mutex_enter(&group->ra_queue.net_qlock);
1021 if (diskio.seq != group->seq) {
1022 rdc_sleepq_t *sq;
1023 int maxseq;
1024
1025 /*
1026 * Check that we have room.
1027 */
1028 maxseq = group->seqack + RDC_MAXPENDQ + 1;
1029 if (maxseq < group->seqack) {
1030 /*
1031 * skip magic values.
1032 */
1033 maxseq += RDC_NEWSEQ + 1;
1034 }
1035 if (!RDC_INFRONT(diskio.seq, maxseq)) {
1036 #ifdef DEBUG
1037 cmn_err(CE_WARN, "!net_write6: Queue "
1038 "size %d exceeded seqack %u "
1039 "this seq %u maxseq %u seq %u",
1040 RDC_MAXPENDQ, group->seqack,
1041 diskio.seq, maxseq, group->seq);
1042 #endif
1043 DTRACE_PROBE2(qsize_exceeded, int, diskio.seq,
1044 int, maxseq);
1045 if (!(rdc_get_vflags(urdc) &
1046 RDC_VOL_FAILED)) {
1047 rdc_many_enter(krdc);
1048 rdc_set_flags(urdc,
1049 RDC_VOL_FAILED);
1050 rdc_many_exit(krdc);
1051 rdc_write_state(urdc);
1052 }
1053 ret2 = EIO;
1054 rdc_sleepqdiscard(group);
1055 group->seq = RDC_NEWSEQ;
1056 group->seqack = RDC_NEWSEQ;
1057 mutex_exit(&group->ra_queue.net_qlock);
1058 goto out;
1059 }
1060
1061 sq = rdc_newsleepq();
1062 sq->seq = diskio.seq;
1063 sq->sindex = diskio.cd;
1064 sq->pindex = diskio.local_cd;
1065 sq->idx = diskio.idx;
1066 sq->qpos = diskio.qpos;
1067 sq->nocache = nocache;
1068 if (rdc_sleepq(group, sq)) {
1069 ret2 = EIO;
1070 group->seq = RDC_NEWSEQ;
1071 group->seqack = RDC_NEWSEQ;
1072 rdc_sleepqdiscard(group);
1073 mutex_exit(&group->ra_queue.net_qlock);
1074 goto out;
1075 }
1076 rdc_net_put_set(diskio.cd, dset);
1077 dset = NULL;
1078 if (krdc->io_kstats) {
1079 mutex_enter(krdc->io_kstats->ks_lock);
1080 kstat_waitq_enter(KSTAT_IO_PTR(krdc->
1081 io_kstats));
1082 mutex_exit(krdc->io_kstats->ks_lock);
1083 }
1084 mutex_exit(&group->ra_queue.net_qlock);
1085 /*
1086 * pending state.
1087 */
1088 netret.result = 1;
1089 netret.index = diskio.idx;
1090 st = svc_sendreply(xprt, xdr_netwriteres,
1091 (char *)&netret);
1092 if (krdc->io_kstats && ret2 != ENOMEM) {
1093 mutex_enter(krdc->io_kstats->ks_lock);
1094 kstat_runq_exit(KSTAT_IO_PTR(
1095 krdc->io_kstats));
1096 mutex_exit(krdc->io_kstats->ks_lock);
1097 }
1098 return;
1099 }
1100 mutex_exit(&group->ra_queue.net_qlock);
1101 }
1102
1103 ret2 = rdc_writemaxfba(krdc, urdc, dset, diskio.seq, nocache);
1104 rdc_net_del_set(diskio.cd, dset);
1105 dset = NULL;
1106 #ifdef DEBUG
1107 if (!RDC_SUCCESS(ret2)) {
1108 cmn_err(CE_WARN, "!r_net_write6: writemaxfba failed %d",
1109 ret2);
1110 }
1111 #endif
1112 if (diskio.seq != RDC_NOSEQ) {
1113 mutex_enter(&group->ra_queue.net_qlock);
1114 group->seq = diskio.seq + 1;
1115 if (group->seq < diskio.seq)
1116 group->seq = RDC_NEWSEQ + 1;
1117 if (group->sleepq &&
1118 (group->sleepq->seq == group->seq)) {
1119 rdc_dopending(group, &netret);
1120 }
1121 group->seqack = group->seq;
1122 mutex_exit(&group->ra_queue.net_qlock);
1123 }
1124 }
1125 out:
1126 if (!RDC_SUCCESS(ret2)) {
1127 DTRACE_PROBE1(rdc_svcwrite6_err_ret2, int, ret2);
1128 netret.result = -ret2;
1129 } else {
1130 netret.result = 0;
1131 netret.index = ret;
1132 }
1133 st = svc_sendreply(xprt, xdr_netwriteres, (char *)&netret);
1134 if (netret.vecdata.vecdata_val) {
1135 kmem_free(netret.vecdata.vecdata_val,
1136 netret.vecdata.vecdata_len * sizeof (net_pendvec_t));
1137 }
1138 if (krdc && krdc->io_kstats && ret2 != ENOMEM) {
1139 mutex_enter(krdc->io_kstats->ks_lock);
1140 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
1141 mutex_exit(krdc->io_kstats->ks_lock);
1142 }
1143 /*
1144 * On Error we must cleanup.
1145 * If we have a handle, free it.
1146 * If we have a network handle, free it.
1147 * If we hold the main nsc buffer, free it.
1148 */
1149 if (!st || !RDC_SUCCESS(ret2)) {
1150 #ifdef DEBUG
1151 cmn_err(CE_WARN, "!r_net_write6 error st %x ret %d seq %u",
1152 st, ret2, diskio.seq);
1153 #endif
1154 if (dset) {
1155 rdc_net_del_set(diskio.cd, dset);
1156 }
1157 } else {
1158 if (dset) {
1159 rdc_net_put_set(diskio.cd, dset);
1160 }
1161 }
1162 if (diskio.data.data_val) {
1163 kmem_free(diskio.data.data_val, RDC_MAXDATA);
1164 RDC_DSMEMUSE(-RDC_MAXDATA);
1165 }
1166 }
1167
1168 /*
1169 * r_net_ping4
1170 *
1171 * received on the primary.
1172 */
1173 static void
r_net_ping4(SVCXPRT * xprt,struct svc_req * req)1174 r_net_ping4(SVCXPRT *xprt, struct svc_req *req)
1175 {
1176 struct rdc_ping6 ping;
1177 int e, ret = 0;
1178 rdc_if_t *ip;
1179
1180 e = SVC_GETARGS(xprt, xdr_rdc_ping6, (char *)&ping);
1181 if (e) {
1182 mutex_enter(&rdc_ping_lock);
1183
1184 /* update specified interface */
1185
1186 for (ip = rdc_if_top; ip; ip = ip->next) {
1187 if ((bcmp(ping.p_ifaddr, ip->ifaddr.buf,
1188 RDC_MAXADDR) == 0) &&
1189 (bcmp(ping.s_ifaddr, ip->r_ifaddr.buf,
1190 RDC_MAXADDR) == 0)) {
1191 ip->new_pulse++;
1192 ip->deadness = 1;
1193
1194 /* Update the rpc protocol version to use */
1195
1196 ip->rpc_version = req->rq_vers;
1197 break;
1198 }
1199 }
1200
1201 mutex_exit(&rdc_ping_lock);
1202 } else {
1203 svcerr_decode(xprt);
1204 #ifdef DEBUG
1205 cmn_err(CE_NOTE, "!SNDR: couldn't get ping4 arguments");
1206 #endif
1207 }
1208
1209 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1210 }
1211
1212 /*
1213 * r_net_ping7
1214 *
1215 * received on the primary.
1216 */
1217 static void
r_net_ping7(SVCXPRT * xprt,struct svc_req * req)1218 r_net_ping7(SVCXPRT *xprt, struct svc_req *req)
1219 {
1220 struct rdc_ping ping;
1221 int e, ret = 0;
1222 rdc_if_t *ip;
1223 unsigned short *sp;
1224
1225 bzero(&ping, sizeof (struct rdc_ping));
1226 e = SVC_GETARGS(xprt, xdr_rdc_ping, (char *)&ping);
1227 if (e) {
1228 sp = (unsigned short *)ping.p_ifaddr.buf;
1229 *sp = ntohs(*sp);
1230 sp = (unsigned short *)ping.s_ifaddr.buf;
1231 *sp = ntohs(*sp);
1232 mutex_enter(&rdc_ping_lock);
1233
1234 /* update specified interface */
1235
1236 for (ip = rdc_if_top; ip; ip = ip->next) {
1237 if ((bcmp(ping.p_ifaddr.buf, ip->ifaddr.buf,
1238 ping.p_ifaddr.len) == 0) &&
1239 (bcmp(ping.s_ifaddr.buf, ip->r_ifaddr.buf,
1240 ping.s_ifaddr.len) == 0)) {
1241 ip->new_pulse++;
1242 ip->deadness = 1;
1243
1244 /* Update the rpc protocol version to use */
1245
1246 ip->rpc_version = req->rq_vers;
1247 break;
1248 }
1249 }
1250
1251 mutex_exit(&rdc_ping_lock);
1252 } else {
1253 svcerr_decode(xprt);
1254 #ifdef DEBUG
1255 cmn_err(CE_NOTE, "!SNDR: couldn't get ping7 arguments");
1256 #endif
1257 }
1258
1259 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1260 }
1261
1262
1263 /*
1264 * r_net_bmap (v5)
1265 * WARNING acts as both client and server
1266 */
1267 static void
r_net_bmap(SVCXPRT * xprt)1268 r_net_bmap(SVCXPRT *xprt)
1269 {
1270 int e, ret = EINVAL;
1271 struct bmap b;
1272 rdc_k_info_t *krdc;
1273 rdc_u_info_t *urdc;
1274 struct bmap6 b6;
1275
1276
1277 e = SVC_GETARGS(xprt, xdr_bmap, (char *)&b);
1278 if (e == TRUE) {
1279 krdc = &rdc_k_info[b.cd];
1280 urdc = &rdc_u_info[b.cd];
1281 if (b.cd >= 0 && b.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1282 ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1283 krdc->rpc_version = RDC_VERSION5;
1284 b6.cd = b.cd;
1285 b6.dual = b.dual;
1286 b6.size = b.size;
1287 ret = RDC_SEND_BITMAP(&b6);
1288 }
1289 }
1290
1291 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1292 }
1293
1294 /*
1295 * r_net_bmap (v6)
1296 * WARNING acts as both client and server
1297 */
1298 static void
r_net_bmap6(SVCXPRT * xprt)1299 r_net_bmap6(SVCXPRT *xprt)
1300 {
1301 int e, ret = EINVAL;
1302 struct bmap6 b;
1303 rdc_k_info_t *krdc;
1304 rdc_u_info_t *urdc;
1305
1306 e = SVC_GETARGS(xprt, xdr_bmap6, (char *)&b);
1307 if (e == TRUE) {
1308 krdc = &rdc_k_info[b.cd];
1309 urdc = &rdc_u_info[b.cd];
1310 if (b.cd >= 0 && b.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1311 ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1312 krdc->rpc_version = RDC_VERSION6;
1313 ret = RDC_SEND_BITMAP(&b);
1314 }
1315 }
1316 /*
1317 * If the bitmap send has succeeded, clear it.
1318 */
1319 if (ret == 0) {
1320 #ifdef DEBUG
1321 cmn_err(CE_NOTE, "!Bitmap clear in r_net_bmap6");
1322 #endif
1323 RDC_ZERO_BITMAP(krdc);
1324 rdc_many_enter(krdc);
1325 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1326 rdc_many_exit(krdc);
1327 }
1328 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1329 }
1330
1331 /*
1332 * r_net_bdata
1333 */
1334 static void
r_net_bdata(SVCXPRT * xprt)1335 r_net_bdata(SVCXPRT *xprt)
1336 {
1337 struct net_bdata bd;
1338 struct net_bdata6 bd6;
1339 int e, ret = -1;
1340 rdc_k_info_t *krdc;
1341 rdc_u_info_t *urdc;
1342
1343 /*
1344 * We have to convert it to the internal form here,
1345 * net_data6, when we know that we will have to convert
1346 * it back to the v5 variant for transmission.
1347 */
1348
1349 bd.data.data_val = kmem_alloc(BMAP_BLKSIZE, KM_NOSLEEP);
1350 if (bd.data.data_val == NULL)
1351 goto out;
1352
1353 e = SVC_GETARGS(xprt, xdr_net_bdata, (char *)&bd);
1354 if (e == TRUE) {
1355 krdc = &rdc_k_info[bd.cd];
1356 urdc = &rdc_u_info[bd.cd];
1357 if (bd.cd >= 0 && bd.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1358 ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1359 bd6.cd = bd.cd;
1360 bd6.offset = bd.offset;
1361 bd6.size = bd.size;
1362 bd6.data.data_len = bd.data.data_len;
1363 bd6.data.data_val = bd.data.data_val;
1364 ret = RDC_OR_BITMAP(&bd6);
1365 }
1366 }
1367 kmem_free(bd.data.data_val, BMAP_BLKSIZE);
1368 out:
1369 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1370 }
1371
1372 /*
1373 * r_net_bdata v6
1374 */
1375 static void
r_net_bdata6(SVCXPRT * xprt)1376 r_net_bdata6(SVCXPRT *xprt)
1377 {
1378 struct net_bdata6 bd;
1379 int e, ret = -1;
1380 rdc_k_info_t *krdc;
1381 rdc_u_info_t *urdc;
1382
1383 /*
1384 * just allocate the bigger block, regardless of < V7
1385 * bd.size will dictate how much we lor into our bitmap
1386 * the other option would be write r_net_bdata7 that is identical
1387 * to this function, but a V7 alloc.
1388 */
1389 bd.data.data_val = kmem_alloc(BMAP_BLKSIZEV7, KM_NOSLEEP);
1390 if (bd.data.data_val == NULL)
1391 goto out;
1392
1393 e = SVC_GETARGS(xprt, xdr_net_bdata6, (char *)&bd);
1394 if (e == TRUE) {
1395 krdc = &rdc_k_info[bd.cd];
1396 urdc = &rdc_u_info[bd.cd];
1397 if (bd.cd >= 0 && bd.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1398 ((krdc->type_flag & RDC_DISABLEPEND) == 0))
1399 ret = RDC_OR_BITMAP(&bd);
1400 }
1401 /*
1402 * Write the merged bitmap.
1403 */
1404 if ((ret == 0) && bd.endoblk && (krdc->bitmap_write > 0)) {
1405 #ifdef DEBUG
1406 cmn_err(CE_NOTE, "!r_net_bdata6: Written bitmap for %s:%s",
1407 urdc->secondary.intf, urdc->secondary.file);
1408 #endif
1409 ret = rdc_write_bitmap(krdc);
1410 }
1411 kmem_free(bd.data.data_val, BMAP_BLKSIZEV7);
1412 out:
1413 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1414 }
1415
1416 /*
1417 * r_net_getsize (v5)
1418 */
1419 static void
r_net_getsize(SVCXPRT * xprt)1420 r_net_getsize(SVCXPRT *xprt)
1421 {
1422 int e, ret = -1, index;
1423 rdc_k_info_t *krdc;
1424
1425 e = SVC_GETARGS(xprt, xdr_int, (char *)&index);
1426 if (e) {
1427 krdc = &rdc_k_info[index];
1428 if (IS_VALID_INDEX(index) && ((krdc->type_flag &
1429 RDC_DISABLEPEND) == 0))
1430 ret = mirror_getsize(index);
1431 }
1432 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1433 }
1434
1435 /*
1436 * r_net_getsize (v6)
1437 */
1438 static void
r_net_getsize6(SVCXPRT * xprt)1439 r_net_getsize6(SVCXPRT *xprt)
1440 {
1441 int e, index;
1442 rdc_k_info_t *krdc;
1443 uint64_t ret;
1444
1445 /*
1446 * small change in semantics here, as we can't return
1447 * -1 over the wire anymore.
1448 */
1449 ret = 0;
1450
1451 e = SVC_GETARGS(xprt, xdr_int, (char *)&index);
1452 if (e) {
1453 krdc = &rdc_k_info[index];
1454 if (IS_VALID_INDEX(index) && ((krdc->type_flag &
1455 RDC_DISABLEPEND) == 0))
1456 ret = mirror_getsize(index);
1457 }
1458 (void) svc_sendreply(xprt, xdr_u_longlong_t, (char *)&ret);
1459 }
1460
1461
1462 /*
1463 * r_net_state4
1464 */
1465 static void
r_net_state4(SVCXPRT * xprt)1466 r_net_state4(SVCXPRT *xprt)
1467 {
1468 rdc_u_info_t *urdc;
1469 rdc_k_info_t *krdc;
1470 struct set_state4 state;
1471 rdc_set_t rdc_set;
1472 int e, index = -1;
1473 int options;
1474 int log = 0;
1475 int done = 0;
1476 int slave = 0;
1477 int rev_sync = 0;
1478
1479 e = SVC_GETARGS(xprt, xdr_set_state4, (char *)&state);
1480 if (e) {
1481 init_rdc_netbuf(&(rdc_set.primary.addr));
1482 init_rdc_netbuf(&(rdc_set.secondary.addr));
1483 bcopy(state.netaddr, rdc_set.primary.addr.buf,
1484 state.netaddrlen);
1485 bcopy(state.rnetaddr, rdc_set.secondary.addr.buf,
1486 state.rnetaddrlen);
1487 rdc_set.primary.addr.len = state.netaddrlen;
1488 rdc_set.secondary.addr.len = state.rnetaddrlen;
1489 (void) strncpy(rdc_set.primary.file, state.pfile,
1490 RDC_MAXNAMLEN);
1491 (void) strncpy(rdc_set.secondary.file, state.sfile,
1492 RDC_MAXNAMLEN);
1493 options = state.flag;
1494 index = rdc_lookup_byaddr(&rdc_set);
1495
1496 krdc = &rdc_k_info[index];
1497
1498 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
1499 #ifdef DEBUG
1500 cmn_err(CE_WARN,
1501 "!r_net_state: no index or disable pending");
1502 #endif
1503 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1504 return;
1505 }
1506
1507 urdc = &rdc_u_info[index];
1508
1509 if (!IS_ENABLED(urdc)) {
1510 index = -1;
1511 #ifdef DEBUG
1512 cmn_err(CE_WARN, "!r_net_state: set not enabled ");
1513 #endif
1514 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1515 return;
1516 }
1517
1518 if (krdc->lsrv == NULL) {
1519 cmn_err(CE_NOTE, "!r_net_state: no valid svp\n");
1520 index = -1;
1521 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1522 return;
1523 }
1524 if (!krdc || !krdc->group) {
1525 #ifdef DEBUG
1526 cmn_err(CE_NOTE,
1527 "!r_net_state: no valid krdc %p\n", (void*)krdc);
1528 #endif
1529 index = -1;
1530 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1531 return;
1532 }
1533
1534 mutex_enter(&rdc_conf_lock);
1535 if (krdc->type_flag & RDC_DISABLEPEND) {
1536 mutex_exit(&rdc_conf_lock);
1537 index = -1;
1538 #ifdef DEBUG
1539 cmn_err(CE_WARN, "!r_net_state: disable pending");
1540 #endif
1541 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1542 return;
1543 }
1544 set_busy(krdc);
1545 mutex_exit(&rdc_conf_lock);
1546
1547 rdc_group_enter(krdc);
1548
1549 if (rdc_get_vflags(urdc) & RDC_PRIMARY)
1550 krdc->intf = rdc_add_to_if(krdc->lsrv,
1551 &(urdc->primary.addr), &(urdc->secondary.addr), 1);
1552 else
1553 krdc->intf = rdc_add_to_if(krdc->lsrv,
1554 &(urdc->secondary.addr), &(urdc->primary.addr), 0);
1555
1556 if (options & CCIO_SLAVE) {
1557 /*
1558 * mark that the bitmap needs clearing.
1559 */
1560 rdc_many_enter(krdc);
1561 rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1562 rdc_many_exit(krdc);
1563
1564 /* Starting forward sync */
1565 if (urdc->volume_size == 0)
1566 rdc_get_details(krdc);
1567 if (urdc->volume_size == 0) {
1568 index = -1;
1569 goto out;
1570 }
1571 if (krdc->dcio_bitmap == NULL) {
1572 if (rdc_resume_bitmap(krdc) < 0) {
1573 index = -1;
1574 goto out;
1575 }
1576 }
1577 if (rdc_allow_sec_sync(urdc, CCIO_SLAVE) < 0) {
1578 index = -1;
1579 goto out;
1580 }
1581 rdc_dump_dsets(index);
1582 slave = 1;
1583 } else if (options & CCIO_RSYNC) {
1584 /*
1585 * mark that the bitmap needs clearing.
1586 */
1587 rdc_many_enter(krdc);
1588 rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1589 rdc_many_exit(krdc);
1590
1591 /* Starting reverse sync */
1592 if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED |
1593 RDC_VOL_FAILED | RDC_BMP_FAILED)) {
1594 index = -1;
1595 goto out;
1596 }
1597 if (rdc_allow_sec_sync(urdc, CCIO_RSYNC) < 0) {
1598 index = -1;
1599 goto out;
1600 }
1601 rdc_dump_dsets(index);
1602 rev_sync = 1;
1603 } else if (options & CCIO_DONE) {
1604 /* Sync completed OK */
1605 if (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)
1606 done = 1; /* forward sync complete */
1607 rdc_many_enter(krdc);
1608 rdc_clr_flags(urdc, RDC_SYNCING | RDC_SYNC_NEEDED);
1609 rdc_clr_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
1610 rdc_many_exit(krdc);
1611 rdc_write_state(urdc);
1612 if (rdc_get_vflags(urdc) & RDC_CLR_AFTERSYNC) {
1613 RDC_ZERO_BITMAP(krdc);
1614 rdc_many_enter(krdc);
1615 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1616 rdc_many_exit(krdc);
1617 }
1618 } else if (options & CCIO_ENABLELOG) {
1619 /* Sync aborted or logging started */
1620 if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
1621 rdc_clr_flags(urdc, RDC_SYNCING);
1622 rdc_many_enter(krdc);
1623 rdc_clr_mflags(urdc, RDC_SLAVE);
1624 rdc_many_exit(krdc);
1625 }
1626 log = 1;
1627 }
1628 out:
1629 rdc_group_exit(krdc);
1630 free_rdc_netbuf(&(rdc_set.primary.addr));
1631 free_rdc_netbuf(&(rdc_set.secondary.addr));
1632
1633 if (slave) {
1634 if (_rdc_sync_event_notify(RDC_SYNC_START,
1635 urdc->secondary.file, urdc->group_name) >= 0) {
1636 rdc_group_enter(krdc);
1637 rdc_clr_flags(urdc, RDC_LOGGING);
1638 rdc_many_enter(krdc);
1639 rdc_clr_flags(urdc, RDC_VOL_FAILED);
1640 rdc_set_flags(urdc,
1641 RDC_SYNCING | RDC_SYNC_NEEDED);
1642 rdc_set_mflags(urdc, RDC_SLAVE);
1643 rdc_many_exit(krdc);
1644 rdc_write_state(urdc);
1645 rdc_group_exit(krdc);
1646 } else {
1647 index = -1;
1648 }
1649 } else if (rev_sync) {
1650 /* Check to see if volume is mounted */
1651 if (_rdc_sync_event_notify(RDC_RSYNC_START,
1652 urdc->secondary.file, urdc->group_name) >= 0) {
1653 rdc_group_enter(krdc);
1654 rdc_clr_flags(urdc, RDC_LOGGING);
1655 rdc_set_flags(urdc, RDC_SYNCING);
1656 rdc_write_state(urdc);
1657 rdc_group_exit(krdc);
1658 } else {
1659 index = -1;
1660 }
1661 } else if (done) {
1662
1663 /*
1664 * special case...
1665 * if this set is in a group, then sndrsyncd will
1666 * make sure that all sets in the group are REP
1667 * before updating the config to "update", telling
1668 * sndrsyncd that it is ok to take anther snapshot
1669 * on a following sync. The important part about
1670 * the whole thing is that syncd needs kernel stats.
1671 * however, this thread must set the set busy to
1672 * avoid disables. since this is the only
1673 * sync_event_notify() that will cause a status
1674 * call back into the kernel, and we will not be
1675 * accessing the group structure, we have to wakeup now
1676 */
1677
1678 mutex_enter(&rdc_conf_lock);
1679 wakeup_busy(krdc);
1680 mutex_exit(&rdc_conf_lock);
1681
1682 (void) _rdc_sync_event_notify(RDC_SYNC_DONE,
1683 urdc->secondary.file, urdc->group_name);
1684 }
1685 }
1686
1687 if (!done) {
1688 mutex_enter(&rdc_conf_lock);
1689 wakeup_busy(krdc);
1690 mutex_exit(&rdc_conf_lock);
1691 }
1692
1693 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1694 if (log) {
1695 rdc_group_enter(krdc);
1696 rdc_group_log(krdc, RDC_NOFLUSH | RDC_OTHERREMOTE,
1697 "Sync aborted or logging started");
1698 rdc_group_exit(krdc);
1699 }
1700 }
1701
1702
1703 /*
1704 * r_net_state
1705 */
1706 static void
r_net_state(SVCXPRT * xprt)1707 r_net_state(SVCXPRT *xprt)
1708 {
1709 rdc_u_info_t *urdc;
1710 rdc_k_info_t *krdc;
1711 struct set_state state;
1712 rdc_set_t rdc_set;
1713 int e, index = -1;
1714 int options;
1715 int log = 0;
1716 int done = 0;
1717 int slave = 0;
1718 int rev_sync = 0;
1719 unsigned short *sp;
1720
1721 bzero(&state, sizeof (struct set_state));
1722 e = SVC_GETARGS(xprt, xdr_set_state, (char *)&state);
1723 if (e) {
1724 init_rdc_netbuf(&(rdc_set.primary.addr));
1725 init_rdc_netbuf(&(rdc_set.secondary.addr));
1726 sp = (unsigned short *)(state.netaddr.buf);
1727 *sp = ntohs(*sp);
1728 bcopy(state.netaddr.buf, rdc_set.primary.addr.buf,
1729 state.netaddrlen);
1730 sp = (unsigned short *)(state.rnetaddr.buf);
1731 *sp = ntohs(*sp);
1732 bcopy(state.rnetaddr.buf, rdc_set.secondary.addr.buf,
1733 state.rnetaddrlen);
1734 rdc_set.primary.addr.len = state.netaddrlen;
1735 rdc_set.secondary.addr.len = state.rnetaddrlen;
1736 (void) strncpy(rdc_set.primary.file, state.pfile,
1737 RDC_MAXNAMLEN);
1738 (void) strncpy(rdc_set.secondary.file, state.sfile,
1739 RDC_MAXNAMLEN);
1740 options = state.flag;
1741 index = rdc_lookup_byaddr(&rdc_set);
1742
1743 krdc = &rdc_k_info[index];
1744
1745 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
1746 #ifdef DEBUG
1747 cmn_err(CE_WARN,
1748 "!r_net_state: no index or disable pending");
1749 #endif
1750 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1751 return;
1752 }
1753
1754 urdc = &rdc_u_info[index];
1755
1756 if (!IS_ENABLED(urdc)) {
1757 index = -1;
1758 #ifdef DEBUG
1759 cmn_err(CE_WARN, "!r_net_state: set not enabled ");
1760 #endif
1761 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1762 return;
1763 }
1764
1765 if (krdc->lsrv == NULL) {
1766 cmn_err(CE_NOTE, "!r_net_state: no valid svp\n");
1767 index = -1;
1768 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1769 return;
1770 }
1771 if (!krdc || !krdc->group) {
1772 #ifdef DEBUG
1773 cmn_err(CE_NOTE,
1774 "!r_net_state: no valid krdc %p\n", (void*)krdc);
1775 #endif
1776 index = -1;
1777 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1778 return;
1779 }
1780
1781 mutex_enter(&rdc_conf_lock);
1782 if (krdc->type_flag & RDC_DISABLEPEND) {
1783 mutex_exit(&rdc_conf_lock);
1784 index = -1;
1785 #ifdef DEBUG
1786 cmn_err(CE_WARN, "!r_net_state: disable pending");
1787 #endif
1788 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1789 return;
1790 }
1791 set_busy(krdc);
1792 mutex_exit(&rdc_conf_lock);
1793
1794 rdc_group_enter(krdc);
1795
1796 if (rdc_get_vflags(urdc) & RDC_PRIMARY)
1797 krdc->intf = rdc_add_to_if(krdc->lsrv,
1798 &(urdc->primary.addr), &(urdc->secondary.addr), 1);
1799 else
1800 krdc->intf = rdc_add_to_if(krdc->lsrv,
1801 &(urdc->secondary.addr), &(urdc->primary.addr), 0);
1802
1803 if (options & CCIO_SLAVE) {
1804 /*
1805 * mark that the bitmap needs clearing.
1806 */
1807 rdc_many_enter(krdc);
1808 rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1809 rdc_many_exit(krdc);
1810
1811 /* Starting forward sync */
1812 if (urdc->volume_size == 0)
1813 rdc_get_details(krdc);
1814 if (urdc->volume_size == 0) {
1815 index = -1;
1816 goto out;
1817 }
1818 if (krdc->dcio_bitmap == NULL) {
1819 if (rdc_resume_bitmap(krdc) < 0) {
1820 index = -1;
1821 goto out;
1822 }
1823 }
1824 if (rdc_allow_sec_sync(urdc, CCIO_SLAVE) < 0) {
1825 index = -1;
1826 goto out;
1827 }
1828 rdc_dump_dsets(index);
1829 slave = 1;
1830 } else if (options & CCIO_RSYNC) {
1831 /*
1832 * mark that the bitmap needs clearing.
1833 */
1834 rdc_many_enter(krdc);
1835 rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1836 rdc_many_exit(krdc);
1837
1838 /* Starting reverse sync */
1839 if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED |
1840 RDC_VOL_FAILED | RDC_BMP_FAILED)) {
1841 index = -1;
1842 goto out;
1843 }
1844 if (rdc_allow_sec_sync(urdc, CCIO_RSYNC) < 0) {
1845 index = -1;
1846 goto out;
1847 }
1848 rdc_dump_dsets(index);
1849 rev_sync = 1;
1850 } else if (options & CCIO_DONE) {
1851 /* Sync completed OK */
1852 if (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)
1853 done = 1; /* forward sync complete */
1854 rdc_many_enter(krdc);
1855 rdc_clr_flags(urdc, RDC_SYNCING | RDC_SYNC_NEEDED);
1856 rdc_clr_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
1857 rdc_many_exit(krdc);
1858 rdc_write_state(urdc);
1859 if (rdc_get_vflags(urdc) & RDC_CLR_AFTERSYNC) {
1860 RDC_ZERO_BITMAP(krdc);
1861 rdc_many_enter(krdc);
1862 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1863 rdc_many_exit(krdc);
1864 }
1865 } else if (options & CCIO_ENABLELOG) {
1866 /* Sync aborted or logging started */
1867 if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
1868 rdc_clr_flags(urdc, RDC_SYNCING);
1869 rdc_many_enter(krdc);
1870 rdc_clr_mflags(urdc, RDC_SLAVE);
1871 rdc_many_exit(krdc);
1872 }
1873 log = 1;
1874 }
1875 out:
1876 rdc_group_exit(krdc);
1877 free_rdc_netbuf(&(rdc_set.primary.addr));
1878 free_rdc_netbuf(&(rdc_set.secondary.addr));
1879
1880 if (slave) {
1881 if (_rdc_sync_event_notify(RDC_SYNC_START,
1882 urdc->secondary.file, urdc->group_name) >= 0) {
1883 rdc_group_enter(krdc);
1884 rdc_clr_flags(urdc, RDC_LOGGING);
1885 rdc_many_enter(krdc);
1886 rdc_clr_flags(urdc, RDC_VOL_FAILED);
1887 rdc_set_flags(urdc,
1888 RDC_SYNCING | RDC_SYNC_NEEDED);
1889 rdc_set_mflags(urdc, RDC_SLAVE);
1890 rdc_many_exit(krdc);
1891 rdc_write_state(urdc);
1892 rdc_group_exit(krdc);
1893 } else {
1894 index = -1;
1895 }
1896 } else if (rev_sync) {
1897 /* Check to see if volume is mounted */
1898 if (_rdc_sync_event_notify(RDC_RSYNC_START,
1899 urdc->secondary.file, urdc->group_name) >= 0) {
1900 rdc_group_enter(krdc);
1901 rdc_clr_flags(urdc, RDC_LOGGING);
1902 rdc_set_flags(urdc, RDC_SYNCING);
1903 rdc_write_state(urdc);
1904 rdc_group_exit(krdc);
1905 } else {
1906 index = -1;
1907 }
1908 } else if (done) {
1909
1910 /*
1911 * special case...
1912 * if this set is in a group, then sndrsyncd will
1913 * make sure that all sets in the group are REP
1914 * before updating the config to "update", telling
1915 * sndrsyncd that it is ok to take anther snapshot
1916 * on a following sync. The important part about
1917 * the whole thing is that syncd needs kernel stats.
1918 * however, this thread must set the set busy to
1919 * avoid disables. since this is the only
1920 * sync_event_notify() that will cause a status
1921 * call back into the kernel, and we will not be
1922 * accessing the group structure, we have to wakeup now
1923 */
1924
1925 mutex_enter(&rdc_conf_lock);
1926 wakeup_busy(krdc);
1927 mutex_exit(&rdc_conf_lock);
1928
1929 (void) _rdc_sync_event_notify(RDC_SYNC_DONE,
1930 urdc->secondary.file, urdc->group_name);
1931 }
1932 }
1933
1934 if (!done) {
1935 mutex_enter(&rdc_conf_lock);
1936 wakeup_busy(krdc);
1937 mutex_exit(&rdc_conf_lock);
1938 }
1939
1940 (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1941 if (log) {
1942 rdc_group_enter(krdc);
1943 rdc_group_log(krdc, RDC_NOFLUSH | RDC_OTHERREMOTE,
1944 "Sync aborted or logging started");
1945 rdc_group_exit(krdc);
1946 }
1947 free_rdc_netbuf(&(state.netaddr));
1948 free_rdc_netbuf(&(state.rnetaddr));
1949 }
1950
1951 /*
1952 * r_net_getstate4
1953 * Return our state to client
1954 */
1955 static void
r_net_getstate4(SVCXPRT * xprt,struct svc_req * req)1956 r_net_getstate4(SVCXPRT *xprt, struct svc_req *req)
1957 {
1958 int e, ret = -1, index = -1;
1959 struct set_state4 state;
1960 rdc_u_info_t *urdc;
1961 rdc_set_t rdc_set;
1962
1963 bzero(&state, sizeof (struct set_state));
1964 e = SVC_GETARGS(xprt, xdr_set_state4, (char *)&state);
1965 if (e) {
1966 init_rdc_netbuf(&(rdc_set.primary.addr));
1967 init_rdc_netbuf(&(rdc_set.secondary.addr));
1968 bcopy(state.netaddr, rdc_set.primary.addr.buf,
1969 state.netaddrlen);
1970 bcopy(state.rnetaddr, rdc_set.secondary.addr.buf,
1971 state.rnetaddrlen);
1972 rdc_set.primary.addr.len = state.netaddrlen;
1973 rdc_set.secondary.addr.len = state.rnetaddrlen;
1974 (void) strncpy(rdc_set.primary.file, state.pfile,
1975 RDC_MAXNAMLEN);
1976 (void) strncpy(rdc_set.secondary.file, state.sfile,
1977 RDC_MAXNAMLEN);
1978 index = rdc_lookup_byaddr(&rdc_set);
1979 if (index >= 0) {
1980 urdc = &rdc_u_info[index];
1981
1982 ret = 0;
1983 if (rdc_get_vflags(urdc) & RDC_SYNCING)
1984 ret |= 4;
1985 if (rdc_get_vflags(urdc) & RDC_SLAVE)
1986 ret |= 2;
1987 if (rdc_get_vflags(urdc) & RDC_LOGGING)
1988 ret |= 1;
1989 rdc_set_if_vers(urdc, req->rq_vers);
1990 }
1991 free_rdc_netbuf(&(rdc_set.primary.addr));
1992 free_rdc_netbuf(&(rdc_set.secondary.addr));
1993 }
1994 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1995 }
1996
1997 /*
1998 * r_net_getstate7
1999 * Return our state to client
2000 */
2001 static void
r_net_getstate7(SVCXPRT * xprt,struct svc_req * req)2002 r_net_getstate7(SVCXPRT *xprt, struct svc_req *req)
2003 {
2004 int e, ret = -1, index = -1;
2005 struct set_state state;
2006 char pstr[RDC_MAXNAMLEN];
2007 char sstr[RDC_MAXNAMLEN];
2008 rdc_u_info_t *urdc;
2009 rdc_set_t rdc_set;
2010 unsigned short *sp;
2011
2012 bzero(&state, sizeof (struct set_state));
2013 state.pfile = pstr;
2014 state.sfile = sstr;
2015
2016 e = SVC_GETARGS(xprt, xdr_set_state, (char *)&state);
2017 if (e) {
2018 init_rdc_netbuf(&(rdc_set.primary.addr));
2019 init_rdc_netbuf(&(rdc_set.secondary.addr));
2020 sp = (unsigned short *)(state.netaddr.buf);
2021 *sp = ntohs(*sp);
2022 bcopy(state.netaddr.buf, rdc_set.primary.addr.buf,
2023 state.netaddrlen);
2024 sp = (unsigned short *)(state.rnetaddr.buf);
2025 *sp = ntohs(*sp);
2026 bcopy(state.rnetaddr.buf, rdc_set.secondary.addr.buf,
2027 state.rnetaddrlen);
2028 rdc_set.primary.addr.len = state.netaddrlen;
2029 rdc_set.secondary.addr.len = state.rnetaddrlen;
2030 /*
2031 * strncpy(rdc_set.primary.file, state.pfile, RDC_MAXNAMLEN);
2032 * strncpy(rdc_set.secondary.file, state.sfile, RDC_MAXNAMLEN);
2033 */
2034 bcopy(state.pfile, rdc_set.primary.file, RDC_MAXNAMLEN);
2035 bcopy(state.sfile, rdc_set.secondary.file, RDC_MAXNAMLEN);
2036 index = rdc_lookup_byaddr(&rdc_set);
2037 if (index >= 0) {
2038 urdc = &rdc_u_info[index];
2039
2040 ret = 0;
2041 if (rdc_get_vflags(urdc) & RDC_SYNCING)
2042 ret |= 4;
2043 if (rdc_get_vflags(urdc) & RDC_SLAVE)
2044 ret |= 2;
2045 if (rdc_get_vflags(urdc) & RDC_LOGGING)
2046 ret |= 1;
2047 rdc_set_if_vers(urdc, req->rq_vers);
2048 }
2049 free_rdc_netbuf(&(rdc_set.primary.addr));
2050 free_rdc_netbuf(&(rdc_set.secondary.addr));
2051 }
2052 (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
2053 }
2054
2055 /*
2056 * copy from/to a dset/vector combination to a network xdr buffer.
2057 */
2058 static int
rdc_dsetcopy(rdc_net_dataset_t * dset,nsc_vec_t * invec,nsc_off_t fba_pos,nsc_size_t fba_len,char * bdata,int blen,int dir)2059 rdc_dsetcopy(rdc_net_dataset_t *dset, nsc_vec_t *invec, nsc_off_t fba_pos,
2060 nsc_size_t fba_len, char *bdata, int blen, int dir)
2061 {
2062 nsc_vec_t *vec;
2063 uchar_t *sv_addr;
2064 uchar_t *data;
2065 int sv_len;
2066 nsc_off_t fpos;
2067 int len;
2068 int n;
2069
2070 if (!bdata || !dset || !invec) {
2071 #ifdef DEBUG
2072 cmn_err(CE_NOTE,
2073 "!rdc: dsetcopy: parameters failed bdata %p, dset %p "
2074 "invec %p", (void *)bdata, (void *)dset, (void *)invec);
2075 #endif
2076 return (FALSE);
2077 }
2078
2079 if (fba_len > MAX_RDC_FBAS ||
2080 (dir != COPY_IN && dir != COPY_OUT)) {
2081 #ifdef DEBUG
2082 cmn_err(CE_NOTE,
2083 "!rdc: dsetcopy: params failed fba_len %" NSC_SZFMT
2084 " fba_pos %" NSC_SZFMT ", dir %d", fba_len, fba_pos, dir);
2085 #endif
2086 return (FALSE);
2087 }
2088
2089 data = (uchar_t *)bdata; /* pointer to data in rpc */
2090 len = FBA_SIZE(fba_len); /* length of this transfer in bytes */
2091 fpos = fba_pos; /* start fba offset within buffer */
2092
2093 if (!len) {
2094 #ifdef DEBUG
2095 cmn_err(CE_NOTE, "!rdc: dsetcopy: len = 0");
2096 #endif
2097 return (FALSE);
2098 }
2099
2100 if (len != blen) {
2101 #ifdef DEBUG
2102 cmn_err(CE_NOTE, "!rdc:dsetcopy: len %d != blen %d", len, blen);
2103 #endif
2104 if (len > blen)
2105 len = blen;
2106 }
2107
2108 if (!RDC_DSET_LIMITS(dset, fba_pos, fba_len)) {
2109 /* should never happen */
2110 #ifdef DEBUG
2111 cmn_err(CE_NOTE,
2112 "!rdc: dsetcopy: handle limits pos %" NSC_SZFMT " (%"
2113 NSC_SZFMT ") len %" NSC_SZFMT " (%" NSC_SZFMT ")",
2114 fba_pos, dset->pos, fba_len, dset->fbalen);
2115 #endif
2116 return (FALSE); /* Don't overrun handle */
2117 }
2118
2119 vec = invec;
2120 fpos -= dset->pos;
2121
2122 /* find starting position in vector */
2123
2124 for (; fpos >= FBA_NUM(vec->sv_len); vec++)
2125 fpos -= FBA_NUM(vec->sv_len);
2126
2127 /*
2128 * Copy data
2129 */
2130
2131 sv_addr = vec->sv_addr + FBA_SIZE(fpos);
2132 sv_len = vec->sv_len - FBA_SIZE(fpos);
2133
2134 while (len) {
2135 if (!sv_addr) /* end of vec - how did this happen? */
2136 break;
2137
2138 n = min(sv_len, len);
2139
2140 if (dir == COPY_OUT)
2141 bcopy(data, sv_addr, (size_t)n);
2142 else
2143 bcopy(sv_addr, data, (size_t)n);
2144
2145 sv_len -= n;
2146 len -= n;
2147
2148 sv_addr += n;
2149 data += n;
2150
2151 if (sv_len <= 0) {
2152 /* goto next vector */
2153 vec++;
2154 sv_addr = vec->sv_addr;
2155 sv_len = vec->sv_len;
2156 }
2157 }
2158
2159 return (TRUE);
2160 }
2161
2162
2163 /*
2164 * rdc_start_server
2165 * Starts the kRPC server for rdc. Uses tli file descriptor passed down
2166 * from user level rdc server.
2167 *
2168 * Returns: 0 or errno (NOT unistat!).
2169 */
2170 int
rdc_start_server(struct rdc_svc_args * args,int mode)2171 rdc_start_server(struct rdc_svc_args *args, int mode)
2172 {
2173 file_t *fp;
2174 int ret;
2175 struct cred *cred;
2176 STRUCT_HANDLE(rdc_svc_args, rs);
2177
2178 STRUCT_SET_HANDLE(rs, mode, args);
2179 cred = ddi_get_cred();
2180 if (drv_priv(cred) != 0)
2181 return (EPERM);
2182 fp = getf(STRUCT_FGET(rs, fd));
2183 if (fp == NULL) {
2184 #ifdef DEBUG
2185 cmn_err(CE_WARN, "!rdc_start_server fd %d, fp %p", args->fd,
2186 (void *) fp);
2187 #endif
2188 return (EBADF);
2189 }
2190
2191 ret = rdcsrv_load(fp, rdc_srvtab, args, mode);
2192
2193 releasef(STRUCT_FGET(rs, fd));
2194 return (ret);
2195 }
2196
2197 /*
2198 * Allocate a new sleepq element.
2199 */
2200
2201 static rdc_sleepq_t *
rdc_newsleepq()2202 rdc_newsleepq()
2203 {
2204 rdc_sleepq_t *sq;
2205
2206 sq = kmem_alloc(sizeof (rdc_sleepq_t), KM_SLEEP);
2207 sq->next = NULL;
2208 #ifdef DEBUG
2209 mutex_enter(&rdc_cntlock);
2210 rdc_sleepcnt++;
2211 mutex_exit(&rdc_cntlock);
2212 #endif
2213 return (sq);
2214 }
2215
2216 /*
2217 * free memory/resources used by a sleepq element.
2218 */
2219 static void
rdc_delsleepq(rdc_sleepq_t * sq)2220 rdc_delsleepq(rdc_sleepq_t *sq)
2221 {
2222 rdc_net_dataset_t *dset;
2223
2224 if (sq->idx != -1) {
2225 dset = rdc_net_get_set(sq->sindex, sq->idx);
2226 if (dset) {
2227 rdc_net_del_set(sq->sindex, dset);
2228 }
2229 }
2230 kmem_free(sq, sizeof (rdc_sleepq_t));
2231 #ifdef DEBUG
2232 mutex_enter(&rdc_cntlock);
2233 rdc_sleepcnt--;
2234 mutex_exit(&rdc_cntlock);
2235 #endif
2236 }
2237
2238
2239 /*
2240 * skip down the sleep q and insert the sleep request
2241 * in ascending order. Return 0 on success, 1 on failure.
2242 */
2243 static int
rdc_sleepq(rdc_group_t * group,rdc_sleepq_t * sq)2244 rdc_sleepq(rdc_group_t *group, rdc_sleepq_t *sq)
2245 {
2246 rdc_sleepq_t *findsq;
2247
2248
2249 ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2250 if (group->sleepq == NULL) {
2251 group->sleepq = sq;
2252 } else {
2253 if (sq->seq == group->sleepq->seq) {
2254 cmn_err(CE_WARN, "!rdc_sleepq: Attempt to "
2255 "add duplicate request to queue %d", sq->seq);
2256 return (1);
2257 }
2258 if (RDC_INFRONT(sq->seq, group->sleepq->seq)) {
2259 sq->next = group->sleepq;
2260 group->sleepq = sq;
2261 } else {
2262 findsq = group->sleepq;
2263
2264 while (findsq->next) {
2265 if (sq->seq == findsq->next->seq) {
2266 cmn_err(CE_WARN, "!rdc_sleepq: "
2267 "Attempt to add duplicate "
2268 "request to queue %d", sq->seq);
2269 return (1);
2270 }
2271 if (RDC_INFRONT(sq->seq, findsq->next->seq)) {
2272 sq->next = findsq->next;
2273 findsq->next = sq;
2274 break;
2275 }
2276 findsq = findsq->next;
2277 }
2278 if (findsq->next == NULL)
2279 findsq->next = sq;
2280 }
2281 }
2282 return (0);
2283 }
2284
2285 /*
2286 * run down the sleep q and discard all the sleepq elements.
2287 */
2288 void
rdc_sleepqdiscard(rdc_group_t * group)2289 rdc_sleepqdiscard(rdc_group_t *group)
2290 {
2291 rdc_sleepq_t *sq;
2292 rdc_k_info_t *krdc;
2293
2294 ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2295 sq = group->sleepq;
2296
2297 while (sq) {
2298 rdc_sleepq_t *dsq;
2299
2300 dsq = sq;
2301 krdc = &rdc_k_info[dsq->sindex];
2302 if (krdc->io_kstats) {
2303 mutex_enter(krdc->io_kstats->ks_lock);
2304 kstat_waitq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2305 mutex_exit(krdc->io_kstats->ks_lock);
2306 }
2307 sq = sq->next;
2308 rdc_delsleepq(dsq);
2309 }
2310 group->sleepq = NULL;
2311 }
2312
2313 /*
2314 * split any write requests down to maxfba sized chunks.
2315 */
2316 /*ARGSUSED*/
2317 static int
rdc_writemaxfba(rdc_k_info_t * krdc,rdc_u_info_t * urdc,rdc_net_dataset_t * dset,uint_t seq,int nocache)2318 rdc_writemaxfba(rdc_k_info_t *krdc, rdc_u_info_t *urdc,
2319 rdc_net_dataset_t *dset, uint_t seq, int nocache)
2320 {
2321 int len;
2322 int ret;
2323 nsc_vec_t vector[2];
2324 nsc_buf_t *handle;
2325 int reserved;
2326 int rtype;
2327 nsc_size_t mfba;
2328 nsc_size_t wsize;
2329 nsc_off_t pos;
2330 int eintr_count;
2331 unsigned char *daddr;
2332 int kstat_len;
2333
2334 kstat_len = len = dset->fbalen;
2335 ret = 0;
2336 handle = NULL;
2337 reserved = 0;
2338 rtype = RDC_RAW;
2339
2340 ASSERT(dset->nitems == 1);
2341
2342 eintr_count = 0;
2343 do {
2344 ret = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
2345 if (ret == EINTR) {
2346 ++eintr_count;
2347 delay(2);
2348 }
2349 } while ((ret == EINTR) && (eintr_count < MAX_EINTR_COUNT));
2350 if (ret != 0) {
2351 #ifdef DEBUG
2352 cmn_err(CE_NOTE, "!rdc_writemaxfba: reserve devs "
2353 "failed %d", ret);
2354 #endif
2355 goto out;
2356
2357 }
2358 reserved = 1;
2359 /*
2360 * Perhaps we should cache mfba.
2361 */
2362 ret = nsc_maxfbas(RDC_U_FD(krdc), 0, &mfba);
2363 if (ret != 0) {
2364 #ifdef DEBUG
2365 cmn_err(CE_NOTE, "!rdc_writemaxfba: msc_maxfbas failed %d",
2366 ret);
2367 #endif
2368 goto out;
2369 }
2370
2371 ASSERT(urdc->volume_size != 0);
2372 if (dset->pos + len > urdc->volume_size) {
2373 /* should never happen */
2374 /*
2375 * also need to trim down the vector
2376 * sizes.
2377 */
2378 kstat_len = len = urdc->volume_size - dset->pos;
2379 dset->head->len -= FBA_SIZE(len);
2380 ASSERT(dset->head->len > 0);
2381 }
2382 daddr = dset->head->dptr;
2383 pos = dset->pos;
2384 vector[1].sv_addr = NULL;
2385 vector[1].sv_len = 0;
2386
2387 while (len > 0) {
2388 wsize = min((nsc_size_t)len, mfba);
2389 vector[0].sv_addr = daddr;
2390 vector[0].sv_len = FBA_SIZE(wsize);
2391
2392 if (handle) {
2393 (void) nsc_free_buf(handle);
2394 handle = NULL;
2395 }
2396 ret = nsc_alloc_buf(RDC_U_FD(krdc), pos, wsize,
2397 NSC_WRBUF|NSC_NODATA|nocache, &handle);
2398 if (ret != 0) {
2399 #ifdef DEBUG
2400 cmn_err(CE_NOTE, "!rdc_writemaxfba: "
2401 "nsc_alloc (d1) buf failed %d at "
2402 "pos %" NSC_SZFMT " len %" NSC_SZFMT,
2403 ret, pos, wsize);
2404 #endif
2405 goto out;
2406 }
2407 handle->sb_vec = &vector[0];
2408 ret = rdc_combywrite(krdc, handle);
2409 if (ret != 0) {
2410 #ifdef DEBUG
2411 cmn_err(CE_NOTE, "!rdc_writemaxfba: "
2412 "write failed (d1) %d offset %" NSC_SZFMT " "
2413 "length %" NSC_SZFMT, ret, pos, wsize);
2414 #endif
2415 goto out;
2416 }
2417 pos += wsize;
2418 len -= wsize;
2419 daddr += FBA_SIZE(wsize);
2420 }
2421 out:
2422 if (!RDC_SUCCESS(ret)) {
2423 if (!(rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
2424 ASSERT(!(rdc_get_vflags(urdc) &
2425 RDC_PRIMARY));
2426 rdc_many_enter(krdc);
2427 rdc_set_flags(urdc, RDC_SYNC_NEEDED);
2428 rdc_set_flags_log(urdc, RDC_VOL_FAILED,
2429 "svc write failed");
2430 rdc_many_exit(krdc);
2431 rdc_write_state(urdc);
2432 }
2433 } else {
2434 /* success */
2435 #ifdef DEBUG
2436 if (rdc_netwrite6) {
2437 /*
2438 * This string is used in the ZatoIchi MASNDR
2439 * tests, if you change this, update the test.
2440 */
2441 cmn_err(CE_NOTE, "!writemaxfba: Write "
2442 "sequence %u", seq);
2443 }
2444 #endif
2445 if (krdc->io_kstats) {
2446 KSTAT_IO_PTR(krdc->io_kstats)->writes++;
2447 KSTAT_IO_PTR(krdc->io_kstats)->nwritten +=
2448 FBA_SIZE(kstat_len);
2449 }
2450 }
2451 if (handle)
2452 (void) nsc_free_buf(handle);
2453 if (reserved)
2454 _rdc_rlse_devs(krdc, rtype);
2455 return (ret);
2456 }
2457
2458 static int
rdc_combywrite(rdc_k_info_t * krdc,nsc_buf_t * handle)2459 rdc_combywrite(rdc_k_info_t *krdc, nsc_buf_t *handle)
2460 {
2461 int rsync;
2462 int ret;
2463 int multiret;
2464
2465 rsync = -1;
2466 ret = 0;
2467 /* Handle multihop I/O even on error */
2468 if (IS_MULTI(krdc)) {
2469 rdc_k_info_t *ktmp;
2470 rdc_u_info_t *utmp;
2471
2472 rdc_many_enter(krdc);
2473 /*
2474 * Find a target primary that is enabled,
2475 * taking account of the fact that this
2476 * could be a multihop secondary
2477 * connected to a 1-to-many primary.
2478 */
2479 ktmp = krdc->multi_next;
2480 if (ktmp == NULL) {
2481 rdc_many_exit(krdc);
2482 goto multi_done;
2483 }
2484 utmp = &rdc_u_info[ktmp->index];
2485 do {
2486 if ((rdc_get_vflags(utmp) & RDC_PRIMARY)
2487 /* CSTYLED */
2488 && IS_ENABLED(utmp))
2489 break;
2490
2491 ktmp = ktmp->many_next;
2492 utmp = &rdc_u_info[ktmp->index];
2493 } while (ktmp != krdc->multi_next);
2494
2495 if (!(rdc_get_vflags(utmp) & RDC_PRIMARY) ||
2496 !IS_ENABLED(utmp)) {
2497 rdc_many_exit(krdc);
2498 goto multi_done;
2499 }
2500
2501 rdc_many_exit(krdc);
2502 rsync = (rdc_get_mflags(utmp) & RDC_SLAVE);
2503 if (!rsync) {
2504 /* normal case - local io first */
2505 ret = nsc_write(handle, handle->sb_pos, handle->sb_len,
2506 0);
2507 }
2508 multiret = _rdc_multi_write(handle, handle->sb_pos,
2509 handle->sb_len, 0, ktmp);
2510 if (!RDC_SUCCESS(multiret)) {
2511 #ifdef DEBUG
2512 cmn_err(CE_NOTE, "!combywrite: "
2513 "rdc_multi_write failed "
2514 "status %d ret %d",
2515 handle->sb_error, multiret);
2516 #endif
2517 if (!(rdc_get_vflags(utmp) &
2518 RDC_VOL_FAILED)) {
2519 rdc_many_enter(ktmp);
2520 if (rdc_get_vflags(utmp) &
2521 RDC_PRIMARY) {
2522 rdc_set_mflags(utmp,
2523 RDC_RSYNC_NEEDED);
2524 } else {
2525 rdc_set_flags(utmp,
2526 RDC_SYNC_NEEDED);
2527 }
2528 rdc_set_flags(utmp,
2529 RDC_VOL_FAILED);
2530 rdc_many_exit(ktmp);
2531 rdc_write_state(utmp);
2532 }
2533 }
2534 }
2535
2536 multi_done:
2537 if (rsync != 0) {
2538 /*
2539 * Either:
2540 * reverse sync in progress and so we
2541 * need to do the local io after the
2542 * (multihop) secondary io.
2543 * Or:
2544 * no multihop and this is the only io
2545 * required.
2546 */
2547 ret = nsc_write(handle, handle->sb_pos, handle->sb_len, 0);
2548
2549 }
2550 return (ret);
2551 }
2552 /*
2553 * set the pos and len values in the piggyback reply.
2554 */
2555 static void
rdc_setbitind(int * pendcnt,net_pendvec_t * pvec,rdc_net_dataset_t * dset,uint_t seq,int pindex,int qpos)2556 rdc_setbitind(int *pendcnt, net_pendvec_t *pvec, rdc_net_dataset_t *dset,
2557 uint_t seq, int pindex, int qpos)
2558 {
2559 int pc;
2560 ASSERT(*pendcnt < RDC_MAXPENDQ);
2561
2562 pc = *pendcnt;
2563 pvec[pc].seq = seq;
2564 pvec[pc].apos = dset->pos;
2565 pvec[pc].qpos = qpos;
2566 pvec[pc].alen = dset->fbalen;
2567 pvec[pc].pindex = pindex;
2568 *pendcnt = pc + 1;
2569 DTRACE_PROBE1(pvec_reply, int, seq);
2570 }
2571
2572 /*
2573 * Enters with group->ra_queue.net_qlock held.
2574 * Tries to construct the return status data for
2575 * all the pending requests in the sleepq that it can
2576 * satisfy.
2577 */
2578 static void
rdc_dopending(rdc_group_t * group,netwriteres * netretp)2579 rdc_dopending(rdc_group_t *group, netwriteres *netretp)
2580 {
2581 int pendcnt;
2582 net_pendvec_t *pendvec;
2583 rdc_sleepq_t *sq;
2584 int ret;
2585 int pendsz;
2586
2587 ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2588
2589 pendcnt = 0;
2590 pendsz = RDC_MAXPENDQ * sizeof (net_pendvec_t);
2591 pendvec = kmem_alloc(pendsz, KM_SLEEP);
2592
2593 /*
2594 * now look at the Q of pending tasks, attempt
2595 * to write any that have been waiting for
2596 * me to complete my write, and piggyback
2597 * their results in my reply, by setiing pendcnt
2598 * to the number of extra requests sucessfully
2599 * processed.
2600 */
2601 while (group->sleepq && group->sleepq->seq == group->seq) {
2602 rdc_k_info_t *krdc;
2603 rdc_u_info_t *urdc;
2604 struct rdc_net_dataset *dset;
2605
2606 sq = group->sleepq;
2607 group->sleepq = sq->next;
2608 mutex_exit(&group->ra_queue.net_qlock);
2609
2610 krdc = &rdc_k_info[sq->sindex];
2611 urdc = &rdc_u_info[sq->sindex];
2612 if (krdc->io_kstats) {
2613 mutex_enter(krdc->io_kstats->ks_lock);
2614 kstat_waitq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2615 mutex_exit(krdc->io_kstats->ks_lock);
2616 }
2617
2618 dset = rdc_net_get_set(sq->sindex, sq->idx);
2619 if (dset == NULL) {
2620 #ifdef DEBUG
2621 cmn_err(CE_NOTE, "!pending: %s:%s rdc_net_get_set "
2622 "failed", urdc->secondary.intf,
2623 urdc->secondary.file);
2624 #endif
2625 /*
2626 * as we failed to get the pointer, there
2627 * is no point expecting the cleanup
2628 * code in rdc_delsleepq() to get it
2629 * either.
2630 */
2631 sq->idx = -1;
2632 goto cleansq;
2633 }
2634 sq->idx = -1; /* marked as cleaned up */
2635
2636 ret = rdc_writemaxfba(krdc, urdc, dset, sq->seq, sq->nocache);
2637 if (RDC_SUCCESS(ret)) {
2638 rdc_setbitind(&pendcnt, pendvec, dset,
2639 sq->seq, sq->pindex, sq->qpos);
2640 } else {
2641 cmn_err(CE_WARN, "!dopending: Write of pending "
2642 "asynchronous task failed, with "
2643 "sequence number %u for SNDR set %s:%s",
2644 sq->seq, urdc->secondary.intf,
2645 urdc->secondary.file);
2646 }
2647 rdc_net_del_set(sq->sindex, dset);
2648 cleansq:
2649 mutex_enter(&group->ra_queue.net_qlock);
2650 group->seq = sq->seq + 1;
2651 if (group->seq < sq->seq)
2652 group->seq = RDC_NEWSEQ + 1;
2653 rdc_delsleepq(sq);
2654 }
2655 mutex_exit(&group->ra_queue.net_qlock);
2656 if (pendcnt) {
2657 int vecsz;
2658 #ifdef DEBUG
2659 if (rdc_netwrite6) {
2660 cmn_err(CE_NOTE, "!packing pend, count %d", pendcnt);
2661 }
2662 #endif
2663 vecsz = pendcnt * sizeof (net_pendvec_t);
2664 netretp->vecdata.vecdata_val =
2665 kmem_alloc(vecsz, KM_SLEEP);
2666 netretp->vecdata.vecdata_len = pendcnt;
2667 bcopy(pendvec, netretp->vecdata.vecdata_val, vecsz);
2668 }
2669 kmem_free(pendvec, pendsz);
2670 mutex_enter(&group->ra_queue.net_qlock);
2671 }
2672
2673 /*
2674 * Take the dset and allocate and fill in the vector.
2675 */
2676 static nsc_vec_t *
rdc_dset2vec(rdc_net_dataset_t * dset)2677 rdc_dset2vec(rdc_net_dataset_t *dset)
2678 {
2679 nsc_vec_t *vecret;
2680 int i;
2681 rdc_net_dataitem_t *ditem;
2682
2683 ASSERT(dset->nitems > 0);
2684 ASSERT(dset->head);
2685 ASSERT(dset->tail);
2686
2687 vecret = kmem_alloc((dset->nitems + 1) * sizeof (nsc_vec_t),
2688 KM_NOSLEEP);
2689 if (vecret == NULL) {
2690 return (NULL);
2691 }
2692 RDC_DSMEMUSE((dset->nitems + 1) * sizeof (nsc_vec_t));
2693 ditem = dset->head;
2694 for (i = 0; i < dset->nitems; i++) {
2695 ASSERT(ditem);
2696 vecret[i].sv_addr = ditem->dptr;
2697 vecret[i].sv_len = ditem->len;
2698 ditem = ditem->next;
2699 }
2700 /*
2701 * Null terminate.
2702 */
2703 vecret[i].sv_addr = NULL;
2704 vecret[i].sv_len = 0;
2705 /*
2706 * Check the list and count matches.
2707 */
2708 ASSERT(ditem == NULL);
2709 return (vecret);
2710 }
2711
2712 /*
2713 * Split the local read into maxfba sized chunks.
2714 * Returns 0 on an error, or a valid idx on success.
2715 */
2716 static int
rdc_readmaxfba(int cd,nsc_off_t pos,nsc_size_t fbalen,int nocache)2717 rdc_readmaxfba(int cd, nsc_off_t pos, nsc_size_t fbalen, int nocache)
2718 {
2719 int idx;
2720 rdc_k_info_t *krdc;
2721 rdc_u_info_t *urdc;
2722 rdc_net_dataset_t *dset;
2723 rdc_net_dataitem_t *ditem;
2724 int rtype;
2725 nsc_buf_t *handle;
2726 nsc_vec_t veclist[2];
2727 int ret;
2728 int reserved;
2729 nsc_size_t fbaleft;
2730 nsc_size_t mfba;
2731 nsc_off_t fba;
2732 nsc_off_t spos;
2733 int eintr_count;
2734
2735 handle = NULL;
2736 idx = 0; /* error status */
2737 dset = NULL;
2738 ditem = NULL;
2739 reserved = 0;
2740 ret = 0;
2741 mfba = 0;
2742
2743 rtype = RDC_RAW;
2744 krdc = &rdc_k_info[cd];
2745 urdc = &rdc_u_info[cd];
2746
2747 eintr_count = 0;
2748 do {
2749 ret = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
2750 if (ret == EINTR) {
2751 ++eintr_count;
2752 delay(2);
2753 }
2754 } while ((ret == EINTR) && (eintr_count < MAX_EINTR_COUNT));
2755 if (ret != 0) {
2756 #ifdef DEBUG
2757 cmn_err(CE_NOTE, "!readmaxfba: reserve failed on set %s:%s %d",
2758 urdc->secondary.intf, urdc->secondary.file,
2759 ret);
2760 #endif
2761 goto out;
2762 }
2763 reserved = 1;
2764 /*
2765 * create a dataset that we can hang all the buffers from.
2766 */
2767 dset = rdc_net_add_set(cd);
2768 if (dset == NULL) {
2769 #ifdef DEBUG
2770 cmn_err(CE_NOTE, "!readmaxfba: Unable to allocate dset on set "
2771 "%s:%s", urdc->secondary.intf, urdc->secondary.file);
2772 #endif
2773 goto out;
2774 }
2775 dset->pos = pos;
2776 dset->fbalen = fbalen;
2777 ret = nsc_maxfbas(RDC_U_FD(krdc), 0, &mfba);
2778 if (ret != 0) {
2779 #ifdef DEBUG
2780 cmn_err(CE_NOTE, "!readmaxfba: msc_maxfbas failed on set %s:%s "
2781 "%d", urdc->secondary.intf, urdc->secondary.file, ret);
2782 #endif
2783 goto out;
2784 }
2785 spos = pos;
2786 fbaleft = fbalen;
2787 veclist[1].sv_addr = NULL;
2788 veclist[1].sv_len = 0;
2789
2790 while (fbaleft > 0) {
2791 fba = min(mfba, fbaleft);
2792 if (handle) {
2793 (void) nsc_free_buf(handle);
2794 handle = NULL;
2795 }
2796 ret = nsc_alloc_buf(RDC_U_FD(krdc), spos, fba,
2797 nocache|NSC_NODATA, &handle);
2798 if (ret != 0) {
2799 #ifdef DEBUG
2800 cmn_err(CE_NOTE, "!readmaxfba: alloc failed on set"
2801 "%s:%s %d", urdc->secondary.intf,
2802 urdc->secondary.file, ret);
2803 #endif
2804 goto out;
2805 }
2806 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
2807 if (ditem == NULL) {
2808 goto out;
2809 }
2810 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
2811 ditem->len = FBA_SIZE(fba);
2812 ditem->mlen = ditem->len;
2813 ditem->dptr = kmem_alloc(ditem->len, KM_SLEEP);
2814 RDC_DSMEMUSE(ditem->len);
2815 ditem->next = NULL;
2816 /*
2817 * construct a vector list
2818 */
2819 veclist[0].sv_addr = ditem->dptr;
2820 veclist[0].sv_len = ditem->len;
2821 handle->sb_vec = veclist;
2822 ret = rdc_combyread(krdc, urdc, handle);
2823 if (ret != 0) {
2824 goto out;
2825 }
2826 /*
2827 * place on linked list.
2828 */
2829 dset->nitems++;
2830 if (dset->head == NULL) {
2831 dset->head = ditem;
2832 dset->tail = ditem;
2833 } else {
2834 dset->tail->next = ditem;
2835 dset->tail = ditem;
2836 }
2837 /*
2838 * now its linked, clear this so its not freed twice.
2839 */
2840 ditem = NULL;
2841 fbaleft -= fba;
2842 spos += fba;
2843 }
2844 /*
2845 * all the reads have worked, store the results.
2846 */
2847 idx = dset->id;
2848 rdc_net_put_set(cd, dset);
2849 dset = NULL;
2850 out:
2851 if (handle)
2852 (void) nsc_free_buf(handle);
2853 if (reserved)
2854 _rdc_rlse_devs(krdc, rtype);
2855 if (dset)
2856 rdc_net_del_set(cd, dset);
2857 if (ditem) {
2858 kmem_free(ditem->dptr, ditem->mlen);
2859 RDC_DSMEMUSE(-ditem->mlen);
2860 kmem_free(ditem, sizeof (*ditem));
2861 RDC_DSMEMUSE(-sizeof (*ditem));
2862 }
2863 return (idx);
2864 }
2865
2866
2867 /*
2868 * perform both a local read, and if multihop, a remote read.
2869 * return 0 on success, or errno on failure.
2870 */
2871 static int
rdc_combyread(rdc_k_info_t * krdc,rdc_u_info_t * urdc,nsc_buf_t * handle)2872 rdc_combyread(rdc_k_info_t *krdc, rdc_u_info_t *urdc, nsc_buf_t *handle)
2873 {
2874 int ret;
2875 rdc_k_info_t *ktmp;
2876 rdc_u_info_t *utmp;
2877
2878 /*
2879 * read it.
2880 */
2881 if (krdc->io_kstats) {
2882 mutex_enter(krdc->io_kstats->ks_lock);
2883 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
2884 mutex_exit(krdc->io_kstats->ks_lock);
2885 }
2886
2887 ret = nsc_read(handle, handle->sb_pos, handle->sb_len, NSC_READ);
2888
2889 if (krdc->io_kstats) {
2890 mutex_enter(krdc->io_kstats->ks_lock);
2891 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2892 mutex_exit(krdc->io_kstats->ks_lock);
2893 }
2894
2895 if (ret != 0) {
2896 #ifdef DEBUG
2897 cmn_err(CE_NOTE, "!combyread: read failed on set %s:%s %d",
2898 urdc->secondary.intf, urdc->secondary.file, ret);
2899 #endif
2900 if (!(rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
2901 rdc_many_enter(krdc);
2902 rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
2903 rdc_set_flags_log(urdc, RDC_VOL_FAILED,
2904 "comby read failed");
2905 rdc_many_exit(krdc);
2906 rdc_write_state(urdc);
2907 }
2908 goto out;
2909 }
2910 if (IS_MULTI(krdc) && (ktmp = krdc->multi_next) &&
2911 (utmp = &rdc_u_info[ktmp->index]) &&
2912 IS_ENABLED(utmp) &&
2913 (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED)) {
2914 ret = _rdc_remote_read(ktmp, handle, handle->sb_pos,
2915 handle->sb_len, NSC_READ);
2916 /*
2917 * Set NSC_MIXED so
2918 * that the cache will throw away this
2919 * buffer when we free it since we have
2920 * combined data from multiple sources
2921 * into a single buffer.
2922 * Currently we don't use the cache for
2923 * data volumes, so comment this out.
2924 * handle->sb_flag |= NSC_MIXED;
2925 */
2926 if (ret != 0) {
2927 #ifdef DEBUG
2928 cmn_err(CE_NOTE, "!combyread: remote read failed on "
2929 "set %s:%s %d", utmp->secondary.intf,
2930 utmp->secondary.file, ret);
2931 #endif
2932 goto out;
2933 }
2934 }
2935 if (krdc->io_kstats) {
2936 KSTAT_IO_PTR(krdc->io_kstats)->reads++;
2937 KSTAT_IO_PTR(krdc->io_kstats)->nread +=
2938 FBA_SIZE(handle->sb_len);
2939 }
2940 out:
2941 return (ret);
2942 }
2943
2944
2945 /*
2946 * remove and free all the collected dsets for this set.
2947 */
2948 void
rdc_dump_dsets(int index)2949 rdc_dump_dsets(int index)
2950 {
2951 rdc_k_info_t *krdc;
2952 rdc_net_dataset_t *dset;
2953
2954 krdc = &rdc_k_info[index];
2955 tloop:
2956 mutex_enter(&krdc->dc_sleep);
2957 while ((dset = krdc->net_dataset) != NULL) {
2958 if (dset->inuse) {
2959 /*
2960 * for the dset to be in use, the
2961 * service routine r_net_write6() must
2962 * be active with it. It will free
2963 * it eventually.
2964 */
2965 mutex_exit(&krdc->dc_sleep);
2966 delay(5);
2967 goto tloop;
2968 }
2969 /*
2970 * free it.
2971 */
2972 rdc_net_free_set(krdc, dset);
2973 }
2974 mutex_exit(&krdc->dc_sleep);
2975 }
2976
2977 #ifdef DEBUG
2978 void
rdc_stallzero(int flag)2979 rdc_stallzero(int flag)
2980 {
2981 static int init = 0;
2982 static kcondvar_t cv;
2983 static kmutex_t mu;
2984
2985 if (init == 0) {
2986 cv_init(&cv, NULL, CV_DRIVER, NULL);
2987 mutex_init(&mu, NULL, MUTEX_DRIVER, NULL);
2988 init = 1;
2989 }
2990
2991 mutex_enter(&mu);
2992 switch (flag) {
2993 case 0:
2994 rdc_stall0 = 0;
2995 cv_signal(&cv);
2996 break;
2997 case 1:
2998 rdc_stall0 = 1;
2999 break;
3000 case 2:
3001 while (rdc_stall0 == 1)
3002 cv_wait(&cv, &mu);
3003 break;
3004 default:
3005 cmn_err(CE_PANIC, "Bad flag value passed to rdc_stallzero");
3006 break;
3007 }
3008 mutex_exit(&mu);
3009 }
3010 #endif
3011
3012 /*
3013 * RDC protocol version 5
3014 */
3015 static rdc_disptab_t rdc_disptab5[] =
3016 {
3017 /* PROC Idempotent */
3018 { r_net_null, FALSE },
3019 { rdcsrv_noproc, FALSE },
3020 { r_net_getsize, FALSE },
3021 { rdcsrv_noproc, FALSE },
3022 { r_net_write5, TRUE },
3023 { r_net_read, FALSE },
3024 { rdcsrv_noproc, FALSE },
3025 { r_net_state4, FALSE },
3026 { r_net_ping4, FALSE },
3027 { r_net_bmap, FALSE },
3028 { r_net_bdata, FALSE },
3029 { rdcsrv_noproc, FALSE },
3030 { r_net_getstate4, FALSE }
3031 };
3032
3033 /*
3034 * RDC protocol version 6
3035 */
3036 static rdc_disptab_t rdc_disptab6[] =
3037 {
3038 /* PROC Idempotent */
3039 { r_net_null, FALSE },
3040 { rdcsrv_noproc, FALSE },
3041 { r_net_getsize6, FALSE },
3042 { rdcsrv_noproc, FALSE },
3043 { r_net_write6, TRUE },
3044 { r_net_read6, FALSE },
3045 { rdcsrv_noproc, FALSE },
3046 { r_net_state4, FALSE },
3047 { r_net_ping4, FALSE },
3048 { r_net_bmap6, FALSE },
3049 { r_net_bdata6, FALSE },
3050 { rdcsrv_noproc, FALSE },
3051 { r_net_getstate4, FALSE }
3052 };
3053
3054 /*
3055 * RDC protocol version 7
3056 */
3057 static rdc_disptab_t rdc_disptab7[] =
3058 {
3059 /* PROC Idempotent */
3060 { r_net_null, FALSE },
3061 { rdcsrv_noproc, FALSE },
3062 { r_net_getsize6, FALSE },
3063 { rdcsrv_noproc, FALSE },
3064 { r_net_write6, TRUE },
3065 { r_net_read6, FALSE },
3066 { rdcsrv_noproc, FALSE },
3067 { r_net_state, FALSE },
3068 { r_net_ping7, FALSE },
3069 { r_net_bmap6, FALSE },
3070 { r_net_bdata6, FALSE },
3071 { rdcsrv_noproc, FALSE },
3072 { r_net_getstate7, FALSE }
3073 };
3074
3075 static rdcsrv_t rdc_srvtab[] = {
3076 { rdc_disptab5, sizeof (rdc_disptab5) / sizeof (*rdc_disptab5) },
3077 { rdc_disptab6, sizeof (rdc_disptab6) / sizeof (*rdc_disptab6) },
3078 { rdc_disptab7, sizeof (rdc_disptab7) / sizeof (*rdc_disptab7) }
3079 };
3080