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 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/ksynch.h>
29 #include <sys/kmem.h>
30 #include <sys/errno.h>
31 #include <sys/cmn_err.h>
32 #include <sys/debug.h>
33 #include <sys/ddi.h>
34 #include <sys/nsc_thread.h>
35 #include <sys/sysmacros.h>
36 #include <sys/unistat/spcs_s.h>
37 #include <sys/unistat/spcs_errors.h>
38
39 #include <sys/unistat/spcs_s_k.h>
40 #include <sys/nsctl/nsctl.h>
41 #include "dsw.h"
42 #include "dsw_dev.h"
43 #include "../rdc/rdc_update.h"
44 #include <sys/nskernd.h>
45
46 #include <sys/sdt.h> /* dtrace is S10 or later */
47
48 #ifdef DS_DDICT
49 #include "../contract.h"
50 #endif
51
52 /*
53 * Instant Image
54 *
55 * This file contains the core implementation of II.
56 *
57 * II is implemented as a simple filter module that pushes itself between
58 * user (SV, STE, etc.) and SDBC or NET.
59 *
60 */
61
62
63 #define REMOTE_VOL(s, ip) (((s) && ((ip->bi_flags)&DSW_SHDEXPORT)) || \
64 (!(s)&&((ip->bi_flags)&DSW_SHDIMPORT)))
65
66 #define total_ref(ip) ((ip->bi_shdref + ip->bi_shdrref + ip->bi_bmpref) + \
67 (NSHADOWS(ip) ? 0 : ip->bi_mstref + ip->bi_mstrref))
68
69
70 #define II_TAIL_COPY(d, s, m, t) bcopy(&(s.m), &(d.m), \
71 sizeof (d) - (uintptr_t)&((t *)0)->m)
72 extern dev_info_t *ii_dip;
73
74 #define II_LINK_CLUSTER(ip, cluster) \
75 _ii_ll_add(ip, &_ii_cluster_mutex, &_ii_cluster_top, cluster, \
76 &ip->bi_cluster)
77 #define II_UNLINK_CLUSTER(ip) \
78 _ii_ll_remove(ip, &_ii_cluster_mutex, &_ii_cluster_top, &ip->bi_cluster)
79
80 #define II_LINK_GROUP(ip, group) \
81 _ii_ll_add(ip, &_ii_group_mutex, &_ii_group_top, group, &ip->bi_group)
82 #define II_UNLINK_GROUP(ip) \
83 _ii_ll_remove(ip, &_ii_group_mutex, &_ii_group_top, &ip->bi_group)
84
85 _ii_info_t *_ii_info_top;
86 _ii_info_t *_ii_mst_top = 0;
87 _ii_overflow_t *_ii_overflow_top;
88 _ii_lsthead_t *_ii_cluster_top;
89 _ii_lsthead_t *_ii_group_top;
90
91 int ii_debug; /* level of cmn_err noise */
92 int ii_bitmap; /* bitmap operations switch */
93 uint_t ii_header = 16; /* Undocumented tunable (with adb!), start */
94 /* of area cleared in volume when a dependent */
95 /* shadow is disabled. */
96 /* max # of chunks in copy loop before delay */
97 int ii_throttle_unit = MIN_THROTTLE_UNIT;
98 /* length of delay during update loop */
99 int ii_throttle_delay = MIN_THROTTLE_DELAY;
100 int ii_copy_direct = 1;
101 int ii_nconcopy = 10; /* default value when starting with no cache */
102 kmutex_t _ii_cluster_mutex;
103 kmutex_t _ii_group_mutex;
104
105 static int _ii_shutting_down = 0;
106 static nsc_io_t *_ii_io, *_ii_ior;
107 static nsc_mem_t *_ii_local_mem;
108 static nsc_def_t _ii_fd_def[], _ii_io_def[], _ii_ior_def[];
109 static kmutex_t _ii_info_mutex;
110 static kmutex_t _ii_overflow_mutex;
111 static kmutex_t _ii_config_mutex;
112 static _ii_bmp_ops_t alloc_buf_bmp, kmem_buf_bmp;
113 static nsc_svc_t *ii_volume_update; /* IIVolumeUpdate token */
114 static nsc_svc_t *ii_report_luns; /* IIReportLuns token */
115 static nsc_svc_t *ii_get_initiators; /* IIGetInitiators token */
116 static ksema_t _ii_concopy_sema;
117 static int _ii_concopy_init = 0;
118 static int _ii_instance = 0;
119
120 void _ii_deinit_dev();
121
122 static void _ii_info_free(_ii_info_t *ip);
123 static void _ii_info_freeshd(_ii_info_t *ip);
124 static void ii_sibling_free(_ii_info_t *ip);
125 ii_header_t *_ii_bm_header_get(_ii_info_t *ip, nsc_buf_t **tmp);
126 int _ii_bm_header_put(ii_header_t *hdr, _ii_info_t *ip,
127 nsc_buf_t *tmp);
128 static void _ii_bm_header_free(ii_header_t *hdr, _ii_info_t *ip,
129 nsc_buf_t *tmp);
130 static int _ii_copyvol(_ii_info_t *, int, int, spcs_s_info_t, int);
131 static void _ii_stopvol(_ii_info_t *ip);
132 static int _ii_stopcopy(_ii_info_t *ip);
133 static _ii_info_t *_ii_find_set(char *volume);
134 static _ii_info_t *_ii_find_vol(char *, int);
135 static _ii_overflow_t *_ii_find_overflow(char *volume);
136 static void _ii_ioctl_done(_ii_info_t *ip);
137 static void _ii_lock_chunk(_ii_info_t *ip, chunkid_t);
138 static void _ii_unlock_chunks(_ii_info_t *ip, chunkid_t, int);
139 void _ii_error(_ii_info_t *ip, int error_type);
140 static nsc_buf_t *_ii_alloc_handle(void (*d_cb)(), void (*r_cb)(),
141 void (*w_cb)(), ii_fd_t *bfd);
142 static int _ii_free_handle(ii_buf_t *h, ii_fd_t *bfd);
143 extern nsc_size_t ii_btsize(nsc_size_t);
144 extern int ii_tinit(_ii_info_t *);
145 extern chunkid_t ii_tsearch(_ii_info_t *, chunkid_t);
146 extern void ii_tdelete(_ii_info_t *, chunkid_t);
147 extern void ii_reclaim_overflow(_ii_info_t *);
148 static void ii_overflow_free(_ii_info_t *ip, int disable);
149 static int ii_overflow_attach(_ii_info_t *, char *, int);
150 int _ii_nsc_io(_ii_info_t *, int, nsc_fd_t *, int, nsc_off_t, unsigned char *,
151 nsc_size_t);
152 static nsc_path_t *_ii_register_path(char *path, int type, nsc_io_t *io);
153 static int _ii_unregister_path(nsc_path_t *sp, int flag, char *type);
154 static int _ii_reserve_begin(_ii_info_t *ip);
155 static int _ii_wait_for_it(_ii_info_t *ip);
156 static void _ii_reserve_end(_ii_info_t *ip);
157 static kstat_t *_ii_overflow_kstat_create(_ii_info_t *ip, _ii_overflow_t *op);
158 static int _ii_ll_add(_ii_info_t *, kmutex_t *, _ii_lsthead_t **, char *,
159 char **);
160 static int _ii_ll_remove(_ii_info_t *, kmutex_t *, _ii_lsthead_t **, char **);
161 #define _ii_unlock_chunk(ip, chunk) _ii_unlock_chunks(ip, chunk, 1)
162 extern const int dsw_major_rev;
163 extern const int dsw_minor_rev;
164 extern const int dsw_micro_rev;
165 extern const int dsw_baseline_rev;
166
167 /*
168 * These constants are used by ii_overflow_free() to indicate how the
169 * reclamation should take place.
170 * NO_RECLAIM: just detach the overflow from the set; do not
171 * attempt to reclaim chunks, do not decrement the
172 * used-by count
173 * RECLAIM: reclaim all chunks before decrementing the used-by count
174 * INIT_OVR: decrement the used-by count only; do not reclaim chunks
175 */
176
177 #define NO_RECLAIM 0
178 #define RECLAIM 1
179 #define INIT_OVR 2
180
181 struct copy_args { /* arguments passed to copy process */
182 _ii_info_t *ip;
183 int flag;
184 int rtype;
185 int wait;
186 spcs_s_info_t kstatus;
187 int rc;
188 };
189
190 /* set-specific kstats info */
191 ii_kstat_set_t ii_kstat_set = {
192 { DSW_SKSTAT_SIZE, KSTAT_DATA_ULONG },
193 { DSW_SKSTAT_MTIME, KSTAT_DATA_ULONG },
194 { DSW_SKSTAT_FLAGS, KSTAT_DATA_ULONG },
195 { DSW_SKSTAT_THROTTLE_UNIT, KSTAT_DATA_ULONG },
196 { DSW_SKSTAT_THROTTLE_DELAY, KSTAT_DATA_ULONG },
197 { DSW_SKSTAT_SHDCHKS, KSTAT_DATA_ULONG },
198 { DSW_SKSTAT_SHDCHKUSED, KSTAT_DATA_ULONG },
199 { DSW_SKSTAT_SHDBITS, KSTAT_DATA_ULONG },
200 { DSW_SKSTAT_COPYBITS, KSTAT_DATA_ULONG },
201 { DSW_SKSTAT_MSTA, KSTAT_DATA_CHAR },
202 { DSW_SKSTAT_MSTB, KSTAT_DATA_CHAR },
203 { DSW_SKSTAT_MSTC, KSTAT_DATA_CHAR },
204 { DSW_SKSTAT_MSTD, KSTAT_DATA_CHAR },
205 { DSW_SKSTAT_SETA, KSTAT_DATA_CHAR },
206 { DSW_SKSTAT_SETB, KSTAT_DATA_CHAR },
207 { DSW_SKSTAT_SETC, KSTAT_DATA_CHAR },
208 { DSW_SKSTAT_SETD, KSTAT_DATA_CHAR },
209 { DSW_SKSTAT_BMPA, KSTAT_DATA_CHAR },
210 { DSW_SKSTAT_BMPB, KSTAT_DATA_CHAR },
211 { DSW_SKSTAT_BMPC, KSTAT_DATA_CHAR },
212 { DSW_SKSTAT_BMPD, KSTAT_DATA_CHAR },
213 { DSW_SKSTAT_OVRA, KSTAT_DATA_CHAR },
214 { DSW_SKSTAT_OVRB, KSTAT_DATA_CHAR },
215 { DSW_SKSTAT_OVRC, KSTAT_DATA_CHAR },
216 { DSW_SKSTAT_OVRD, KSTAT_DATA_CHAR },
217 { DSW_SKSTAT_MSTIO, KSTAT_DATA_CHAR },
218 { DSW_SKSTAT_SHDIO, KSTAT_DATA_CHAR },
219 { DSW_SKSTAT_BMPIO, KSTAT_DATA_CHAR },
220 { DSW_SKSTAT_OVRIO, KSTAT_DATA_CHAR },
221 };
222
223 /*
224 * _ii_init_dev
225 * Initialise the shadow driver
226 *
227 */
228
229 int
_ii_init_dev()230 _ii_init_dev()
231 {
232 _ii_io = nsc_register_io("ii", NSC_II_ID|NSC_REFCNT|NSC_FILTER,
233 _ii_io_def);
234 if (_ii_io == NULL)
235 cmn_err(CE_WARN, "!ii: nsc_register_io failed.");
236
237 _ii_ior = nsc_register_io("ii-raw", NSC_IIR_ID|NSC_REFCNT|NSC_FILTER,
238 _ii_ior_def);
239 if (_ii_ior == NULL)
240 cmn_err(CE_WARN, "!ii: nsc_register_io r failed.");
241
242 _ii_local_mem = nsc_register_mem("ii:kmem", NSC_MEM_LOCAL, 0);
243 if (_ii_local_mem == NULL)
244 cmn_err(CE_WARN, "!ii: nsc_register_mem failed.");
245
246
247 if (!_ii_io || !_ii_ior || !_ii_local_mem) {
248 _ii_deinit_dev();
249 return (ENOMEM);
250 }
251
252 mutex_init(&_ii_info_mutex, NULL, MUTEX_DRIVER, NULL);
253 mutex_init(&_ii_overflow_mutex, NULL, MUTEX_DRIVER, NULL);
254 mutex_init(&_ii_config_mutex, NULL, MUTEX_DRIVER, NULL);
255 mutex_init(&_ii_cluster_mutex, NULL, MUTEX_DRIVER, NULL);
256 mutex_init(&_ii_group_mutex, NULL, MUTEX_DRIVER, NULL);
257
258 ii_volume_update = nsc_register_svc("RDCVolumeUpdated", 0);
259 ii_report_luns = nsc_register_svc("IIReportLuns", 0);
260 ii_get_initiators = nsc_register_svc("IIGetInitiators", 0);
261
262 if (!ii_volume_update || !ii_report_luns || !ii_get_initiators) {
263 _ii_deinit_dev();
264 return (ENOMEM);
265 }
266
267 return (0);
268 }
269
270
271 /*
272 * _ii_deinit_dev
273 * De-initialise the shadow driver
274 *
275 */
276
277 void
_ii_deinit_dev()278 _ii_deinit_dev()
279 {
280
281 if (_ii_io)
282 (void) nsc_unregister_io(_ii_io, 0);
283
284 if (_ii_ior)
285 (void) nsc_unregister_io(_ii_ior, 0);
286
287 if (_ii_local_mem)
288 (void) nsc_unregister_mem(_ii_local_mem);
289
290 if (ii_volume_update)
291 (void) nsc_unregister_svc(ii_volume_update);
292
293 if (ii_report_luns)
294 (void) nsc_unregister_svc(ii_report_luns);
295
296 if (ii_get_initiators)
297 (void) nsc_unregister_svc(ii_get_initiators);
298
299 mutex_destroy(&_ii_info_mutex);
300 mutex_destroy(&_ii_overflow_mutex);
301 mutex_destroy(&_ii_config_mutex);
302 mutex_destroy(&_ii_cluster_mutex);
303 mutex_destroy(&_ii_group_mutex);
304 if (_ii_concopy_init)
305 sema_destroy(&_ii_concopy_sema);
306 _ii_concopy_init = 0;
307
308 }
309
310 static char *
ii_pathname(nsc_fd_t * fd)311 ii_pathname(nsc_fd_t *fd)
312 {
313 char *rc;
314
315 if (fd == NULL || (rc = nsc_pathname(fd)) == NULL)
316 return ("");
317 else
318 return (rc);
319 }
320
321
322 /*
323 * _ii_rlse_d
324 * Internal mechanics of _ii_rlse_devs(). Takes care of
325 * resetting the ownership information as required.
326 */
327
328 static void
_ii_rlse_d(ip,mst,raw)329 _ii_rlse_d(ip, mst, raw)
330 _ii_info_t *ip;
331 int mst, raw;
332 {
333 _ii_info_dev_t *cip;
334 _ii_info_dev_t *rip;
335
336 rip = mst ? (ip->bi_mstrdev) : &(ip->bi_shdrdev);
337 cip = mst ? (ip->bi_mstdev) : &(ip->bi_shddev);
338
339 DTRACE_PROBE2(_ii_rlse_d_type,
340 _ii_info_dev_t *, rip,
341 _ii_info_dev_t *, cip);
342
343
344 if (RSRV(cip)) {
345 if (raw) {
346 ASSERT(cip->bi_orsrv > 0);
347 cip->bi_orsrv--;
348 } else {
349 ASSERT(cip->bi_rsrv > 0);
350 cip->bi_rsrv--;
351 }
352
353 if (cip->bi_rsrv > 0) {
354 nsc_set_owner(cip->bi_fd, cip->bi_iodev);
355 } else if (cip->bi_orsrv > 0) {
356 nsc_set_owner(cip->bi_fd, rip->bi_iodev);
357 } else {
358 nsc_set_owner(cip->bi_fd, NULL);
359 }
360
361 if (!RSRV(cip)) {
362 nsc_release(cip->bi_fd);
363 }
364 } else {
365 if (raw) {
366 ASSERT(rip->bi_rsrv > 0);
367 rip->bi_rsrv--;
368 } else {
369 ASSERT(rip->bi_orsrv > 0);
370 rip->bi_orsrv--;
371 }
372
373 if (rip->bi_rsrv > 0) {
374 nsc_set_owner(rip->bi_fd, rip->bi_iodev);
375 } else if (rip->bi_orsrv > 0) {
376 nsc_set_owner(rip->bi_fd, cip->bi_iodev);
377 } else {
378 nsc_set_owner(rip->bi_fd, NULL);
379 }
380
381 if (!RSRV(rip)) {
382 rip->bi_flag = 0;
383 nsc_release(rip->bi_fd);
384 cv_broadcast(&ip->bi_releasecv);
385 }
386 }
387
388 }
389
390
391 /*
392 * _ii_rlse_devs
393 * Release named underlying devices.
394 *
395 * NOTE: the 'devs' argument must be the same as that passed to
396 * the preceding _ii_rsrv_devs call.
397 */
398
399 void
_ii_rlse_devs(ip,devs)400 _ii_rlse_devs(ip, devs)
401 _ii_info_t *ip;
402 int devs;
403 {
404
405 ASSERT(!(devs & (MST|SHD)));
406
407 ASSERT(ip->bi_head != (_ii_info_t *)0xdeadbeef);
408 if (!ip) {
409 cmn_err(CE_WARN, "!ii: _ii_rlse_devs null ip");
410 return;
411 }
412
413 mutex_enter(&ip->bi_rsrvmutex);
414
415 DTRACE_PROBE(_ii_rlse_devs_mutex);
416
417 if ((devs&(MST|MSTR)) != 0 && (ip->bi_flags&DSW_SHDIMPORT) == 0) {
418 if (NSHADOWS(ip) && ip != ip->bi_master)
419 _ii_rlse_devs(ip->bi_master, devs&(MST|MSTR));
420 else
421 _ii_rlse_d(ip, 1, (devs&MSTR));
422 }
423
424 if ((devs&(SHD|SHDR)) != 0 && (ip->bi_flags&DSW_SHDEXPORT) == 0) {
425 _ii_rlse_d(ip, 0, (devs&SHDR));
426 }
427
428 if ((devs&BMP) != 0 && ip->bi_bmpfd) {
429 if (--(ip->bi_bmprsrv) == 0)
430 nsc_release(ip->bi_bmpfd);
431 }
432
433 ASSERT(ip->bi_bmprsrv >= 0);
434 ASSERT(ip->bi_shdrsrv >= 0);
435 ASSERT(ip->bi_shdrrsrv >= 0);
436 mutex_exit(&ip->bi_rsrvmutex);
437
438 }
439
440
441 /*
442 * _ii_rsrv_d
443 * Reserve device flagged, unless its companion is already reserved,
444 * in that case increase the reserve on the companion.
445 */
446
447 static int
_ii_rsrv_d(int raw,_ii_info_dev_t * rid,_ii_info_dev_t * cid,int flag,_ii_info_t * ip)448 _ii_rsrv_d(int raw, _ii_info_dev_t *rid, _ii_info_dev_t *cid, int flag,
449 _ii_info_t *ip)
450 {
451 _ii_info_dev_t *p = NULL;
452 int other = 0;
453 int rc;
454
455 /*
456 * If user wants to do a cache reserve and it's already
457 * raw reserved, we need to do a real nsc_reserve, so wait
458 * until the release has been done.
459 */
460 if (RSRV(rid) && (flag == II_EXTERNAL) &&
461 (raw == 0) && (rid->bi_flag != II_EXTERNAL)) {
462 ip->bi_release++;
463 while (RSRV(rid)) {
464 DTRACE_PROBE1(_ii_rsrv_d_wait, _ii_info_dev_t *, rid);
465 cv_wait(&ip->bi_releasecv, &ip->bi_rsrvmutex);
466 DTRACE_PROBE1(_ii_rsrv_d_resume, _ii_info_dev_t *, rid);
467 }
468 ip->bi_release--;
469 }
470
471 if (RSRV(rid)) {
472 p = rid;
473 if (!raw) {
474 other = 1;
475 }
476 } else if (RSRV(cid)) {
477 p = cid;
478 if (raw) {
479 other = 1;
480 }
481 }
482
483 if (p) {
484 if (other) {
485 p->bi_orsrv++;
486 } else {
487 p->bi_rsrv++;
488 }
489
490 if (p->bi_iodev) {
491 nsc_set_owner(p->bi_fd, p->bi_iodev);
492 }
493
494 return (0);
495 }
496 p = raw ? rid : cid;
497
498 if ((rc = nsc_reserve(p->bi_fd, 0)) == 0) {
499 if (p->bi_iodev) {
500 nsc_set_owner(p->bi_fd, p->bi_iodev);
501 }
502 p->bi_rsrv++;
503 if (raw)
504 p->bi_flag = flag;
505 }
506
507 return (rc);
508 }
509
510 /*
511 * _ii_rsrv_devs
512 * Reserve named underlying devices.
513 *
514 */
515
516 int
_ii_rsrv_devs(_ii_info_t * ip,int devs,int flag)517 _ii_rsrv_devs(_ii_info_t *ip, int devs, int flag)
518 {
519 int rc = 0;
520 int got = 0;
521
522 ASSERT(!(devs & (MST|SHD)));
523
524 if (!ip) {
525 cmn_err(CE_WARN, "!ii: _ii_rsrv_devs null ip");
526 return (EINVAL);
527 }
528
529 mutex_enter(&ip->bi_rsrvmutex);
530
531 DTRACE_PROBE(_ii_rsrv_devs_mutex);
532
533 if (rc == 0 && (devs&(MST|MSTR)) != 0 &&
534 (ip->bi_flags&DSW_SHDIMPORT) == 0) {
535 DTRACE_PROBE(_ii_rsrv_devs_master);
536 if (NSHADOWS(ip) && ip != ip->bi_master) {
537 if ((rc = _ii_rsrv_devs(ip->bi_master, devs&(MST|MSTR),
538 flag)) != 0) {
539 cmn_err(CE_WARN,
540 "!ii: nsc_reserve multi-master failed");
541 } else {
542 got |= devs&(MST|MSTR);
543 }
544 } else {
545 if ((rc = _ii_rsrv_d((devs&MSTR) != 0, ip->bi_mstrdev,
546 ip->bi_mstdev, flag, ip)) != 0) {
547 cmn_err(CE_WARN,
548 "!ii: nsc_reserve master failed %d", rc);
549 } else {
550 got |= (devs&(MST|MSTR));
551 }
552 }
553 }
554
555 if (rc == 0 && (devs&(SHD|SHDR)) != 0 &&
556 (ip->bi_flags&DSW_SHDEXPORT) == 0) {
557 DTRACE_PROBE(_ii_rsrv_devs_shadow);
558 if ((rc = _ii_rsrv_d((devs&SHDR) != 0, &ip->bi_shdrdev,
559 &ip->bi_shddev, flag, ip)) != 0) {
560 cmn_err(CE_WARN,
561 "!ii: nsc_reserve shadow failed %d", rc);
562 } else {
563 got |= (devs&(SHD|SHDR));
564 }
565 }
566
567 if (rc == 0 && (devs&BMP) != 0 && ip->bi_bmpfd) {
568 DTRACE_PROBE(_ii_rsrv_devs_bitmap);
569 if ((ip->bi_bmprsrv == 0) &&
570 (rc = nsc_reserve(ip->bi_bmpfd, 0)) != 0) {
571 cmn_err(CE_WARN,
572 "!ii: nsc_reserve bitmap failed %d", rc);
573 } else {
574 (ip->bi_bmprsrv)++;
575 got |= BMP;
576 }
577 }
578 mutex_exit(&ip->bi_rsrvmutex);
579 if (rc != 0 && got != 0)
580 _ii_rlse_devs(ip, got);
581
582 return (rc);
583 }
584
585 static int
_ii_reserve_begin(_ii_info_t * ip)586 _ii_reserve_begin(_ii_info_t *ip)
587 {
588 int rc;
589
590 mutex_enter(&ip->bi_rlsemutex);
591 if ((rc = _ii_wait_for_it(ip)) == 0) {
592 ++ip->bi_rsrvcnt;
593 }
594 mutex_exit(&ip->bi_rlsemutex);
595
596 return (rc);
597 }
598
599 static int
_ii_wait_for_it(_ii_info_t * ip)600 _ii_wait_for_it(_ii_info_t *ip)
601 {
602 int nosig;
603
604 nosig = 1;
605 while (ip->bi_rsrvcnt > 0) {
606 nosig = cv_wait_sig(&ip->bi_reservecv, &ip->bi_rlsemutex);
607 if (!nosig) {
608 break;
609 }
610 }
611
612 return (nosig? 0 : EINTR);
613 }
614
615 static void
_ii_reserve_end(_ii_info_t * ip)616 _ii_reserve_end(_ii_info_t *ip)
617 {
618 mutex_enter(&ip->bi_rlsemutex);
619 if (ip->bi_rsrvcnt <= 0) {
620 mutex_exit(&ip->bi_rlsemutex);
621 return;
622 }
623 --ip->bi_rsrvcnt;
624 mutex_exit(&ip->bi_rlsemutex);
625 cv_broadcast(&ip->bi_reservecv);
626
627 }
628
629 static int
ii_fill_copy_bmp(_ii_info_t * ip)630 ii_fill_copy_bmp(_ii_info_t *ip)
631 {
632 int rc;
633 chunkid_t max_chunk, chunk_num;
634
635 if ((rc = II_FILL_COPY_BMP(ip)) != 0)
636 return (rc);
637 /*
638 * make certain that the last bits of the last byte of the bitmap
639 * aren't filled as they may be copied out to the user.
640 */
641
642 chunk_num = ip->bi_size / DSW_SIZE;
643 if ((ip->bi_size % DSW_SIZE) != 0)
644 ++chunk_num;
645
646 max_chunk = chunk_num;
647 if ((max_chunk & 0x7) != 0)
648 max_chunk = (max_chunk + 7) & ~7;
649
650 DTRACE_PROBE2(_ii_fill_copy_bmp_chunks, chunkid_t, chunk_num,
651 chunkid_t, max_chunk);
652
653 for (; chunk_num < max_chunk; chunk_num++) {
654 (void) II_CLR_COPY_BIT(ip, chunk_num);
655 }
656
657 return (0);
658 }
659
660 static int
ii_update_denied(_ii_info_t * ip,spcs_s_info_t kstatus,int direction,int all)661 ii_update_denied(_ii_info_t *ip, spcs_s_info_t kstatus,
662 int direction, int all)
663 {
664 rdc_update_t update;
665 int size;
666 unsigned char *bmp;
667
668 update.volume = direction == CV_SHD2MST ? ii_pathname(MSTFD(ip)) :
669 ip->bi_keyname;
670 update.denied = 0;
671 update.protocol = RDC_SVC_ONRETURN;
672 update.size = size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
673 update.status = kstatus;
674 update.bitmap = bmp = kmem_alloc(update.size, KM_SLEEP);
675 if (bmp == NULL) {
676 spcs_s_add(kstatus, ENOMEM);
677 return (1);
678 }
679
680 DTRACE_PROBE2(_ii_update_denied, int, all, int, size);
681
682 if (all) {
683 while (size-- > 0)
684 *bmp++ = (unsigned char)0xff;
685 } else {
686 if (II_CHANGE_BMP(ip, update.bitmap) != 0) {
687 /* failed to read bitmap */
688 spcs_s_add(kstatus, EIO);
689 update.denied = 1;
690 }
691 }
692
693 /* check that no user of volume objects */
694 if (update.denied == 0) {
695 (void) nsc_call_svc(ii_volume_update, (intptr_t)&update);
696 }
697 kmem_free(update.bitmap, FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size)));
698
699 return (update.denied);
700 }
701
702 static int
ii_need_same_size(_ii_info_t * ip)703 ii_need_same_size(_ii_info_t *ip)
704 {
705 rdc_update_t update;
706
707 update.volume = ip->bi_keyname;
708 update.denied = 0;
709 update.protocol = RDC_SVC_VOL_ENABLED;
710
711 (void) nsc_call_svc(ii_volume_update, (intptr_t)&update);
712
713 return (update.denied);
714 }
715
716 /*
717 * ii_volume: check if vol is already known to Instant Image and return
718 * volume type if it is.
719 */
720
721 static int
ii_volume(char * vol,int locked)722 ii_volume(char *vol, int locked)
723 {
724 _ii_info_t *ip;
725 _ii_overflow_t *op;
726 int rc = NONE;
727
728 /* scan overflow volume list */
729 mutex_enter(&_ii_overflow_mutex);
730
731 DTRACE_PROBE(_ii_volume_mutex);
732
733 for (op = _ii_overflow_top; op; op = op->ii_next) {
734 if (strcmp(vol, op->ii_volname) == 0)
735 break;
736 }
737 mutex_exit(&_ii_overflow_mutex);
738 if (op) {
739 return (OVR);
740 }
741
742 if (!locked) {
743 mutex_enter(&_ii_info_mutex);
744 }
745
746 DTRACE_PROBE(_ii_volume_mutex2);
747
748 for (ip = _ii_info_top; ip; ip = ip->bi_next) {
749 if (strcmp(vol, ii_pathname(ip->bi_mstfd)) == 0) {
750 rc = MST;
751 break;
752 }
753 if (strcmp(vol, ip->bi_keyname) == 0) {
754 rc = SHD;
755 break;
756 }
757 if (strcmp(vol, ii_pathname(ip->bi_bmpfd)) == 0) {
758 rc = BMP;
759 break;
760 }
761 }
762 DTRACE_PROBE1(_ii_volume_data, int, rc);
763
764 if (!locked) {
765 mutex_exit(&_ii_info_mutex);
766 }
767
768 return (rc);
769 }
770
771 /*
772 * ii_open_shadow: open shadow volume for both cached and raw access,
773 * if the normal device open fails attempt a file open to allow
774 * shadowing into a file.
775 */
776
777 static int
ii_open_shadow(_ii_info_t * ip,char * shadow_vol)778 ii_open_shadow(_ii_info_t *ip, char *shadow_vol)
779 {
780 int rc = 0;
781 int file_rc = 0;
782
783 ip->bi_shdfd = nsc_open(shadow_vol,
784 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, _ii_fd_def,
785 (blind_t)&(ip->bi_shddev), &rc);
786 if (!ip->bi_shdfd) {
787 ip->bi_shdfd = nsc_open(shadow_vol,
788 NSC_IIR_ID|NSC_FILE|NSC_RDWR, _ii_fd_def,
789 (blind_t)&(ip->bi_shddev), &file_rc);
790 file_rc = 1;
791 if (!ip->bi_shdfd) {
792 return (rc);
793 }
794 DTRACE_PROBE(_ii_open_shadow);
795 }
796 else
797 DTRACE_PROBE(_ii_open_shadow);
798
799 if (file_rc == 0) {
800 ip->bi_shdrfd = nsc_open(shadow_vol,
801 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, _ii_fd_def,
802 (blind_t)&(ip->bi_shdrdev), &rc);
803 DTRACE_PROBE(_ii_open_shadow);
804 } else {
805 ip->bi_shdrfd = nsc_open(shadow_vol,
806 NSC_IIR_ID|NSC_FILE|NSC_RDWR, _ii_fd_def,
807 (blind_t)&(ip->bi_shdrdev), &rc);
808 DTRACE_PROBE(_ii_open_shadow);
809 }
810
811 if (!ip->bi_shdrfd) {
812 (void) nsc_close(ip->bi_shdfd);
813 DTRACE_PROBE(_ii_open_shadow);
814 return (rc);
815 }
816
817 return (0);
818 }
819
820 static void
ii_register_shd(_ii_info_t * ip)821 ii_register_shd(_ii_info_t *ip)
822 {
823 ip->bi_shd_tok = _ii_register_path(ip->bi_keyname,
824 NSC_CACHE, _ii_io);
825 ip->bi_shdr_tok = _ii_register_path(ip->bi_keyname,
826 NSC_DEVICE, _ii_ior);
827
828 }
829
830 static void
ii_register_mst(_ii_info_t * ip)831 ii_register_mst(_ii_info_t *ip)
832 {
833 ip->bi_mst_tok = _ii_register_path(ii_pathname(ip->bi_mstfd),
834 NSC_CACHE, _ii_io);
835 ip->bi_mstr_tok = _ii_register_path(ii_pathname(ip->bi_mstrfd),
836 NSC_DEVICE, _ii_ior);
837
838 }
839
840 static int
ii_register_ok(_ii_info_t * ip)841 ii_register_ok(_ii_info_t *ip)
842 {
843 int rc;
844 int sibling;
845 int exported;
846
847 rc = 1;
848 sibling = NSHADOWS(ip) && ip != ip->bi_head;
849 exported = ip->bi_flags & DSW_SHDEXPORT;
850
851 if ((ip->bi_bmpfd && !ip->bi_bmp_tok) || (!exported && (
852 !ip->bi_shd_tok || !ip->bi_shdr_tok)))
853 rc = 0;
854 else if (!sibling && (!ip->bi_mst_tok || !ip->bi_mstr_tok))
855 rc = 0;
856
857 return (rc);
858 }
859
860 #ifndef DISABLE_KSTATS
861
862 /*
863 * _ii_kstat_create
864 * Create and install kstat_io data
865 *
866 * Calling/Exit State:
867 * Returns 0 if kstats couldn't be created, otherwise it returns
868 * a pointer to the created kstat_t.
869 */
870
871 static kstat_t *
_ii_kstat_create(_ii_info_t * ip,char * type)872 _ii_kstat_create(_ii_info_t *ip, char *type)
873 {
874 kstat_t *result;
875 char name[ IOSTAT_NAME_LEN ];
876 int setnum;
877 char *nptr;
878 static int mstnum = 0;
879 static int shdbmpnum = -1;
880
881 switch (*type) {
882 case 'm':
883 setnum = mstnum++;
884 nptr = ip->bi_kstat_io.mstio;
885 break;
886 case 's':
887 /* assumption: shadow kstats created before bitmap */
888 setnum = ++shdbmpnum;
889 nptr = ip->bi_kstat_io.shdio;
890 break;
891 case 'b':
892 setnum = shdbmpnum;
893 nptr = ip->bi_kstat_io.bmpio;
894 break;
895 default:
896 cmn_err(CE_WARN, "!Unable to determine kstat type (%c)", *type);
897 setnum = -1;
898 break;
899 }
900 /*
901 * The name of the kstat, defined below, is designed to work
902 * with the 'iostat -x' command. This command leaves only
903 * 9 characters for the name, and the kstats built in to Solaris
904 * all seem to be of the form <service><number>. For that
905 * reason, we have chosen ii<type><number>, where <type> is
906 * m, s, b, or o (for master, shadow, bitmap, and overflow
907 * respectively), and the number is monotonically increasing from
908 * 0 for each time one of those <type>s are created. Note that
909 * the shadow and bitmap are always created in pairs and so, for
910 * any given set, they will have the same <number>.
911 */
912 (void) sprintf(name, "ii%c%d", *type, setnum);
913 (void) strncpy(nptr, name, IOSTAT_NAME_LEN);
914 result = kstat_create("ii", 0, name, "disk", KSTAT_TYPE_IO, 1, 0);
915 if (result) {
916 result->ks_private = ip;
917 result->ks_lock = &ip->bi_kstat_io.statmutex;
918 kstat_install(result);
919 } else {
920 cmn_err(CE_WARN, "!Unable to create %s kstats for set %s", type,
921 ip->bi_keyname);
922 }
923
924 return (result);
925 }
926
927 /*
928 * _ii_overflow_kstat_create
929 * Create and install kstat_io data for an overflow volume
930 *
931 * Calling/Exit State:
932 * Returns 0 if kstats couldn't be created, otherwise it returns
933 * a pointer to the created kstat_t.
934 *
935 * See comments in _ii_kstat_create for additional information.
936 *
937 */
938 static kstat_t *
_ii_overflow_kstat_create(_ii_info_t * ip,_ii_overflow_t * op)939 _ii_overflow_kstat_create(_ii_info_t *ip, _ii_overflow_t *op)
940 {
941 kstat_t *result;
942 char *nptr;
943 char name [IOSTAT_NAME_LEN];
944 static int ovrnum = 0;
945 int setnum = ovrnum++;
946
947 nptr = ip->bi_kstat_io.ovrio;
948
949 (void) sprintf(name, "iio%d", setnum);
950 (void) strncpy(nptr, name, IOSTAT_NAME_LEN);
951
952 mutex_init(&op->ii_kstat_mutex, NULL, MUTEX_DRIVER, NULL);
953
954 if ((result =
955 kstat_create("ii", 0, name, "disk", KSTAT_TYPE_IO, 1, 0))) {
956 result->ks_private = ip;
957 result->ks_lock = &op->ii_kstat_mutex;
958 kstat_install(result);
959 } else {
960 mutex_destroy(&op->ii_kstat_mutex);
961 cmn_err(CE_WARN, "!Unabled to create overflow kstat for set "
962 "%s", ip->bi_keyname);
963 }
964
965 return (result);
966 }
967
968 #endif
969
970 static void
ii_str_kstat_copy(char * str,char * p1,char * p2,char * p3,char * p4)971 ii_str_kstat_copy(char *str, char *p1, char *p2, char *p3, char *p4)
972 {
973 static int whinged = 0;
974 char *part[ 4 ];
975 char fulldata[ DSW_NAMELEN ];
976 int i, offset, remain;
977 int num_parts;
978 int leftover;
979 int kscharsize = KSTAT_DATA_CHAR_LEN - 1;
980
981 /*
982 * NOTE: the following lines must be changed if DSW_NAMELEN
983 * ever changes. You'll need a part[] for every kscharsize
984 * characters (or fraction thereof). The ii_kstat_set_t
985 * definition in dsw_dev.h will also need new ovr_? entries.
986 */
987 part[ 0 ] = p1;
988 part[ 1 ] = p2;
989 part[ 2 ] = p3;
990 part[ 3 ] = p4;
991
992 bzero(fulldata, DSW_NAMELEN);
993 if (str) {
994 (void) strncpy(fulldata, str, DSW_NAMELEN);
995 }
996
997 num_parts = DSW_NAMELEN / kscharsize;
998 leftover = DSW_NAMELEN % kscharsize;
999 if (leftover) {
1000 ++num_parts;
1001 }
1002
1003 if (num_parts > sizeof (part) / sizeof (part[0])) {
1004 /*
1005 * DSW_NAMELEN is 64 and kscharsize is 15.
1006 * It's always "whinged"
1007 */
1008 if (!whinged) {
1009 #ifdef DEBUG
1010 cmn_err(CE_WARN, "!May not have enough room "
1011 "to store volume name in kstats");
1012 #endif
1013 whinged = 1;
1014 }
1015 num_parts = sizeof (part) / sizeof (part[0]);
1016 }
1017
1018 offset = 0;
1019 remain = DSW_NAMELEN;
1020 for (i = 0; i < num_parts; i++) {
1021 int to_copy = remain > kscharsize? kscharsize : remain;
1022 bcopy(&fulldata[ offset ], part[ i ], to_copy);
1023 offset += to_copy;
1024 remain -= to_copy;
1025 }
1026 }
1027
1028 static int
ii_set_stats_update(kstat_t * ksp,int rw)1029 ii_set_stats_update(kstat_t *ksp, int rw)
1030 {
1031 _ii_info_t *ip = (_ii_info_t *)ksp->ks_private;
1032 ii_kstat_set_t *kp = (ii_kstat_set_t *)ksp->ks_data;
1033
1034 if (KSTAT_WRITE == rw) {
1035 return (EACCES);
1036 }
1037
1038 /* copy values over */
1039 kp->size.value.ul = ip->bi_size;
1040 kp->flags.value.ul = ip->bi_flags;
1041 kp->unit.value.ul = ip->bi_throttle_unit;
1042 kp->delay.value.ul = ip->bi_throttle_delay;
1043 kp->mtime.value.ul = ip->bi_mtime;
1044
1045 /* update bitmap counters if necessary */
1046 if (ip->bi_state & DSW_CNTCPYBITS) {
1047 ip->bi_copybits = 0;
1048 if (_ii_rsrv_devs(ip, BMP, II_INTERNAL) == 0) {
1049 ip->bi_state &= ~DSW_CNTCPYBITS;
1050 II_CNT_BITS(ip, ip->bi_copyfba,
1051 &ip->bi_copybits,
1052 DSW_BM_SIZE_BYTES(ip));
1053 _ii_rlse_devs(ip, BMP);
1054 }
1055 }
1056
1057 if (ip->bi_state & DSW_CNTSHDBITS) {
1058 ip->bi_shdbits = 0;
1059 if (_ii_rsrv_devs(ip, BMP, II_INTERNAL) == 0) {
1060 ip->bi_state &= ~DSW_CNTSHDBITS;
1061 II_CNT_BITS(ip, ip->bi_shdfba,
1062 &ip->bi_shdbits,
1063 DSW_BM_SIZE_BYTES(ip));
1064 _ii_rlse_devs(ip, BMP);
1065 }
1066 }
1067
1068 kp->copybits.value.ul = ip->bi_copybits;
1069 kp->shdbits.value.ul = ip->bi_shdbits;
1070
1071 /* copy volume names */
1072 ii_str_kstat_copy(ii_pathname(MSTFD(ip)),
1073 kp->mst_a.value.c, kp->mst_b.value.c,
1074 kp->mst_c.value.c, kp->mst_d.value.c);
1075
1076 ii_str_kstat_copy(ip->bi_keyname, kp->set_a.value.c, kp->set_b.value.c,
1077 kp->set_c.value.c, kp->set_d.value.c);
1078
1079 ii_str_kstat_copy(ii_pathname(ip->bi_bmpfd),
1080 kp->bmp_a.value.c, kp->bmp_b.value.c,
1081 kp->bmp_c.value.c, kp->bmp_d.value.c);
1082
1083 if (ip->bi_overflow) {
1084 ii_str_kstat_copy(ip->bi_overflow->ii_volname,
1085 kp->ovr_a.value.c, kp->ovr_b.value.c, kp->ovr_c.value.c,
1086 kp->ovr_d.value.c);
1087 (void) strlcpy(kp->ovr_io.value.c, ip->bi_kstat_io.ovrio,
1088 KSTAT_DATA_CHAR_LEN);
1089 } else {
1090 ii_str_kstat_copy("", kp->ovr_a.value.c, kp->ovr_b.value.c,
1091 kp->ovr_c.value.c, kp->ovr_d.value.c);
1092 bzero(kp->ovr_io.value.c, KSTAT_DATA_CHAR_LEN);
1093 }
1094 if ((ip->bi_flags) & DSW_TREEMAP) {
1095 kp->shdchks.value.ul = ip->bi_shdchks;
1096 kp->shdchkused.value.ul = ip->bi_shdchkused;
1097 } else {
1098 kp->shdchks.value.ul = 0;
1099 kp->shdchkused.value.ul = 0;
1100 }
1101 /* make sure value.c are always null terminated */
1102 (void) strlcpy(kp->mst_io.value.c, ip->bi_kstat_io.mstio,
1103 KSTAT_DATA_CHAR_LEN);
1104 (void) strlcpy(kp->shd_io.value.c, ip->bi_kstat_io.shdio,
1105 KSTAT_DATA_CHAR_LEN);
1106 (void) strlcpy(kp->bmp_io.value.c, ip->bi_kstat_io.bmpio,
1107 KSTAT_DATA_CHAR_LEN);
1108
1109 return (0);
1110 }
1111
1112 /*
1113 * _ii_config
1114 * Configure an II device pair
1115 *
1116 * Calling/Exit State:
1117 * Returns 0 if the pairing was configured, otherwise an
1118 * error code. The ioctl data stucture is copied out to the user
1119 * and contains any additional error information, and the master
1120 * and shadow volume names if not supplied by the user.
1121 *
1122 * Description:
1123 * Reads the user configuration structure and attempts
1124 * to establish an II pairing. The snapshot of the master
1125 * device is established at this point in time.
1126 */
1127
1128 int
_ii_config(intptr_t arg,int ilp32,int * rvp,int iflags)1129 _ii_config(intptr_t arg, int ilp32, int *rvp, int iflags)
1130 {
1131 dsw_config_t uconf;
1132 dsw_config32_t *uconf32;
1133 _ii_info_t *ip, *hip, **ipp;
1134 int rc;
1135 int type;
1136 int nshadows;
1137 int add_to_mst_top;
1138 int import;
1139 int existing;
1140 int resized;
1141 nsc_size_t mst_size, shd_size, bmp_size;
1142 nsc_off_t shdfba;
1143 nsc_off_t copyfba;
1144 int keylen, keyoffset;
1145 ii_header_t *bm_header;
1146 nsc_buf_t *tmp;
1147 spcs_s_info_t kstatus;
1148 spcs_s_info32_t ustatus32;
1149 int rtype;
1150 uint_t hints;
1151
1152 /* Import is a once only operation like an enable */
1153 ASSERT((iflags&(II_EXISTING|II_IMPORT)) != (II_EXISTING|II_IMPORT));
1154 existing = (iflags&II_EXISTING) != 0;
1155 import = (iflags&II_IMPORT) != 0;
1156 *rvp = 0;
1157 if (ilp32) {
1158 uconf32 = kmem_zalloc(sizeof (dsw_config32_t), KM_SLEEP);
1159 if (uconf32 == NULL) {
1160 return (ENOMEM);
1161 }
1162 if (copyin((void *)arg, uconf32, sizeof (*uconf32)) < 0)
1163 return (EFAULT);
1164 II_TAIL_COPY(uconf, (*uconf32), master_vol, dsw_config_t);
1165 uconf.status = (spcs_s_info_t)uconf32->status;
1166 ustatus32 = uconf32->status;
1167 kmem_free(uconf32, sizeof (dsw_config32_t));
1168 } else if (copyin((void *)arg, &uconf, sizeof (uconf)) < 0)
1169 return (EFAULT);
1170
1171 DTRACE_PROBE3(_ii_config_info, char *, uconf.master_vol,
1172 char *, uconf.shadow_vol, char *, uconf.bitmap_vol);
1173
1174 kstatus = spcs_s_kcreate();
1175 if (kstatus == NULL)
1176 return (ENOMEM);
1177
1178 if (_ii_shutting_down)
1179 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1180 DSW_ESHUTDOWN));
1181
1182 if (uconf.bitmap_vol[0] == 0)
1183 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EEMPTY));
1184
1185 mutex_enter(&_ii_config_mutex);
1186 ip = nsc_kmem_zalloc(sizeof (*ip), KM_SLEEP, _ii_local_mem);
1187 if (!ip) {
1188 mutex_exit(&_ii_config_mutex);
1189 return (spcs_s_ocopyoutf(&kstatus, uconf.status, ENOMEM));
1190 }
1191 ip->bi_mstdev = nsc_kmem_zalloc(sizeof (*ip->bi_mstdev), KM_SLEEP,
1192 _ii_local_mem);
1193 ip->bi_mstrdev = nsc_kmem_zalloc(sizeof (*ip->bi_mstdev), KM_SLEEP,
1194 _ii_local_mem);
1195 if (ip->bi_mstdev == NULL || ip->bi_mstrdev == NULL) {
1196 mutex_exit(&_ii_config_mutex);
1197 _ii_info_free(ip);
1198 return (spcs_s_ocopyoutf(&kstatus, uconf.status, ENOMEM));
1199 }
1200
1201 ip->bi_disabled = 1; /* mark as disabled until we are ready to go */
1202 mutex_init(&ip->bi_mutex, NULL, MUTEX_DRIVER, NULL);
1203 mutex_init(&ip->bi_bmpmutex, NULL, MUTEX_DRIVER, NULL);
1204 mutex_init(&ip->bi_rsrvmutex, NULL, MUTEX_DRIVER, NULL);
1205 mutex_init(&ip->bi_rlsemutex, NULL, MUTEX_DRIVER, NULL);
1206 mutex_init(&ip->bi_chksmutex, NULL, MUTEX_DRIVER, NULL);
1207 cv_init(&ip->bi_copydonecv, NULL, CV_DRIVER, NULL);
1208 cv_init(&ip->bi_reservecv, NULL, CV_DRIVER, NULL);
1209 cv_init(&ip->bi_releasecv, NULL, CV_DRIVER, NULL);
1210 cv_init(&ip->bi_ioctlcv, NULL, CV_DRIVER, NULL);
1211 cv_init(&ip->bi_closingcv, NULL, CV_DRIVER, NULL);
1212 cv_init(&ip->bi_busycv, NULL, CV_DRIVER, NULL);
1213 rw_init(&ip->bi_busyrw, NULL, RW_DRIVER, NULL);
1214 rw_init(&ip->bi_linkrw, NULL, RW_DRIVER, NULL);
1215 (void) strncpy(ip->bi_keyname, uconf.shadow_vol, DSW_NAMELEN);
1216 ip->bi_keyname[DSW_NAMELEN-1] = '\0';
1217 ip->bi_throttle_unit = ii_throttle_unit;
1218 ip->bi_throttle_delay = ii_throttle_delay;
1219
1220 /* First check the list to see if uconf.bitmap_vol's already there */
1221
1222 if (ii_volume(uconf.bitmap_vol, 0) != NONE) {
1223 DTRACE_PROBE(_ii_config_bmp_found);
1224 mutex_exit(&_ii_config_mutex);
1225 _ii_info_free(ip);
1226 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EINUSE));
1227 }
1228
1229 ip->bi_bmpfd = nsc_open(uconf.bitmap_vol,
1230 NSC_IIR_ID|NSC_FILE|NSC_RDWR, NULL, (blind_t)&(ip->bi_bmpdev), &rc);
1231 if (!ip->bi_bmpfd)
1232 ip->bi_bmpfd = nsc_open(uconf.bitmap_vol,
1233 NSC_IIR_ID|NSC_CACHE|NSC_DEVICE|NSC_RDWR, NULL,
1234 (blind_t)&(ip->bi_bmpdev), &rc);
1235 if (!ip->bi_bmpfd && !existing) {
1236 mutex_exit(&_ii_config_mutex);
1237 _ii_info_free(ip);
1238 spcs_s_add(kstatus, rc);
1239 DTRACE_PROBE(_ii_config_no_bmp);
1240 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EOPEN));
1241 }
1242
1243 if (import) {
1244 uconf.flag = DSW_GOLDEN;
1245 II_FLAG_SETX(DSW_SHDIMPORT|DSW_GOLDEN, ip);
1246 }
1247
1248 if (existing) {
1249
1250 DTRACE_PROBE(_ii_config_existing);
1251 /*
1252 * ii_config is used by enable, import and resume (existing)
1253 * If not importing or resuming, then this must be enable.
1254 * Indicate this fact for SNMP use.
1255 */
1256
1257 if (!ip->bi_bmpfd) {
1258 /*
1259 * Couldn't read bitmap, mark master and shadow as
1260 * unusable.
1261 */
1262 II_FLAG_ASSIGN(DSW_BMPOFFLINE|DSW_MSTOFFLINE|
1263 DSW_SHDOFFLINE, ip);
1264
1265 /*
1266 * Set cluster tag for this element so it can
1267 * be suspended later
1268 */
1269 (void) II_LINK_CLUSTER(ip, uconf.cluster_tag);
1270
1271 /* need to check on master, might be shared */
1272 goto header_checked;
1273 }
1274 /* check the header */
1275 (void) _ii_rsrv_devs(ip, BMP, II_INTERNAL);
1276
1277 /* get first block of bit map */
1278 mutex_enter(&ip->bi_mutex);
1279 bm_header = _ii_bm_header_get(ip, &tmp);
1280 mutex_exit(&ip->bi_mutex);
1281 if (bm_header == NULL) {
1282 if (ii_debug > 0)
1283 cmn_err(CE_WARN,
1284 "!ii: _ii_bm_header_get returned NULL");
1285 mutex_exit(&_ii_config_mutex);
1286 _ii_info_free(ip);
1287 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1288 DSW_EHDRBMP));
1289 }
1290
1291 if (bm_header->ii_magic != DSW_DIRTY &&
1292 bm_header->ii_magic != DSW_CLEAN) {
1293 mutex_exit(&_ii_config_mutex);
1294 _ii_bm_header_free(bm_header, ip, tmp);
1295 _ii_info_free(ip);
1296 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1297 DSW_EINVALBMP));
1298 }
1299
1300 II_FLAG_ASSIGN(bm_header->ii_state, ip);
1301 /* Restore copy throttle parameters, if header version is 3 */
1302 if (bm_header->ii_version >= 3) { /* II_HEADER_VERSION */
1303 ip->bi_throttle_delay = bm_header->ii_throttle_delay;
1304 ip->bi_throttle_unit = bm_header->ii_throttle_unit;
1305 }
1306
1307 /* Restore cluster & group names, if header version is 4 */
1308 if (bm_header->ii_version >= 4) {
1309 /* cluster */
1310 if (*bm_header->clstr_name) {
1311 (void) strncpy(uconf.cluster_tag,
1312 bm_header->clstr_name, DSW_NAMELEN);
1313 (void) II_LINK_CLUSTER(ip, uconf.cluster_tag);
1314 }
1315
1316 /* group */
1317 if (*bm_header->group_name) {
1318 (void) strncpy(uconf.group_name,
1319 bm_header->group_name, DSW_NAMELEN);
1320 (void) II_LINK_GROUP(ip, uconf.group_name);
1321 }
1322 }
1323 /* restore latest modification time, if header version >= 5 */
1324 if (bm_header->ii_version >= 5) {
1325 ip->bi_mtime = bm_header->ii_mtime;
1326 }
1327
1328 /* Fetch master and shadow names from bitmap header */
1329 if (uconf.master_vol[0] == 0)
1330 (void) strncpy(uconf.master_vol, bm_header->master_vol,
1331 DSW_NAMELEN);
1332 if (uconf.shadow_vol[0] == 0)
1333 (void) strncpy(uconf.shadow_vol, bm_header->shadow_vol,
1334 DSW_NAMELEN);
1335
1336 /* return the fetched names to the user */
1337 if (ilp32) {
1338 uconf32 = kmem_zalloc(sizeof (dsw_config32_t),
1339 KM_SLEEP);
1340 if (uconf32 == NULL) {
1341 mutex_exit(&_ii_config_mutex);
1342 _ii_bm_header_free(bm_header, ip, tmp);
1343 _ii_rlse_devs(ip, BMP);
1344 _ii_info_free(ip);
1345 return (ENOMEM);
1346 }
1347 uconf32->status = ustatus32;
1348 II_TAIL_COPY((*uconf32), uconf, master_vol,
1349 dsw_config32_t);
1350 rc = copyout(uconf32, (void *)arg, sizeof (*uconf32));
1351 kmem_free(uconf32, sizeof (dsw_config32_t));
1352 } else {
1353 rc = copyout(&uconf, (void *)arg, sizeof (uconf));
1354 }
1355 if (rc) {
1356 mutex_exit(&_ii_config_mutex);
1357 _ii_bm_header_free(bm_header, ip, tmp);
1358 _ii_rlse_devs(ip, BMP);
1359 _ii_info_free(ip);
1360 return (EFAULT);
1361 }
1362
1363 if (strncmp(bm_header->bitmap_vol, uconf.bitmap_vol,
1364 DSW_NAMELEN) || ((!(ip->bi_flags&DSW_SHDIMPORT)) &&
1365 strncmp(bm_header->master_vol, uconf.master_vol,
1366 DSW_NAMELEN)) || strncmp(bm_header->shadow_vol,
1367 uconf.shadow_vol, DSW_NAMELEN)) {
1368 mutex_exit(&_ii_config_mutex);
1369 _ii_bm_header_free(bm_header, ip, tmp);
1370 _ii_rlse_devs(ip, BMP);
1371 _ii_info_free(ip);
1372 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1373 DSW_EMISMATCH));
1374 }
1375 shdfba = bm_header->ii_shdfba;
1376 copyfba = bm_header->ii_copyfba;
1377 if ((ip->bi_flags)&DSW_TREEMAP) {
1378 if (ii_debug > 0)
1379 cmn_err(CE_NOTE,
1380 "!II: Resuming short shadow volume");
1381
1382 ip->bi_mstchks = bm_header->ii_mstchks;
1383 ip->bi_shdchks = bm_header->ii_shdchks;
1384 ip->bi_shdchkused = bm_header->ii_shdchkused;
1385 ip->bi_shdfchk = bm_header->ii_shdfchk;
1386
1387 if (bm_header->overflow_vol[0] != 0)
1388 if ((rc = ii_overflow_attach(ip,
1389 bm_header->overflow_vol, 0)) != 0) {
1390 mutex_exit(&_ii_config_mutex);
1391 _ii_bm_header_free(bm_header, ip, tmp);
1392 _ii_rlse_devs(ip, BMP);
1393 _ii_info_free(ip);
1394 return (spcs_s_ocopyoutf(&kstatus,
1395 uconf.status, rc));
1396 }
1397 }
1398 _ii_bm_header_free(bm_header, ip, tmp);
1399 _ii_rlse_devs(ip, BMP);
1400 }
1401 header_checked:
1402
1403 if (ip->bi_flags&DSW_SHDIMPORT)
1404 (void) strcpy(uconf.master_vol, "<imported shadow>");
1405 if (!uconf.master_vol[0] || !uconf.shadow_vol[0]) {
1406 mutex_exit(&_ii_config_mutex);
1407 _ii_info_free(ip);
1408 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EEMPTY));
1409 }
1410
1411 /* check that no volume has been given twice */
1412 if (strncmp(uconf.master_vol, uconf.shadow_vol, DSW_NAMELEN) == 0) {
1413 mutex_exit(&_ii_config_mutex);
1414 _ii_info_free(ip);
1415 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EOPEN));
1416 }
1417
1418 if (strncmp(uconf.master_vol, uconf.bitmap_vol, DSW_NAMELEN) == 0) {
1419 mutex_exit(&_ii_config_mutex);
1420 _ii_info_free(ip);
1421 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EOPEN));
1422 }
1423
1424 if (strncmp(uconf.bitmap_vol, uconf.shadow_vol, DSW_NAMELEN) == 0) {
1425 mutex_exit(&_ii_config_mutex);
1426 _ii_info_free(ip);
1427 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EOPEN));
1428 }
1429
1430 /* check that master is not already a bitmap, shadow or overflow */
1431 type = ii_volume(uconf.master_vol, 1);
1432 if (type != NONE && type != MST) {
1433 mutex_exit(&_ii_config_mutex);
1434 _ii_info_free(ip);
1435 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EINUSE));
1436 }
1437
1438 /* check that shadow is not used as anything else */
1439 type = ii_volume(uconf.shadow_vol, 1);
1440 if (type != NONE && type != SHD) {
1441 mutex_exit(&_ii_config_mutex);
1442 _ii_info_free(ip);
1443 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EINUSE));
1444 }
1445
1446 /* Setup the table bitmap operations table */
1447 switch (ii_bitmap) {
1448 case II_KMEM:
1449 if (ii_debug > 0)
1450 cmn_err(CE_NOTE, "!ii: using volatile bitmaps");
1451 ip->bi_bitmap_ops = &kmem_buf_bmp;
1452 break;
1453 case II_FWC:
1454 hints = 0;
1455 (void) nsc_node_hints(&hints);
1456 if ((hints & NSC_FORCED_WRTHRU) == 0)
1457 ip->bi_bitmap_ops = &kmem_buf_bmp;
1458 else
1459 ip->bi_bitmap_ops = &alloc_buf_bmp;
1460 if (ii_debug > 0) {
1461 cmn_err(CE_NOTE, "!ii: chosen to use %s bitmaps",
1462 ip->bi_bitmap_ops == &kmem_buf_bmp ?
1463 "volatile" : "persistent");
1464 }
1465 break;
1466 case II_WTHRU:
1467 default:
1468 if (ii_debug > 0)
1469 cmn_err(CE_NOTE, "!ii: using persistent bitmaps");
1470 ip->bi_bitmap_ops = &alloc_buf_bmp;
1471 break;
1472 }
1473
1474 /*
1475 * If we found aother shadow volume with the same name,
1476 * If this is an resume operation,
1477 * If this shadow is in the exported state
1478 * then try an on the fly join instead
1479 */
1480 for (hip = _ii_info_top; hip; hip = hip->bi_next)
1481 if (strcmp(uconf.shadow_vol, hip->bi_keyname) == 0)
1482 break;
1483 if ((hip) && (type == SHD) && existing &&
1484 (ip->bi_flags & DSW_SHDEXPORT)) {
1485
1486 /*
1487 * Stop any copy in progress
1488 */
1489 while (_ii_stopcopy(hip) == EINTR)
1490 ;
1491
1492 /*
1493 * Start the imported shadow teardown
1494 */
1495 mutex_enter(&hip->bi_mutex);
1496
1497 /* disable accesss to imported shadow */
1498 hip->bi_disabled = 1;
1499
1500 /* Wait for any I/O's to complete */
1501 while (hip->bi_ioctl) {
1502 hip->bi_state |= DSW_IOCTL;
1503 cv_wait(&hip->bi_ioctlcv, &hip->bi_mutex);
1504 }
1505 mutex_exit(&hip->bi_mutex);
1506
1507 /* this rw_enter forces us to drain all active IO */
1508 rw_enter(&hip->bi_linkrw, RW_WRITER);
1509 rw_exit(&hip->bi_linkrw);
1510
1511 /* remove ip from _ii_info_top linked list */
1512 mutex_enter(&_ii_info_mutex);
1513 for (ipp = &_ii_info_top; *ipp; ipp = &((*ipp)->bi_next)) {
1514 if (hip == *ipp) {
1515 *ipp = hip->bi_next;
1516 break;
1517 }
1518 }
1519 if (hip->bi_kstat) {
1520 kstat_delete(hip->bi_kstat);
1521 hip->bi_kstat = NULL;
1522 }
1523 mutex_exit(&_ii_info_mutex);
1524
1525 /* Gain access to both bitmap volumes */
1526 rtype = BMP;
1527 if (((rc = _ii_rsrv_devs(hip, rtype, II_INTERNAL)) != 0) ||
1528 ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0)) {
1529 mutex_exit(&_ii_config_mutex);
1530 _ii_info_free(ip);
1531 return (spcs_s_ocopyoutf(&kstatus, uconf.status, rc));
1532 }
1533
1534 /* Merge imported bitmap */
1535 rc = II_JOIN_BMP(ip, hip);
1536
1537 /* Release access to bitmap volume */
1538 _ii_rlse_devs(hip, rtype);
1539 ii_sibling_free(hip);
1540
1541 /* Clear the fact that we are exported */
1542 mutex_enter(&ip->bi_mutex);
1543 II_FLAG_CLR(DSW_SHDEXPORT, ip);
1544
1545 /* Release resources */
1546 mutex_exit(&ip->bi_mutex);
1547 _ii_rlse_devs(ip, BMP);
1548
1549 } else if (type != NONE) {
1550 mutex_exit(&_ii_config_mutex);
1551 _ii_info_free(ip);
1552 return (spcs_s_ocopyoutf(&kstatus, uconf.status, DSW_EINUSE));
1553 }
1554
1555 /*
1556 * Handle non-exported shadow
1557 */
1558 if ((ip->bi_flags & DSW_SHDEXPORT) == 0) {
1559 if ((rc = ii_open_shadow(ip, uconf.shadow_vol)) != 0) {
1560 mutex_exit(&_ii_config_mutex);
1561 _ii_info_free(ip);
1562 spcs_s_add(kstatus, rc);
1563 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1564 DSW_EOPEN));
1565 }
1566 }
1567
1568 /*
1569 * allocate _ii_concopy_sema and set to a value that won't allow
1570 * all cache to be allocated by copy loops.
1571 */
1572
1573 if (_ii_concopy_init == 0 && ip->bi_bmpfd != NULL) {
1574 int asize = 0, wsize;
1575 nsc_size_t cfbas, maxfbas;
1576
1577 (void) nsc_cache_sizes(&asize, &wsize);
1578
1579 if (asize > 0) {
1580 cfbas = FBA_NUM(asize);
1581 (void) _ii_rsrv_devs(ip, BMP, II_INTERNAL);
1582 rc = nsc_maxfbas(ip->bi_bmpfd, 0, &maxfbas);
1583 _ii_rlse_devs(ip, BMP);
1584 if (!II_SUCCESS(rc))
1585 maxfbas = 1024; /* i.e. _SD_MAX_FBAS */
1586 ii_nconcopy = cfbas / (maxfbas * 2) / 3;
1587 }
1588 if (ii_nconcopy < 2)
1589 ii_nconcopy = 2;
1590 ASSERT(ii_nconcopy > 0);
1591 sema_init(&_ii_concopy_sema, ii_nconcopy, NULL,
1592 SEMA_DRIVER, NULL);
1593 _ii_concopy_init = 1;
1594 }
1595
1596 /* check for shared master volume */
1597 for (hip = _ii_mst_top; hip; hip = hip->bi_nextmst)
1598 if (strcmp(uconf.master_vol, ii_pathname(hip->bi_mstfd)) == 0)
1599 break;
1600 add_to_mst_top = (hip == NULL);
1601 if (!hip)
1602 for (hip = _ii_info_top; hip; hip = hip->bi_next)
1603 if (strcmp(uconf.master_vol,
1604 ii_pathname(hip->bi_mstfd)) == 0)
1605 break;
1606 nshadows = (hip != NULL);
1607
1608 /* Check if master is offline */
1609 if (hip) {
1610 if (hip->bi_flags & DSW_MSTOFFLINE) {
1611 mutex_exit(&_ii_config_mutex);
1612 _ii_info_free(ip);
1613 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1614 DSW_EOFFLINE));
1615 }
1616 }
1617
1618 if (!nshadows && (ip->bi_flags&DSW_SHDIMPORT) == 0) {
1619 ip->bi_mstfd = nsc_open(uconf.master_vol,
1620 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, _ii_fd_def,
1621 (blind_t)(ip->bi_mstdev), &rc);
1622 if (!ip->bi_mstfd) {
1623 mutex_exit(&_ii_config_mutex);
1624 _ii_info_free(ip);
1625 spcs_s_add(kstatus, rc);
1626 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1627 DSW_EOPEN));
1628 }
1629
1630 ip->bi_mstrfd = nsc_open(uconf.master_vol,
1631 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, _ii_fd_def,
1632 (blind_t)(ip->bi_mstrdev), &rc);
1633 if (!ip->bi_mstrfd) {
1634 mutex_exit(&_ii_config_mutex);
1635 _ii_info_free(ip);
1636 spcs_s_add(kstatus, rc);
1637 return (spcs_s_ocopyoutf(&kstatus, uconf.status,
1638 DSW_EOPEN));
1639 }
1640 }
1641
1642 ip->bi_head = ip;
1643 ip->bi_master = ip;
1644
1645 mutex_enter(&_ii_info_mutex);
1646 ip->bi_next = _ii_info_top;
1647 _ii_info_top = ip;
1648 if (nshadows) {
1649 /* link new shadow group together with others sharing master */
1650 if (ii_debug > 0)
1651 cmn_err(CE_NOTE,
1652 "!II: shadow %s shares master %s with other shadow"
1653 " groups", uconf.shadow_vol, uconf.master_vol);
1654 hip = hip->bi_head;
1655 nsc_kmem_free(ip->bi_mstrdev, sizeof (*ip->bi_mstrdev));
1656 nsc_kmem_free(ip->bi_mstdev, sizeof (*ip->bi_mstdev));
1657 ip->bi_mstrdev = hip->bi_mstrdev;
1658 ip->bi_mstdev = hip->bi_mstdev;
1659 ip->bi_head = hip;
1660 ip->bi_sibling = hip->bi_sibling;
1661 if (add_to_mst_top) {
1662 hip->bi_nextmst = _ii_mst_top;
1663 _ii_mst_top = hip;
1664 }
1665 hip->bi_sibling = ip;
1666 ip->bi_master = ip->bi_head->bi_master;
1667 }
1668 mutex_exit(&_ii_info_mutex);
1669 mutex_exit(&_ii_config_mutex);
1670
1671 keylen = strlen(ip->bi_keyname);
1672 if (keylen > KSTAT_STRLEN - 1) {
1673 keyoffset = keylen + 1 - KSTAT_STRLEN;
1674 } else {
1675 keyoffset = 0;
1676 }
1677 ip->bi_kstat = kstat_create("ii", _ii_instance++,
1678 &ip->bi_keyname[ keyoffset ], "iiset", KSTAT_TYPE_NAMED,
1679 sizeof (ii_kstat_set) / sizeof (kstat_named_t),
1680 KSTAT_FLAG_VIRTUAL);
1681 if (ip->bi_kstat) {
1682 ip->bi_kstat->ks_data = &ii_kstat_set;
1683 ip->bi_kstat->ks_update = ii_set_stats_update;
1684 ip->bi_kstat->ks_private = ip;
1685 kstat_install(ip->bi_kstat);
1686 } else {
1687 cmn_err(CE_WARN, "!Unable to create set-specific kstats");
1688 }
1689
1690 #ifndef DISABLE_KSTATS
1691 /* create kstats information */
1692 mutex_init(&ip->bi_kstat_io.statmutex, NULL, MUTEX_DRIVER, NULL);
1693 if (ip == ip->bi_master) {
1694 ip->bi_kstat_io.master = _ii_kstat_create(ip, "master");
1695 } else {
1696 ip->bi_kstat_io.master = ip->bi_master->bi_kstat_io.master;
1697 (void) strlcpy(ip->bi_kstat_io.mstio,
1698 ip->bi_master->bi_kstat_io.mstio, KSTAT_DATA_CHAR_LEN);
1699 }
1700 ip->bi_kstat_io.shadow = _ii_kstat_create(ip, "shadow");
1701 ip->bi_kstat_io.bitmap = _ii_kstat_create(ip, "bitmap");
1702 #endif
1703
1704 (void) _ii_reserve_begin(ip);
1705 rtype = MSTR|SHDR|BMP;
1706 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
1707 spcs_s_add(kstatus, rc);
1708 rc = DSW_ERSRVFAIL;
1709 goto fail;
1710 }
1711
1712 if (ip->bi_flags&DSW_SHDIMPORT) {
1713 rc = 0; /* no master for imported volumes */
1714 mst_size = 0;
1715 } else
1716 rc = nsc_partsize(MSTFD(ip), &mst_size);
1717 if (rc == 0 && (ip->bi_flags&DSW_SHDEXPORT) == 0)
1718 rc = nsc_partsize(SHDFD(ip), &shd_size);
1719 if (!ip->bi_bmpfd)
1720 rc = EINVAL;
1721 if (rc == 0)
1722 rc = nsc_partsize(ip->bi_bmpfd, &bmp_size);
1723
1724 if (ip->bi_flags&DSW_SHDIMPORT)
1725 ip->bi_size = shd_size;
1726 else
1727 ip->bi_size = mst_size;
1728
1729 if ((((ip->bi_flags&DSW_SHDIMPORT) != DSW_SHDIMPORT) &&
1730 (mst_size < 1)) ||
1731 (((ip->bi_flags&DSW_SHDEXPORT) != DSW_SHDEXPORT) &&
1732 (shd_size < 1)) ||
1733 ((rc == 0) && (bmp_size < 1))) {
1734 /* could be really zero, or could be > 1 TB; fail the enable */
1735 rc = EINVAL;
1736 }
1737
1738 if (rc != 0) { /* rc set means an nsc_partsize() failed */
1739 /*
1740 * If existing group, mark bitmap as offline and set
1741 * bmp_size to "right size".
1742 */
1743 if (existing) {
1744 bmp_size = 2 * DSW_BM_FBA_LEN(mst_size) +
1745 DSW_SHD_BM_OFFSET;
1746 goto no_more_bmp_tests;
1747 }
1748 spcs_s_add(kstatus, rc);
1749 rc = DSW_EPARTSIZE;
1750 _ii_rlse_devs(ip, rtype);
1751 _ii_reserve_end(ip);
1752 goto fail;
1753 }
1754
1755 if (ip->bi_flags&DSW_SHDIMPORT)
1756 mst_size = shd_size;
1757 if (ip->bi_flags&DSW_SHDEXPORT)
1758 shd_size = mst_size;
1759 /*
1760 * Check with RDC if the master & shadow sizes are different.
1761 * Once II is enabled, the shadow size will be made to appear
1762 * the same as the master, and this will panic RDC if we're
1763 * changing sizes on it.
1764 */
1765 resized = (shd_size != mst_size);
1766 if (resized && ii_need_same_size(ip)) {
1767 cmn_err(CE_WARN, "!Cannot enable II set: would change volume "
1768 "size on RDC");
1769 rc = DSW_EOPACKAGE;
1770 _ii_rlse_devs(ip, rtype);
1771 _ii_reserve_end(ip);
1772 goto fail;
1773 }
1774 if (bmp_size < 2 * DSW_BM_FBA_LEN(mst_size) + DSW_SHD_BM_OFFSET) {
1775 /* bitmap volume too small */
1776 if (ii_debug > 0)
1777 cmn_err(CE_NOTE,
1778 "!ii: invalid sizes: bmp %" NSC_SZFMT " mst %"
1779 NSC_SZFMT " %" NSC_SZFMT "",
1780 bmp_size, mst_size, DSW_BM_FBA_LEN(mst_size));
1781 rc = DSW_EBMPSIZE;
1782 _ii_rlse_devs(ip, rtype);
1783 _ii_reserve_end(ip);
1784 goto fail;
1785 }
1786 if ((shd_size < mst_size) && (uconf.flag&DSW_GOLDEN) != 0) {
1787 /* shadow volume too small */
1788 if (ii_debug > 0)
1789 cmn_err(CE_NOTE, "!shd size too small (%" NSC_SZFMT
1790 ") for independent set's master (%" NSC_SZFMT ")",
1791 shd_size, mst_size);
1792 rc = DSW_ESHDSIZE;
1793 _ii_rlse_devs(ip, rtype);
1794 _ii_reserve_end(ip);
1795 goto fail;
1796 }
1797
1798 ip->bi_busy = kmem_zalloc(1 + (ip->bi_size / (DSW_SIZE * DSW_BITS)),
1799 KM_SLEEP);
1800 if (!ip->bi_busy) {
1801 rc = ENOMEM;
1802 _ii_rlse_devs(ip, rtype);
1803 _ii_reserve_end(ip);
1804 goto fail;
1805 }
1806
1807 if (existing == 0) {
1808
1809 DTRACE_PROBE(_ii_config);
1810
1811 /* first time this shadow has been set up */
1812 mutex_enter(&ip->bi_mutex);
1813 bm_header = _ii_bm_header_get(ip, &tmp);
1814 mutex_exit(&ip->bi_mutex);
1815 if (bm_header == NULL) {
1816 if (ii_debug > 0)
1817 cmn_err(CE_WARN,
1818 "!ii: _ii_bm_header_get returned NULL");
1819 rc = DSW_EHDRBMP;
1820 _ii_rlse_devs(ip, rtype);
1821 _ii_reserve_end(ip);
1822 goto fail;
1823 }
1824 bzero(bm_header, sizeof (*bm_header));
1825 /* copy pathnames into it */
1826 (void) strncpy(bm_header->master_vol, uconf.master_vol,
1827 DSW_NAMELEN);
1828 (void) strncpy(bm_header->shadow_vol, uconf.shadow_vol,
1829 DSW_NAMELEN);
1830 (void) strncpy(bm_header->bitmap_vol, uconf.bitmap_vol,
1831 DSW_NAMELEN);
1832 (void) strncpy(bm_header->clstr_name, uconf.cluster_tag,
1833 DSW_NAMELEN);
1834 (void) strncpy(bm_header->group_name, uconf.group_name,
1835 DSW_NAMELEN);
1836
1837 if (uconf.cluster_tag[0] != 0)
1838 (void) II_LINK_CLUSTER(ip, uconf.cluster_tag);
1839
1840 if (uconf.group_name[0] != 0)
1841 (void) II_LINK_GROUP(ip, uconf.group_name);
1842
1843
1844 bm_header->ii_state = (uconf.flag & DSW_GOLDEN);
1845 II_FLAG_ASSIGN(bm_header->ii_state, ip);
1846
1847 if (import) {
1848 II_FLAG_SETX(DSW_SHDIMPORT, ip);
1849 bm_header->ii_state |= DSW_SHDIMPORT;
1850 }
1851 if (resized) {
1852 II_FLAG_SETX(DSW_RESIZED, ip);
1853 bm_header->ii_state |= DSW_RESIZED;
1854 }
1855 bm_header->ii_type = (uconf.flag & DSW_GOLDEN) ?
1856 DSW_GOLDEN_TYPE : DSW_QUICK_TYPE;
1857 bm_header->ii_magic = DSW_DIRTY;
1858 bm_header->ii_version = II_HEADER_VERSION;
1859 bm_header->ii_shdfba = DSW_SHD_BM_OFFSET;
1860 bm_header->ii_copyfba = DSW_COPY_BM_OFFSET;
1861 bm_header->ii_throttle_delay = ip->bi_throttle_delay;
1862 bm_header->ii_throttle_unit = ip->bi_throttle_unit;
1863 ip->bi_shdfba = bm_header->ii_shdfba;
1864 ip->bi_copyfba = bm_header->ii_copyfba;
1865 ip->bi_mtime = ddi_get_time();
1866
1867 /* write it to disk */
1868 mutex_enter(&ip->bi_mutex);
1869 rc = _ii_bm_header_put(bm_header, ip, tmp);
1870 mutex_exit(&ip->bi_mutex);
1871 if (!II_SUCCESS(rc)) {
1872 spcs_s_add(kstatus, rc);
1873 rc = DSW_EHDRBMP;
1874 _ii_rlse_devs(ip, rtype);
1875 _ii_reserve_end(ip);
1876 goto fail;
1877 }
1878 if ((shd_size < mst_size) && (uconf.flag & DSW_GOLDEN) == 0) {
1879 /*
1880 * shadow volume smaller than master, must use a dependent
1881 * copy with a bitmap file stored mapping for chunk locations.
1882 */
1883 /* number of chunks in shadow volume */
1884 nsc_size_t shd_chunks;
1885 nsc_size_t bmp_chunks;
1886 nsc_size_t tmp_chunks;
1887
1888 if (ii_debug > 1)
1889 cmn_err(CE_NOTE, "!ii: using tree index on %s",
1890 uconf.master_vol);
1891 shd_chunks = shd_size / DSW_SIZE;
1892 /* do not add in partial chunk at end */
1893
1894 ip->bi_mstchks = mst_size / DSW_SIZE;
1895 if (mst_size % DSW_SIZE != 0)
1896 ip->bi_mstchks++;
1897 bmp_chunks = ii_btsize(bmp_size - ip->bi_copyfba -
1898 DSW_BM_FBA_LEN(ip->bi_size));
1899 tmp_chunks = ip->bi_copyfba +
1900 DSW_BM_FBA_LEN(ip->bi_size);
1901 if (bmp_chunks < (nsc_size_t)ip->bi_mstchks) {
1902 if (ii_debug > -1) {
1903 cmn_err(CE_NOTE, "!ii: bitmap vol too"
1904 "small: %" NSC_SZFMT " vs. %"
1905 NSC_SZFMT, bmp_size,
1906 tmp_chunks);
1907 }
1908 spcs_s_add(kstatus, rc);
1909 rc = DSW_EHDRBMP;
1910 _ii_rlse_devs(ip, rtype);
1911 _ii_reserve_end(ip);
1912 goto fail;
1913 }
1914 mutex_enter(&ip->bi_mutex);
1915 II_FLAG_SET(DSW_TREEMAP, ip);
1916 mutex_exit(&ip->bi_mutex);
1917
1918 /* following values are written to header by ii_tinit */
1919 #if (defined(NSC_MULTI_TERABYTE) && !defined(II_MULTIMULTI_TERABYTE))
1920 ASSERT(shd_chunks <= INT32_MAX);
1921 ASSERT(mst_size / DSW_SIZE <= INT32_MAX);
1922 #endif
1923 ip->bi_mstchks = mst_size / DSW_SIZE;
1924 if (mst_size % DSW_SIZE != 0)
1925 ip->bi_mstchks++;
1926 #ifdef II_MULTIMULTI_TERABYTE
1927 ip->bi_shdchks = shd_chunks;
1928 #else
1929 /* still have 31 bit chunkid's */
1930 ip->bi_shdchks = (chunkid_t)shd_chunks;
1931 #endif
1932 ip->bi_shdchkused = 0;
1933 rc = ii_tinit(ip);
1934 } else {
1935 ip->bi_shdchks = shd_size / DSW_SIZE;
1936 ip->bi_shdchkused = 0;
1937 }
1938 if (rc == 0)
1939 rc = II_LOAD_BMP(ip, 1);
1940 if (rc == 0)
1941 rc = II_ZEROBM(ip);
1942 if (rc == 0)
1943 rc = II_COPYBM(ip); /* also clear copy bitmap */
1944 if (rc == 0 && (uconf.flag & DSW_GOLDEN) && !import)
1945 rc = ii_fill_copy_bmp(ip);
1946 if (rc) {
1947 spcs_s_add(kstatus, rc);
1948 rc = DSW_EHDRBMP;
1949 _ii_rlse_devs(ip, rtype);
1950 goto fail;
1951 }
1952 /* check that changing shadow won't upset RDC */
1953 if (ii_update_denied(ip, kstatus, 0, 1)) {
1954 rc = DSW_EOPACKAGE;
1955 _ii_rlse_devs(ip, rtype);
1956 _ii_reserve_end(ip);
1957 goto fail;
1958 }
1959 ip->bi_disabled = 0; /* all okay and ready, we can go now */
1960 _ii_rlse_devs(ip, rtype);
1961 /* no _ii_reserve_end() here - we must register first */
1962 ip->bi_bmp_tok = _ii_register_path(ii_pathname(ip->bi_bmpfd),
1963 NSC_CACHE|NSC_DEVICE, _ii_io);
1964 if (!nshadows)
1965 ii_register_mst(ip);
1966 ii_register_shd(ip);
1967
1968 if (!ii_register_ok(ip)) {
1969 ip->bi_disabled = 1; /* argh */
1970 rc = DSW_EREGISTER;
1971 goto fail;
1972 }
1973 /* no _ii_reserve_begin() here -- we're still in process */
1974 (void) _ii_rsrv_devs(ip, rtype, II_INTERNAL);
1975
1976 if (ii_debug > 0)
1977 cmn_err(CE_NOTE, "!ii: config: master %s shadow %s",
1978 uconf.master_vol, uconf.shadow_vol);
1979 rc = 0;
1980 if ((uconf.flag & DSW_GOLDEN) && !import) {
1981 mutex_enter(&ip->bi_mutex);
1982 II_FLAG_SET(DSW_COPYINGM | DSW_COPYINGP, ip);
1983 ip->bi_ioctl++; /* we are effectively in an ioctl */
1984 mutex_exit(&ip->bi_mutex);
1985 rc = _ii_copyvol(ip, 0, rtype, kstatus, 1);
1986 }
1987 _ii_rlse_devs(ip, rtype);
1988 _ii_reserve_end(ip);
1989
1990 ++iigkstat.num_sets.value.ul;
1991
1992 return (spcs_s_ocopyoutf(&kstatus, uconf.status, rc));
1993 }
1994
1995 ip->bi_shdchks = shd_size / DSW_SIZE;
1996 ip->bi_shdfba = shdfba;
1997 ip->bi_copyfba = copyfba;
1998 rc = II_LOAD_BMP(ip, 0); /* reload saved bitmap */
1999 mutex_enter(&ip->bi_mutex);
2000 if (rc == 0)
2001 bm_header = _ii_bm_header_get(ip, &tmp);
2002 mutex_exit(&ip->bi_mutex);
2003 if (rc || bm_header == NULL) {
2004 if (existing) {
2005 goto no_more_bmp_tests;
2006 }
2007 rc = DSW_EHDRBMP;
2008 goto fail;
2009 }
2010
2011 /*
2012 * If the header is dirty and it wasn't kept on persistent storage
2013 * then the bitmaps must be assumed to be bad.
2014 */
2015 if (bm_header->ii_magic == DSW_DIRTY &&
2016 ip->bi_bitmap_ops != &alloc_buf_bmp) {
2017 type = bm_header->ii_type;
2018 _ii_bm_header_free(bm_header, ip, tmp);
2019 if (type == DSW_GOLDEN_TYPE) {
2020 if ((ip->bi_flags & DSW_COPYINGM) != 0)
2021 _ii_error(ip, DSW_SHDOFFLINE);
2022 else if ((ip->bi_flags & DSW_COPYINGS) != 0)
2023 _ii_error(ip, DSW_MSTOFFLINE);
2024 else {
2025 /* No copying, so they're just different */
2026 rc = ii_fill_copy_bmp(ip);
2027 if (rc) {
2028 spcs_s_add(kstatus, rc);
2029 rc = DSW_EHDRBMP;
2030 goto fail;
2031 }
2032 }
2033 } else
2034 _ii_error(ip, DSW_SHDOFFLINE);
2035
2036 mutex_enter(&ip->bi_mutex);
2037 bm_header = _ii_bm_header_get(ip, &tmp);
2038 mutex_exit(&ip->bi_mutex);
2039 if (bm_header == NULL) {
2040 rc = DSW_EHDRBMP;
2041 goto fail;
2042 }
2043 }
2044
2045 bm_header->ii_magic = DSW_DIRTY;
2046 mutex_enter(&ip->bi_mutex);
2047 rc = _ii_bm_header_put(bm_header, ip, tmp);
2048 mutex_exit(&ip->bi_mutex);
2049 if (!II_SUCCESS(rc)) {
2050 spcs_s_add(kstatus, rc);
2051 rc = DSW_EHDRBMP;
2052 goto fail;
2053 }
2054
2055 ip->bi_bmp_tok = _ii_register_path(ii_pathname(ip->bi_bmpfd),
2056 NSC_CACHE|NSC_DEVICE, _ii_io);
2057 no_more_bmp_tests:
2058 _ii_rlse_devs(ip, rtype);
2059 ip->bi_disabled = 0; /* all okay and ready, we can go now */
2060 if (!nshadows)
2061 ii_register_mst(ip);
2062 if ((ip->bi_flags & DSW_SHDEXPORT) == 0)
2063 ii_register_shd(ip);
2064
2065 if (!ii_register_ok(ip)) {
2066 rc = DSW_EREGISTER;
2067 goto fail;
2068 }
2069 _ii_reserve_end(ip);
2070
2071 if (ii_debug > 0)
2072 cmn_err(CE_NOTE, "!ii: config: master %s shadow %s",
2073 uconf.master_vol, uconf.shadow_vol);
2074
2075 rc = 0;
2076 if (ip->bi_flags & DSW_COPYINGP) {
2077 /* Copy was in progress, so continue it */
2078 (void) _ii_rsrv_devs(ip, rtype, II_INTERNAL);
2079 mutex_enter(&ip->bi_mutex);
2080 ip->bi_ioctl++; /* we are effectively in an ioctl */
2081 mutex_exit(&ip->bi_mutex);
2082 rc = _ii_copyvol(ip, ((ip->bi_flags & DSW_COPYINGS) != 0) ?
2083 CV_SHD2MST : 0, rtype, kstatus, 0);
2084 }
2085
2086 ++iigkstat.num_sets.value.ul;
2087
2088 return (spcs_s_ocopyoutf(&kstatus, uconf.status, rc));
2089
2090 fail:
2091 /* remove ip from _ii_info_top linked list */
2092 mutex_enter(&_ii_info_mutex);
2093 for (ipp = &_ii_info_top; *ipp; ipp = &((*ipp)->bi_next)) {
2094 if (ip == *ipp) {
2095 *ipp = ip->bi_next;
2096 break;
2097 }
2098 }
2099 mutex_exit(&_ii_info_mutex);
2100 ii_sibling_free(ip);
2101
2102 return (spcs_s_ocopyoutf(&kstatus, uconf.status, rc));
2103 }
2104
2105 static int
_ii_perform_disable(char * setname,spcs_s_info_t * kstatusp,int reclaim)2106 _ii_perform_disable(char *setname, spcs_s_info_t *kstatusp, int reclaim)
2107 {
2108 _ii_info_t **xip, *ip;
2109 _ii_overflow_t *op;
2110 nsc_buf_t *tmp = NULL;
2111 int rc;
2112 ii_header_t *bm_header;
2113 int rtype;
2114
2115 mutex_enter(&_ii_info_mutex);
2116 ip = _ii_find_set(setname);
2117 if (ip == NULL) {
2118 mutex_exit(&_ii_info_mutex);
2119 return (DSW_ENOTFOUND);
2120 }
2121
2122 if ((ip->bi_flags & DSW_GOLDEN) &&
2123 ((ip->bi_flags & DSW_COPYINGP) != 0)) {
2124 /*
2125 * Cannot disable an independent copy while still copying
2126 * as it means that a data dependency exists.
2127 */
2128 mutex_exit(&_ii_info_mutex);
2129 _ii_ioctl_done(ip);
2130 mutex_exit(&ip->bi_mutex);
2131 DTRACE_PROBE(_ii_perform_disable_end_DSW_EDEPENDENCY);
2132 return (DSW_EDEPENDENCY);
2133 }
2134
2135 if ((ip->bi_flags & DSW_GOLDEN) == 0 &&
2136 ii_update_denied(ip, *kstatusp, 0, 1)) {
2137 /* Cannot disable a dependent shadow while RDC is unsure */
2138 mutex_exit(&_ii_info_mutex);
2139 _ii_ioctl_done(ip);
2140 mutex_exit(&ip->bi_mutex);
2141 DTRACE_PROBE(DSW_EOPACKAGE);
2142 return (DSW_EOPACKAGE);
2143 }
2144
2145 if (((ip->bi_flags & DSW_RESIZED) == DSW_RESIZED) &&
2146 ii_need_same_size(ip)) {
2147 /* We can't disable the set whilst RDC is using it */
2148 mutex_exit(&_ii_info_mutex);
2149 _ii_ioctl_done(ip);
2150 mutex_exit(&ip->bi_mutex);
2151 cmn_err(CE_WARN, "!Cannot disable II set: would change "
2152 "volume size on RDC");
2153 DTRACE_PROBE(DSW_EOPACKAGE_resize);
2154 return (DSW_EOPACKAGE);
2155 }
2156
2157 ip->bi_disabled = 1;
2158 if (NSHADOWS(ip) && (ip->bi_master == ip)) {
2159 ip->bi_flags &= (~DSW_COPYING);
2160 ip->bi_state |= DSW_MULTIMST;
2161 }
2162 mutex_exit(&_ii_info_mutex);
2163
2164 _ii_ioctl_done(ip);
2165 mutex_exit(&ip->bi_mutex);
2166
2167 _ii_stopvol(ip);
2168
2169 rtype = SHDR|BMP;
2170 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
2171 spcs_s_add(*kstatusp, rc);
2172 DTRACE_PROBE(DSW_ERSRVFAIL);
2173 return (DSW_ERSRVFAIL);
2174 }
2175
2176 if ((ii_header < 128) &&
2177 (((ip->bi_flags & DSW_GOLDEN) == 0) ||
2178 (ip->bi_flags & DSW_COPYING))) {
2179 /*
2180 * Not a full copy so attempt to prevent use of partial copy
2181 * by clearing where the first ufs super-block would be
2182 * located. Solaris often incorporates the disk header into
2183 * the start of the first slice, so avoid clearing the very
2184 * first 16 blocks of the volume.
2185 */
2186
2187 if (ii_debug > 1)
2188 cmn_err(CE_NOTE, "!ii: Shadow copy invalidated");
2189 II_READ_START(ip, shadow);
2190 rc = nsc_alloc_buf(SHDFD(ip), ii_header, 128 - ii_header,
2191 NSC_RDWRBUF, &tmp);
2192 II_READ_END(ip, shadow, rc, 128 - ii_header);
2193 if (II_SUCCESS(rc)) {
2194 rc = nsc_zero(tmp, ii_header, 128 - ii_header, 0);
2195 if (II_SUCCESS(rc)) {
2196 II_NSC_WRITE(ip, shadow, rc, tmp, ii_header,
2197 (128 - ii_header), 0);
2198 }
2199 }
2200 if (tmp)
2201 (void) nsc_free_buf(tmp);
2202 if (!II_SUCCESS(rc))
2203 _ii_error(ip, DSW_SHDOFFLINE);
2204 }
2205
2206 /* this rw_enter forces us to drain all active IO */
2207 rw_enter(&ip->bi_linkrw, RW_WRITER);
2208 rw_exit(&ip->bi_linkrw);
2209
2210 /* remove ip from _ii_info_top linked list */
2211 mutex_enter(&_ii_info_mutex);
2212 for (xip = &_ii_info_top; *xip; xip = &((*xip)->bi_next)) {
2213 if (ip == *xip) {
2214 *xip = ip->bi_next;
2215 break;
2216 }
2217 }
2218 if (ip->bi_kstat) {
2219 kstat_delete(ip->bi_kstat);
2220 ip->bi_kstat = NULL;
2221 }
2222 mutex_exit(&_ii_info_mutex);
2223
2224 rc = II_SAVE_BMP(ip, 1);
2225 mutex_enter(&ip->bi_mutex);
2226 if (rc == 0)
2227 bm_header = _ii_bm_header_get(ip, &tmp);
2228 if (rc == 0 && bm_header) {
2229 if (ii_debug > 1)
2230 cmn_err(CE_NOTE, "!ii: Invalid header written");
2231 bm_header->ii_magic = DSW_INVALID;
2232 /* write it to disk */
2233 (void) _ii_bm_header_put(bm_header, ip, tmp);
2234 }
2235 mutex_exit(&ip->bi_mutex);
2236
2237 op = ip->bi_overflow;
2238 if (op && (reclaim == -1)) {
2239 reclaim = (op->ii_drefcnt == 1? NO_RECLAIM : RECLAIM);
2240 }
2241
2242 if ((op != NULL) && (op->ii_hversion >= 1) &&
2243 (op->ii_hmagic == II_OMAGIC)) {
2244 mutex_enter(&_ii_overflow_mutex);
2245 if (ip->bi_flags & DSW_OVRHDRDRTY) {
2246 mutex_enter(&ip->bi_mutex);
2247 ip->bi_flags &= ~DSW_OVRHDRDRTY;
2248 mutex_exit(&ip->bi_mutex);
2249 ASSERT(op->ii_urefcnt > 0);
2250 op->ii_urefcnt--;
2251 }
2252 if (op->ii_urefcnt == 0) {
2253 op->ii_flags &= ~IIO_CNTR_INVLD;
2254 op->ii_unused = op->ii_nchunks - 1;
2255 }
2256 mutex_exit(&_ii_overflow_mutex);
2257 }
2258 ii_overflow_free(ip, reclaim);
2259 _ii_rlse_devs(ip, rtype);
2260
2261 ii_sibling_free(ip);
2262
2263 --iigkstat.num_sets.value.ul;
2264 return (0);
2265 }
2266
2267 /*
2268 * _ii_disable
2269 * Deconfigures an II pair
2270 *
2271 * Calling/Exit State:
2272 * Returns 0 if the pair was disabled. Otherwise an error code
2273 * is returned and any additional error information is copied
2274 * out to the user.
2275 *
2276 * Description:
2277 * Reads the user configuration structure and attempts to
2278 * deconfigure that pairing based on the master device pathname.
2279 */
2280
2281 int
_ii_disable(intptr_t arg,int ilp32,int * rvp)2282 _ii_disable(intptr_t arg, int ilp32, int *rvp)
2283 {
2284 dsw_ioctl_t uparms;
2285 dsw_ioctl32_t uparms32;
2286 _ii_overflow_t *op;
2287 int rc, rerr;
2288 spcs_s_info_t kstatus;
2289 uint64_t hash;
2290 int reclaim;
2291 _ii_lsthead_t *oldhead, **head;
2292 _ii_lstinfo_t *np, **xnp, *oldp;
2293
2294 *rvp = 0;
2295
2296 if (ilp32) {
2297 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
2298 return (EFAULT);
2299 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
2300 uparms.status = (spcs_s_info_t)uparms32.status;
2301 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
2302 return (EFAULT);
2303
2304 kstatus = spcs_s_kcreate();
2305 if (kstatus == NULL)
2306 return (ENOMEM);
2307
2308 if (!uparms.shadow_vol[0])
2309 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
2310
2311 DTRACE_PROBE2(_ii_disable_info, char *, uparms.shadow_vol,
2312 int, uparms.flags);
2313
2314 /* group or single set? */
2315 if (uparms.flags & CV_IS_GROUP) {
2316 hash = nsc_strhash(uparms.shadow_vol);
2317 mutex_enter(&_ii_group_mutex);
2318 for (head = &_ii_group_top; *head;
2319 head = &((*head)->lst_next)) {
2320 if ((hash == (*head)->lst_hash) &&
2321 strncmp((*head)->lst_name, uparms.shadow_vol,
2322 DSW_NAMELEN) == 0)
2323 break;
2324 }
2325
2326 if (!*head) {
2327 mutex_exit(&_ii_group_mutex);
2328 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2329 DSW_EGNOTFOUND));
2330 }
2331
2332 /* clear any overflow vol usage counts */
2333 for (np = (*head)->lst_start; np; np = np->lst_next) {
2334 if (np->lst_ip->bi_overflow) {
2335 np->lst_ip->bi_overflow->ii_detachcnt = 0;
2336 }
2337 }
2338
2339 /* now increment */
2340 for (np = (*head)->lst_start; np; np = np->lst_next) {
2341 if (np->lst_ip->bi_overflow) {
2342 ++np->lst_ip->bi_overflow->ii_detachcnt;
2343 }
2344 }
2345
2346 /* finally, disable all group members */
2347 rerr = 0;
2348 xnp = &(*head)->lst_start;
2349 while (*xnp) {
2350 op = (*xnp)->lst_ip->bi_overflow;
2351 if (op) {
2352 reclaim = (op->ii_drefcnt == op->ii_detachcnt?
2353 NO_RECLAIM : RECLAIM);
2354 --op->ii_detachcnt;
2355 }
2356
2357 /* clear out the group pointer */
2358 (*xnp)->lst_ip->bi_group = NULL;
2359
2360 rc = _ii_perform_disable((*xnp)->lst_ip->bi_keyname,
2361 &kstatus, reclaim);
2362 if (rc) {
2363 /* restore group name */
2364 (*xnp)->lst_ip->bi_group = (*head)->lst_name;
2365
2366 /* restore detachcnt */
2367 if (op) {
2368 ++op->ii_detachcnt;
2369 }
2370
2371 /* don't delete branch */
2372 ++rerr;
2373 spcs_s_add(kstatus, rc);
2374
2375 /* move forward in linked list */
2376 xnp = &(*xnp)->lst_next;
2377 } else {
2378 oldp = (*xnp);
2379 *xnp = (*xnp)->lst_next;
2380 kmem_free(oldp, sizeof (_ii_lstinfo_t));
2381 }
2382 }
2383 if (rerr) {
2384 mutex_exit(&_ii_group_mutex);
2385 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2386 DSW_EDISABLE));
2387 }
2388 /* no errors, all sets disabled, OK to free list head */
2389 oldhead = *head;
2390 *head = (*head)->lst_next;
2391 kmem_free(oldhead, sizeof (_ii_lsthead_t));
2392 mutex_exit(&_ii_group_mutex);
2393 } else {
2394 /* only a single set is being disabled */
2395 rc = _ii_perform_disable(uparms.shadow_vol, &kstatus, -1);
2396 if (rc)
2397 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
2398 }
2399
2400 spcs_s_kfree(kstatus);
2401
2402 return (0);
2403 }
2404
2405
2406 /*
2407 * _ii_stat
2408 * Get state of the shadow.
2409 *
2410 * Calling/Exit State:
2411 * Returns 0 on success, otherwise an error code is returned
2412 * and any additional error information is copied out to the user.
2413 * The size variable in the dsw_stat_t is set to the FBA size
2414 * of the volume, the stat variable is set to the state, and
2415 * the structure is copied out.
2416 */
2417 /*ARGSUSED*/
2418 int
_ii_stat(intptr_t arg,int ilp32,int * rvp)2419 _ii_stat(intptr_t arg, int ilp32, int *rvp)
2420 {
2421 dsw_stat_t ustat;
2422 dsw_stat32_t ustat32;
2423 _ii_info_t *ip;
2424 spcs_s_info_t kstatus;
2425 char *group, *cluster;
2426
2427 if (ilp32) {
2428 if (copyin((void *)arg, &ustat32, sizeof (ustat32)) < 0)
2429 return (EFAULT);
2430 II_TAIL_COPY(ustat, ustat32, shadow_vol, dsw_stat_t);
2431 ustat.status = (spcs_s_info_t)ustat32.status;
2432 } else if (copyin((void *)arg, &ustat, sizeof (ustat)) < 0)
2433 return (EFAULT);
2434
2435 kstatus = spcs_s_kcreate();
2436 if (kstatus == NULL)
2437 return (ENOMEM);
2438
2439 if (!ustat.shadow_vol[0])
2440 return (spcs_s_ocopyoutf(&kstatus, ustat.status, DSW_EEMPTY));
2441
2442 mutex_enter(&_ii_info_mutex);
2443 ip = _ii_find_set(ustat.shadow_vol);
2444 mutex_exit(&_ii_info_mutex);
2445 if (ip == NULL)
2446 return (spcs_s_ocopyoutf(&kstatus, ustat.status,
2447 DSW_ENOTFOUND));
2448
2449 ustat.stat = ip->bi_flags;
2450 ustat.size = ip->bi_size;
2451 ustat.mtime = ip->bi_mtime;
2452
2453 if (ilp32)
2454 bzero(ustat32.overflow_vol, DSW_NAMELEN);
2455 else
2456 bzero(ustat.overflow_vol, DSW_NAMELEN);
2457 if (ip->bi_overflow) {
2458 (void) strncpy(ilp32 ? ustat32.overflow_vol :
2459 ustat.overflow_vol, ip->bi_overflow->ii_volname,
2460 DSW_NAMELEN);
2461 }
2462
2463 ustat.shdsize = ip->bi_shdchks;
2464 if ((ip->bi_flags) & DSW_TREEMAP) {
2465 ustat.shdused = ip->bi_shdchkused;
2466 } else {
2467 ustat.shdused = 0;
2468 }
2469
2470 /* copy over group and cluster associations */
2471 group = ilp32? ustat32.group_name : ustat.group_name;
2472 cluster = ilp32? ustat32.cluster_tag : ustat.cluster_tag;
2473 bzero(group, DSW_NAMELEN);
2474 bzero(cluster, DSW_NAMELEN);
2475 if (ip->bi_group)
2476 (void) strncpy(group, ip->bi_group, DSW_NAMELEN);
2477 if (ip->bi_cluster)
2478 (void) strncpy(cluster, ip->bi_cluster, DSW_NAMELEN);
2479
2480 _ii_ioctl_done(ip);
2481 mutex_exit(&ip->bi_mutex);
2482
2483 spcs_s_kfree(kstatus);
2484 if (ilp32) {
2485 ustat32.stat = ustat.stat;
2486 ustat32.size = ustat.size;
2487 ustat32.shdsize = ustat.shdsize;
2488 ustat32.shdused = ustat.shdused;
2489 ustat32.mtime = ustat.mtime;
2490 if (copyout(&ustat32, (void *)arg, sizeof (ustat32)))
2491 return (EFAULT);
2492 } else if (copyout(&ustat, (void *)arg, sizeof (ustat)))
2493 return (EFAULT);
2494
2495 return (0);
2496 }
2497
2498
2499 /*
2500 * _ii_list
2501 * List what shadow sets are currently configured.
2502 *
2503 * Calling/Exit State:
2504 * Returns 0 on success, otherwise an error code is returned
2505 * and any additional error information is copied out to the user.
2506 */
2507 /*ARGSUSED*/
2508 int
_ii_list(intptr_t arg,int ilp32,int * rvp)2509 _ii_list(intptr_t arg, int ilp32, int *rvp)
2510 {
2511 dsw_list_t ulist;
2512 dsw_list32_t ulist32;
2513 _ii_info_t *ip;
2514 dsw_config_t cf, *cfp;
2515 dsw_config32_t cf32, *cf32p;
2516 int rc;
2517 int used;
2518 spcs_s_info_t kstatus;
2519
2520 if (ilp32) {
2521 if (copyin((void *)arg, &ulist32, sizeof (ulist32)) < 0)
2522 return (EFAULT);
2523 II_TAIL_COPY(ulist, ulist32, list_size, dsw_list_t);
2524 ulist.status = (spcs_s_info_t)ulist32.status;
2525 } else if (copyin((void *)arg, &ulist, sizeof (ulist)) < 0)
2526 return (EFAULT);
2527
2528 kstatus = spcs_s_kcreate();
2529 if (kstatus == NULL)
2530 return (ENOMEM);
2531
2532 cf32p = (dsw_config32_t *)(unsigned long)ulist32.list;
2533 cfp = ulist.list;
2534 ulist.list_used = 0;
2535 mutex_enter(&_ii_info_mutex);
2536 ip = _ii_info_top;
2537
2538 DTRACE_PROBE1(_ii_list_count, int, ulist.list_size);
2539
2540 for (rc = used = 0; used < ulist.list_size && ip; ip = ip->bi_next) {
2541
2542 if (ip->bi_disabled)
2543 continue;
2544
2545 mutex_enter(&ip->bi_mutex);
2546 ip->bi_ioctl++;
2547 if (ilp32) {
2548 bzero(&cf32, sizeof (cf32));
2549 cf32.flag = ip->bi_flags;
2550 (void) strncpy(cf32.master_vol,
2551 ii_pathname(ip->bi_mstfd), DSW_NAMELEN);
2552 (void) strncpy(cf32.shadow_vol,
2553 ip->bi_keyname, DSW_NAMELEN);
2554 (void) strncpy(cf32.bitmap_vol, (ip->bi_bmpfd)
2555 ? ii_pathname(ip->bi_bmpfd)
2556 : "<offline_bitmap>", DSW_NAMELEN);
2557 if (copyout(&cf32, (void *)cf32p, sizeof (cf32)))
2558 rc = EFAULT;
2559 cf32p++;
2560 } else {
2561 bzero(&cf, sizeof (cf));
2562 cf.flag = ip->bi_flags;
2563 (void) strncpy(cf.master_vol,
2564 ii_pathname(ip->bi_mstfd), DSW_NAMELEN);
2565 (void) strncpy(cf.shadow_vol,
2566 ip->bi_keyname, DSW_NAMELEN);
2567 (void) strncpy(cf.bitmap_vol, (ip->bi_bmpfd)
2568 ? ii_pathname(ip->bi_bmpfd)
2569 : "<offline_bitmap>", DSW_NAMELEN);
2570 if (copyout(&cf, (void *)cfp, sizeof (cf)))
2571 rc = EFAULT;
2572 cfp++;
2573 }
2574 _ii_ioctl_done(ip);
2575 mutex_exit(&ip->bi_mutex);
2576 used++;
2577 }
2578 mutex_exit(&_ii_info_mutex);
2579
2580 spcs_s_kfree(kstatus);
2581 if (rc)
2582 return (rc);
2583
2584 ulist.list_used = used;
2585 if (ilp32) {
2586 ulist32.list_used = ulist.list_used;
2587 if (copyout(&ulist32, (void *)arg, sizeof (ulist32)))
2588 return (EFAULT);
2589 } else if (copyout(&ulist, (void *)arg, sizeof (ulist)))
2590 return (EFAULT);
2591
2592 return (0);
2593 }
2594
2595 /*
2596 * _ii_listlen
2597 * Counts the number of items the DSWIOC_LIST and DSWIOC_OLIST
2598 * ioctl calls would return.
2599 *
2600 * Calling/Exit State:
2601 * Returns 0 on success, otherwise an error code is returned.
2602 * Result is returned as successful ioctl value.
2603 */
2604 /*ARGSUSED*/
2605 int
_ii_listlen(int cmd,int ilp32,int * rvp)2606 _ii_listlen(int cmd, int ilp32, int *rvp)
2607 {
2608 _ii_info_t *ip;
2609 _ii_overflow_t *op;
2610 int count = 0;
2611
2612 switch (cmd) {
2613
2614 case DSWIOC_LISTLEN:
2615 mutex_enter(&_ii_info_mutex);
2616 for (ip = _ii_info_top; ip; ip = ip->bi_next) {
2617 if (ip->bi_disabled == 0) {
2618 count++;
2619 }
2620 }
2621 mutex_exit(&_ii_info_mutex);
2622 break;
2623 case DSWIOC_OLISTLEN:
2624 mutex_enter(&_ii_overflow_mutex);
2625 for (op = _ii_overflow_top; op; op = op->ii_next)
2626 count++;
2627 mutex_exit(&_ii_overflow_mutex);
2628 break;
2629 default:
2630 return (EINVAL);
2631 }
2632 *rvp = count;
2633
2634 return (0);
2635 }
2636
2637 /*
2638 * _ii_report_bmp
2639 *
2640 * Report to the user daemon that the bitmap has gone bad
2641 */
2642 static int
_ii_report_bmp(_ii_info_t * ip)2643 _ii_report_bmp(_ii_info_t *ip)
2644 {
2645 int rc;
2646 struct nskernd *nsk;
2647
2648 nsk = kmem_zalloc(sizeof (*nsk), KM_SLEEP);
2649 if (!nsk) {
2650 return (ENOMEM);
2651 }
2652 nsk->command = NSKERND_IIBITMAP;
2653 nsk->data1 = (int64_t)(ip->bi_flags | DSW_BMPOFFLINE);
2654 (void) strncpy(nsk->char1, ip->bi_keyname,
2655 min(DSW_NAMELEN, NSC_MAXPATH));
2656
2657 rc = nskernd_get(nsk);
2658 if (rc == 0) {
2659 rc = (int)nsk->data1;
2660 }
2661 if (rc == 0) {
2662 DTRACE_PROBE(_ii_report_bmp_end);
2663 } else {
2664 DTRACE_PROBE1(_ii_report_bmp_end_2, int, rc);
2665 }
2666 kmem_free(nsk, sizeof (*nsk));
2667 return (rc);
2668 }
2669
2670 /*
2671 * _ii_offline
2672 * Set volume offline flag(s) for a shadow.
2673 *
2674 * Calling/Exit State:
2675 * Returns 0 on success, otherwise an error code is returned
2676 * and any additional error information is copied out to the user.
2677 */
2678 /*ARGSUSED*/
2679 int
_ii_offline(intptr_t arg,int ilp32,int * rvp)2680 _ii_offline(intptr_t arg, int ilp32, int *rvp)
2681 {
2682 dsw_ioctl_t uparms;
2683 dsw_ioctl32_t uparms32;
2684 _ii_info_t *ip;
2685 int rc;
2686 spcs_s_info_t kstatus;
2687
2688 if (ilp32) {
2689 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
2690 return (EFAULT);
2691 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
2692 uparms.status = (spcs_s_info_t)uparms32.status;
2693 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
2694 return (EFAULT);
2695
2696 kstatus = spcs_s_kcreate();
2697 if (kstatus == NULL)
2698 return (ENOMEM);
2699
2700 if (!uparms.shadow_vol[0])
2701 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
2702
2703 mutex_enter(&_ii_info_mutex);
2704 ip = _ii_find_set(uparms.shadow_vol);
2705 mutex_exit(&_ii_info_mutex);
2706 if (ip == NULL)
2707 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2708 DSW_ENOTFOUND));
2709
2710 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
2711 _ii_ioctl_done(ip);
2712 mutex_exit(&ip->bi_mutex);
2713 spcs_s_add(kstatus, rc);
2714 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2715 DSW_ERSRVFAIL));
2716 }
2717
2718 mutex_exit(&ip->bi_mutex);
2719 _ii_error(ip, uparms.flags & DSW_OFFLINE);
2720 mutex_enter(&ip->bi_mutex);
2721 _ii_ioctl_done(ip);
2722 mutex_exit(&ip->bi_mutex);
2723
2724 _ii_rlse_devs(ip, BMP);
2725
2726 spcs_s_kfree(kstatus);
2727
2728 return (0);
2729 }
2730
2731
2732 /*
2733 * _ii_wait
2734 * Wait for a copy to complete.
2735 *
2736 * Calling/Exit State:
2737 * Returns 0 if the copy completed, otherwise error code.
2738 *
2739 */
2740 /*ARGSUSED*/
2741 int
_ii_wait(intptr_t arg,int ilp32,int * rvp)2742 _ii_wait(intptr_t arg, int ilp32, int *rvp)
2743 {
2744 dsw_ioctl_t uparms;
2745 dsw_ioctl32_t uparms32;
2746 _ii_info_t *ip;
2747 int rc = 0;
2748 spcs_s_info_t kstatus;
2749
2750 if (ilp32) {
2751 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
2752 return (EFAULT);
2753 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
2754 uparms.status = (spcs_s_info_t)uparms32.status;
2755 uparms.pid = uparms32.pid;
2756 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
2757 return (EFAULT);
2758
2759 kstatus = spcs_s_kcreate();
2760 if (kstatus == NULL)
2761 return (ENOMEM);
2762
2763 if (!uparms.shadow_vol[0])
2764 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
2765
2766 mutex_enter(&_ii_info_mutex);
2767 ip = _ii_find_set(uparms.shadow_vol);
2768 mutex_exit(&_ii_info_mutex);
2769 if (ip == NULL)
2770 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2771 DSW_ENOTFOUND));
2772
2773 while (ip->bi_flags & DSW_COPYINGP) {
2774 if (cv_wait_sig(&ip->bi_copydonecv, &ip->bi_mutex) == 0) {
2775 /* Awoken by a signal */
2776 rc = EINTR;
2777 break;
2778 }
2779 }
2780
2781 /* Is this an attempt to unlock the copy/update PID? */
2782 if (uparms.flags & CV_LOCK_PID) {
2783 if (ip->bi_locked_pid == 0) {
2784 rc = DSW_ENOTLOCKED;
2785 } else if (uparms.pid == -1) {
2786 cmn_err(CE_WARN, "!ii: Copy/Update PID %d, cleared",
2787 ip->bi_locked_pid);
2788 ip->bi_locked_pid = 0;
2789 } else if (uparms.pid != ip->bi_locked_pid) {
2790 rc = DSW_EINUSE;
2791 } else {
2792 ip->bi_locked_pid = 0;
2793 }
2794 }
2795
2796 _ii_ioctl_done(ip);
2797 mutex_exit(&ip->bi_mutex);
2798
2799 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
2800 }
2801
2802
2803 static int
_ii_reset_mstvol(_ii_info_t * ip)2804 _ii_reset_mstvol(_ii_info_t *ip)
2805 {
2806 _ii_info_t *xip;
2807
2808 if (!NSHADOWS(ip))
2809 return (DSW_COPYINGS | DSW_COPYINGP);
2810
2811 /* check for siblings updating master */
2812 for (xip = ip->bi_head; xip; xip = xip->bi_sibling) {
2813 if (xip == ip)
2814 continue;
2815 /* check if master is okay */
2816 if ((xip->bi_flags & DSW_MSTOFFLINE) == 0) {
2817 return (0);
2818 }
2819 }
2820
2821 return (DSW_COPYINGS | DSW_COPYINGP);
2822 }
2823
2824 /*
2825 * _ii_reset
2826 * Reset offlined underlying volumes
2827 *
2828 * Calling/Exit State:
2829 * Returns 0 on success, otherwise an error code is returned
2830 * and any additional error information is copied out to the user.
2831 */
2832 /*ARGSUSED*/
2833 int
_ii_reset(intptr_t arg,int ilp32,int * rvp)2834 _ii_reset(intptr_t arg, int ilp32, int *rvp)
2835 {
2836 dsw_ioctl_t uparms;
2837 dsw_ioctl32_t uparms32;
2838 _ii_info_t *ip;
2839 nsc_buf_t *tmp = NULL;
2840 int rc;
2841 int flags;
2842 ii_header_t *bm_header;
2843 spcs_s_info_t kstatus;
2844 int rtype;
2845
2846 if (ilp32) {
2847 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
2848 return (EFAULT);
2849 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
2850 uparms.status = (spcs_s_info_t)uparms32.status;
2851 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
2852 return (EFAULT);
2853
2854 kstatus = spcs_s_kcreate();
2855 if (kstatus == NULL)
2856 return (ENOMEM);
2857
2858 if (!uparms.shadow_vol[0])
2859 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
2860
2861 mutex_enter(&_ii_info_mutex);
2862 ip = _ii_find_set(uparms.shadow_vol);
2863 mutex_exit(&_ii_info_mutex);
2864 if (ip == NULL)
2865 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2866 DSW_ENOTFOUND));
2867
2868 mutex_exit(&ip->bi_mutex);
2869
2870 /* Figure out what to do according to what was flagged as */
2871
2872 if ((ip->bi_flags & DSW_OFFLINE) == 0) {
2873 /* Nothing offline, so no op */
2874 mutex_enter(&ip->bi_mutex);
2875 _ii_ioctl_done(ip);
2876 mutex_exit(&ip->bi_mutex);
2877 spcs_s_kfree(kstatus);
2878 return (0);
2879 }
2880
2881 if (!ip->bi_bmpfd) {
2882 /* No bitmap fd, can't do anything */
2883 mutex_enter(&ip->bi_mutex);
2884 _ii_ioctl_done(ip);
2885 mutex_exit(&ip->bi_mutex);
2886 spcs_s_kfree(kstatus);
2887 return (DSW_EHDRBMP);
2888 }
2889
2890 rtype = MSTR|SHDR|BMP;
2891 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
2892 mutex_enter(&ip->bi_mutex);
2893 _ii_ioctl_done(ip);
2894 mutex_exit(&ip->bi_mutex);
2895 spcs_s_add(kstatus, rc);
2896 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
2897 DSW_ERSRVFAIL));
2898 }
2899
2900 /*
2901 * Cannot use _ii_bm_header_get as it will fail if DSW_BMPOFFLINE
2902 */
2903 II_READ_START(ip, bitmap);
2904 rc = nsc_alloc_buf(ip->bi_bmpfd, 0, FBA_LEN(sizeof (ii_header_t)),
2905 NSC_RDWRBUF, &tmp);
2906 II_READ_END(ip, bitmap, rc, FBA_LEN(sizeof (ii_header_t)));
2907 if (!II_SUCCESS(rc)) {
2908 _ii_rlse_devs(ip, rtype);
2909 mutex_enter(&ip->bi_mutex);
2910 _ii_ioctl_done(ip);
2911 mutex_exit(&ip->bi_mutex);
2912 if (tmp)
2913 (void) nsc_free_buf(tmp);
2914 _ii_error(ip, DSW_BMPOFFLINE);
2915 spcs_s_add(kstatus, rc);
2916 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EHDRBMP));
2917 }
2918
2919 bm_header = (ii_header_t *)(tmp)->sb_vec[0].sv_addr;
2920 if (bm_header == NULL) {
2921 _ii_rlse_devs(ip, rtype);
2922 mutex_enter(&ip->bi_mutex);
2923 _ii_ioctl_done(ip);
2924 mutex_exit(&ip->bi_mutex);
2925 if (tmp)
2926 (void) nsc_free_buf(tmp);
2927 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EHDRBMP));
2928 }
2929
2930 flags = ip->bi_flags & ~DSW_COPY_FLAGS;
2931 if ((flags & (DSW_SHDIMPORT|DSW_SHDEXPORT)) == 0) {
2932 if (((flags & DSW_SHDOFFLINE) == 0) &&
2933 ((flags & DSW_MSTOFFLINE) == DSW_MSTOFFLINE)) {
2934 /* Shadow was OK but master was offline */
2935 flags |= _ii_reset_mstvol(ip);
2936 } else if ((flags & DSW_SHDOFFLINE) == DSW_SHDOFFLINE) {
2937 /* Shadow was offline, don't care what the master was */
2938 flags |= (DSW_COPYINGM | DSW_COPYINGP);
2939 }
2940 }
2941 if (ip->bi_flags & DSW_VOVERFLOW) {
2942 ip->bi_flags &= ~DSW_VOVERFLOW;
2943 ip->bi_flags |= DSW_FRECLAIM;
2944 }
2945 flags &= ~(DSW_OFFLINE | DSW_CFGOFFLINE | DSW_VOVERFLOW | DSW_OVERFLOW);
2946 if ((ip->bi_flags & DSW_BMPOFFLINE) == DSW_BMPOFFLINE) {
2947 /* free any overflow allocation */
2948 ii_overflow_free(ip, INIT_OVR);
2949 /* Bitmap now OK, so set up new bitmap header */
2950 (void) strncpy(bm_header->master_vol, ii_pathname(ip->bi_mstfd),
2951 DSW_NAMELEN);
2952 (void) strncpy(bm_header->shadow_vol, ii_pathname(ip->bi_shdfd),
2953 DSW_NAMELEN);
2954 (void) strncpy(bm_header->bitmap_vol, ii_pathname(ip->bi_bmpfd),
2955 DSW_NAMELEN);
2956 if (ip->bi_cluster) {
2957 (void) strncpy(bm_header->clstr_name, ip->bi_cluster,
2958 DSW_NAMELEN);
2959 }
2960 if (ip->bi_group) {
2961 (void) strncpy(bm_header->group_name, ip->bi_group,
2962 DSW_NAMELEN);
2963 }
2964 bm_header->ii_type = (flags & DSW_GOLDEN) ?
2965 DSW_GOLDEN_TYPE : DSW_QUICK_TYPE;
2966 bm_header->ii_magic = DSW_DIRTY;
2967 bm_header->ii_version = II_HEADER_VERSION;
2968 bm_header->ii_shdfba = DSW_SHD_BM_OFFSET;
2969 bm_header->ii_copyfba = DSW_COPY_BM_OFFSET;
2970 bm_header->ii_throttle_delay = ip->bi_throttle_delay;
2971 bm_header->ii_throttle_unit = ip->bi_throttle_unit;
2972 ip->bi_shdfba = bm_header->ii_shdfba;
2973 ip->bi_copyfba = bm_header->ii_copyfba;
2974 } else if ((ip->bi_flags & DSW_SHDOFFLINE) == DSW_SHDOFFLINE) {
2975 /* bitmap didn't go offline, but shadow did */
2976 if (ip->bi_overflow) {
2977 ii_overflow_free(ip, RECLAIM);
2978 }
2979 }
2980 _ii_lock_chunk(ip, II_NULLCHUNK);
2981 mutex_enter(&ip->bi_mutex);
2982 II_FLAG_ASSIGN(flags, ip);
2983
2984 mutex_exit(&ip->bi_mutex);
2985 rc = ii_fill_copy_bmp(ip);
2986 if (rc == 0)
2987 rc = II_ZEROBM(ip);
2988 if (rc == 0) {
2989 if ((ip->bi_flags&(DSW_GOLDEN)) == 0) {
2990 /* just clear bitmaps for dependent copy */
2991 if (ip->bi_flags & DSW_TREEMAP) {
2992 bm_header->ii_state = ip->bi_flags;
2993 mutex_enter(&ip->bi_mutex);
2994 rc = _ii_bm_header_put(bm_header, ip, tmp);
2995 mutex_exit(&ip->bi_mutex);
2996 tmp = NULL;
2997 if (rc == 0) {
2998 rc = ii_tinit(ip);
2999 if (rc == 0) {
3000 mutex_enter(&ip->bi_mutex);
3001 bm_header =
3002 _ii_bm_header_get(ip, &tmp);
3003 mutex_exit(&ip->bi_mutex);
3004 }
3005 }
3006 }
3007
3008 if (rc == 0)
3009 II_FLAG_CLRX(DSW_COPY_FLAGS, ip);
3010 /*
3011 * if copy flags were set, another process may be
3012 * waiting
3013 */
3014 if (rc == 0 && (flags & DSW_COPYINGP))
3015 cv_broadcast(&ip->bi_copydonecv);
3016
3017 if (rc == 0)
3018 rc = II_COPYBM(ip);
3019 }
3020 }
3021 _ii_unlock_chunk(ip, II_NULLCHUNK);
3022 if (rc) {
3023 if (tmp)
3024 _ii_bm_header_free(bm_header, ip, tmp);
3025 mutex_enter(&ip->bi_mutex);
3026 _ii_ioctl_done(ip);
3027 mutex_exit(&ip->bi_mutex);
3028 _ii_rlse_devs(ip, rtype);
3029 spcs_s_add(kstatus, rc);
3030 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EHDRBMP));
3031 }
3032 bm_header->ii_state = ip->bi_flags;
3033 mutex_enter(&ip->bi_mutex);
3034 rc = _ii_bm_header_put(bm_header, ip, tmp);
3035 if (!II_SUCCESS(rc)) {
3036 _ii_ioctl_done(ip);
3037 mutex_exit(&ip->bi_mutex);
3038 _ii_rlse_devs(ip, rtype);
3039 spcs_s_add(kstatus, rc);
3040 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EHDRBMP));
3041 }
3042
3043 /* check with RDC */
3044 if (ii_update_denied(ip, kstatus, (ip->bi_flags & DSW_COPYINGS) ?
3045 CV_SHD2MST : 0, 1)) {
3046 _ii_ioctl_done(ip);
3047 mutex_exit(&ip->bi_mutex);
3048 _ii_rlse_devs(ip, rtype);
3049 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
3050 }
3051
3052 /* don't perform copy for dependent shadows */
3053 if ((ip->bi_flags&(DSW_GOLDEN)) == 0) {
3054 _ii_ioctl_done(ip);
3055 mutex_exit(&ip->bi_mutex);
3056 _ii_rlse_devs(ip, rtype);
3057 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
3058 }
3059
3060 mutex_exit(&ip->bi_mutex);
3061 /* _ii_copyvol calls _ii_ioctl_done() */
3062 if (ip->bi_flags & DSW_COPYINGS)
3063 rc = _ii_copyvol(ip, CV_SHD2MST, rtype, kstatus, 1);
3064 else if (ip->bi_flags & DSW_COPYINGM)
3065 rc = _ii_copyvol(ip, 0, rtype, kstatus, 1);
3066 else {
3067 mutex_enter(&ip->bi_mutex);
3068 _ii_ioctl_done(ip);
3069 mutex_exit(&ip->bi_mutex);
3070 }
3071
3072 _ii_rlse_devs(ip, rtype);
3073
3074 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
3075 }
3076
3077
3078 /*
3079 * _ii_version
3080 * Get version of the InstantImage module.
3081 *
3082 * Calling/Exit State:
3083 * Returns 0 on success, otherwise EFAULT is returned.
3084 * The major and minor revisions are copied out to the user if
3085 * successful.
3086 */
3087 /*ARGSUSED*/
3088 int
_ii_version(intptr_t arg,int ilp32,int * rvp)3089 _ii_version(intptr_t arg, int ilp32, int *rvp)
3090 {
3091 dsw_version_t uversion;
3092 dsw_version32_t uversion32;
3093
3094 if (ilp32) {
3095 if (copyin((void *)arg, &uversion32, sizeof (uversion32)) < 0)
3096 return (EFAULT);
3097
3098 uversion32.major = dsw_major_rev;
3099 uversion32.minor = dsw_minor_rev;
3100 uversion32.micro = dsw_micro_rev;
3101 uversion32.baseline = dsw_baseline_rev;
3102
3103 if (copyout(&uversion32, (void *)arg, sizeof (uversion32)))
3104 return (EFAULT);
3105 } else {
3106 if (copyin((void *)arg, &uversion, sizeof (uversion)) < 0)
3107 return (EFAULT);
3108
3109 uversion.major = dsw_major_rev;
3110 uversion.minor = dsw_minor_rev;
3111 uversion.micro = dsw_micro_rev;
3112 uversion.baseline = dsw_baseline_rev;
3113
3114 if (copyout(&uversion, (void *)arg, sizeof (uversion)))
3115 return (EFAULT);
3116 }
3117
3118 return (0);
3119 }
3120
3121 /*
3122 * _ii_copyparm
3123 * Get and set copy parameters.
3124 *
3125 * Calling/Exit State:
3126 * Returns 0 on success, otherwise EFAULT is returned.
3127 * The previous values are returned to the user.
3128 */
3129 /*ARGSUSED*/
3130 int
_ii_copyparm(intptr_t arg,int ilp32,int * rvp)3131 _ii_copyparm(intptr_t arg, int ilp32, int *rvp)
3132 {
3133 dsw_copyp_t copyp;
3134 dsw_copyp32_t copyp32;
3135 spcs_s_info_t kstatus;
3136 _ii_info_t *ip;
3137 int rc = 0;
3138 int tmp;
3139
3140 if (ilp32) {
3141 if (copyin((void *)arg, ©p32, sizeof (copyp32)) < 0)
3142 return (EFAULT);
3143 II_TAIL_COPY(copyp, copyp32, shadow_vol, dsw_copyp_t);
3144 copyp.status = (spcs_s_info_t)copyp32.status;
3145 } else if (copyin((void *)arg, ©p, sizeof (copyp)) < 0)
3146 return (EFAULT);
3147
3148 kstatus = spcs_s_kcreate();
3149 if (kstatus == NULL)
3150 return (ENOMEM);
3151
3152 if (!copyp.shadow_vol[0])
3153 return (spcs_s_ocopyoutf(&kstatus, copyp.status, DSW_EEMPTY));
3154
3155 mutex_enter(&_ii_info_mutex);
3156 ip = _ii_find_set(copyp.shadow_vol);
3157 mutex_exit(&_ii_info_mutex);
3158 if (ip == NULL)
3159 return (spcs_s_ocopyoutf(&kstatus, copyp.status,
3160 DSW_ENOTFOUND));
3161
3162 tmp = ip->bi_throttle_delay;
3163 if (copyp.copy_delay != -1) {
3164 if (copyp.copy_delay >= MIN_THROTTLE_DELAY &&
3165 copyp.copy_delay <= MAX_THROTTLE_DELAY)
3166 ip->bi_throttle_delay = copyp.copy_delay;
3167 else {
3168 cmn_err(CE_WARN, "!ii: delay out of range %d",
3169 copyp.copy_delay);
3170 rc = EINVAL;
3171 }
3172 }
3173 copyp.copy_delay = tmp;
3174
3175 tmp = ip->bi_throttle_unit;
3176 if (copyp.copy_unit != -1) {
3177 if (copyp.copy_unit >= MIN_THROTTLE_UNIT &&
3178 copyp.copy_unit <= MAX_THROTTLE_UNIT) {
3179 if (rc != EINVAL)
3180 ip->bi_throttle_unit = copyp.copy_unit;
3181 } else {
3182 cmn_err(CE_WARN, "!ii: unit out of range %d",
3183 copyp.copy_unit);
3184 if (rc != EINVAL) {
3185 rc = EINVAL;
3186 ip->bi_throttle_delay = copyp.copy_delay;
3187 }
3188 }
3189 }
3190 copyp.copy_unit = tmp;
3191
3192 _ii_ioctl_done(ip);
3193 mutex_exit(&ip->bi_mutex);
3194
3195 if (ilp32) {
3196 copyp32.copy_delay = copyp.copy_delay;
3197 copyp32.copy_unit = copyp.copy_unit;
3198 if (copyout(©p32, (void *)arg, sizeof (copyp32)) < 0)
3199 return (EFAULT);
3200 } else if (copyout(©p, (void *)arg, sizeof (copyp)))
3201 return (EFAULT);
3202
3203 return (spcs_s_ocopyoutf(&kstatus, copyp.status, rc));
3204 }
3205
3206
3207 /*
3208 * _ii_suspend_vol
3209 * suspend an individual InstantImage group
3210 *
3211 * Calling/Exit State:
3212 * Returns 0 on success, nonzero otherwise
3213 */
3214
3215 int
_ii_suspend_vol(_ii_info_t * ip)3216 _ii_suspend_vol(_ii_info_t *ip)
3217 {
3218 _ii_info_t **xip;
3219 int copy_flag;
3220 int rc;
3221 nsc_buf_t *tmp = NULL;
3222 ii_header_t *bm_header;
3223
3224 copy_flag = ip->bi_flags & DSW_COPY_FLAGS;
3225
3226 _ii_stopvol(ip);
3227 ASSERT(total_ref(ip) == 0);
3228
3229 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0)
3230 return (rc);
3231
3232 /* this rw_enter forces us to drain all active IO */
3233 rw_enter(&ip->bi_linkrw, RW_WRITER);
3234 rw_exit(&ip->bi_linkrw);
3235
3236 mutex_enter(&_ii_info_mutex);
3237 for (xip = &_ii_info_top; *xip; xip = &(*xip)->bi_next) {
3238 if (ip == *xip)
3239 break;
3240 }
3241 *xip = ip->bi_next;
3242 mutex_exit(&_ii_info_mutex);
3243
3244 rc = II_SAVE_BMP(ip, 1);
3245 mutex_enter(&ip->bi_mutex);
3246 if (rc == 0)
3247 bm_header = _ii_bm_header_get(ip, &tmp);
3248 if (rc == 0 && bm_header) {
3249 bm_header->ii_magic = DSW_CLEAN;
3250 bm_header->ii_state |= copy_flag;
3251 bm_header->ii_throttle_delay = ip->bi_throttle_delay;
3252 bm_header->ii_throttle_unit = ip->bi_throttle_unit;
3253 /* copy over the mtime */
3254 bm_header->ii_mtime = ip->bi_mtime;
3255 /* write it to disk */
3256 rc = _ii_bm_header_put(bm_header, ip, tmp);
3257 }
3258 --iigkstat.num_sets.value.ul;
3259 mutex_exit(&ip->bi_mutex);
3260
3261 ii_overflow_free(ip, NO_RECLAIM);
3262 _ii_rlse_devs(ip, BMP);
3263
3264 ii_sibling_free(ip);
3265
3266 return (rc);
3267 }
3268
3269 /*
3270 * _ii_suspend_cluster
3271 * Cluster resource group is switching over to another node, so
3272 * all shadowed volumes in that group are suspended.
3273 *
3274 * Returns 0 on success, or ESRCH if the name of the cluster resource
3275 * group couldn't be found.
3276 */
3277 int
_ii_suspend_cluster(char * shadow_vol)3278 _ii_suspend_cluster(char *shadow_vol)
3279 {
3280 int found, last;
3281 uint64_t hash;
3282 _ii_info_t *ip;
3283 _ii_lsthead_t **cp, *xcp;
3284 _ii_lstinfo_t **np, *xnp;
3285
3286 /* find appropriate cluster list */
3287 mutex_enter(&_ii_cluster_mutex);
3288 hash = nsc_strhash(shadow_vol);
3289 for (cp = &_ii_cluster_top; *cp; cp = &((*cp)->lst_next)) {
3290 if ((hash == (*cp)->lst_hash) && strncmp(shadow_vol,
3291 (*cp)->lst_name, DSW_NAMELEN) == 0)
3292 break;
3293 }
3294
3295 if (!*cp) {
3296 mutex_exit(&_ii_cluster_mutex);
3297 return (DSW_ECNOTFOUND);
3298 }
3299
3300 found = 1;
3301 last = 0;
3302 while (found && !last) {
3303 found = 0;
3304
3305 mutex_enter(&_ii_info_mutex);
3306 for (np = &(*cp)->lst_start; *np; np = &((*np)->lst_next)) {
3307 ip = (*np)->lst_ip;
3308
3309 if (ip->bi_disabled)
3310 continue;
3311
3312 found++;
3313
3314 ip->bi_disabled = 1;
3315 if (NSHADOWS(ip) && (ip->bi_master == ip)) {
3316 ip->bi_flags &= (~DSW_COPYING);
3317 ip->bi_state |= DSW_MULTIMST;
3318 }
3319 mutex_exit(&_ii_info_mutex);
3320
3321 xnp = *np;
3322 *np = (*np)->lst_next;
3323 kmem_free(xnp, sizeof (_ii_lstinfo_t));
3324 ip->bi_cluster = NULL;
3325
3326 (void) _ii_suspend_vol(ip);
3327 break;
3328 }
3329 if (found == 0)
3330 mutex_exit(&_ii_info_mutex);
3331 else if (!(*cp)->lst_start) {
3332 xcp = *cp;
3333 *cp = (*cp)->lst_next;
3334 kmem_free(xcp, sizeof (_ii_lsthead_t));
3335 last = 1;
3336 }
3337 }
3338 mutex_exit(&_ii_cluster_mutex);
3339
3340 return (0);
3341 }
3342
3343 /*
3344 * _ii_shutdown
3345 * System is shutting down, so all shadowed volumes are suspended.
3346 *
3347 * This always succeeds, so always returns 0.
3348 */
3349
3350 /* ARGSUSED */
3351
3352 int
_ii_shutdown(intptr_t arg,int * rvp)3353 _ii_shutdown(intptr_t arg, int *rvp)
3354 {
3355 _ii_info_t **xip, *ip;
3356 int found;
3357
3358 *rvp = 0;
3359
3360 _ii_shutting_down = 1;
3361
3362 /* Go through the list until only disabled entries are found */
3363
3364 found = 1;
3365 while (found) {
3366 found = 0;
3367
3368 mutex_enter(&_ii_info_mutex);
3369 for (xip = &_ii_info_top; *xip; xip = &(*xip)->bi_next) {
3370 ip = *xip;
3371 if (ip->bi_disabled) {
3372 /* Also covers not fully configured yet */
3373 continue;
3374 }
3375 found++;
3376
3377 ip->bi_disabled = 1;
3378 mutex_exit(&_ii_info_mutex);
3379
3380 (void) _ii_suspend_vol(ip);
3381
3382 break;
3383 }
3384 if (found == 0)
3385 mutex_exit(&_ii_info_mutex);
3386 }
3387
3388 _ii_shutting_down = 0;
3389
3390 return (0);
3391 }
3392
3393 /*
3394 * _ii_suspend
3395 * Suspend an InstantImage, saving its state to allow a subsequent resume.
3396 *
3397 * Calling/Exit State:
3398 * Returns 0 if the pair was suspended. Otherwise an error code
3399 * is returned and any additional error information is copied
3400 * out to the user.
3401 */
3402
3403 /* ARGSUSED */
3404
3405 int
_ii_suspend(intptr_t arg,int ilp32,int * rvp)3406 _ii_suspend(intptr_t arg, int ilp32, int *rvp)
3407 {
3408 dsw_ioctl_t uparms;
3409 dsw_ioctl32_t uparms32;
3410 _ii_info_t *ip;
3411 int rc;
3412 spcs_s_info_t kstatus;
3413
3414 *rvp = 0;
3415
3416 if (ilp32) {
3417 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
3418 return (EFAULT);
3419 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
3420 uparms.status = (spcs_s_info_t)uparms32.status;
3421 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
3422 return (EFAULT);
3423
3424 kstatus = spcs_s_kcreate();
3425 if (kstatus == NULL)
3426 return (ENOMEM);
3427
3428 if (!uparms.shadow_vol[0])
3429 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
3430
3431 if ((uparms.flags & CV_IS_CLUSTER) != 0) {
3432 rc = _ii_suspend_cluster(uparms.shadow_vol);
3433 } else {
3434 mutex_enter(&_ii_info_mutex);
3435 ip = _ii_find_set(uparms.shadow_vol);
3436 if (ip == NULL) {
3437 mutex_exit(&_ii_info_mutex);
3438 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
3439 DSW_ENOTFOUND));
3440 }
3441
3442 ip->bi_disabled = 1;
3443 if (NSHADOWS(ip) && (ip->bi_master == ip)) {
3444 ip->bi_flags &= (~DSW_COPYING);
3445 ip->bi_state |= DSW_MULTIMST;
3446 }
3447 mutex_exit(&_ii_info_mutex);
3448
3449 _ii_ioctl_done(ip);
3450 mutex_exit(&ip->bi_mutex);
3451
3452 rc = _ii_suspend_vol(ip);
3453 }
3454
3455 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
3456 }
3457
3458
3459 /*
3460 * _ii_abort
3461 * Stop any copying process for shadow.
3462 *
3463 * Calling/Exit State:
3464 * Returns 0 if the abort succeeded. Otherwise an error code
3465 * is returned and any additional error information is copied
3466 * out to the user.
3467 */
3468
3469 /* ARGSUSED */
3470
3471 int
_ii_abort(intptr_t arg,int ilp32,int * rvp)3472 _ii_abort(intptr_t arg, int ilp32, int *rvp)
3473 {
3474 dsw_ioctl_t uabort;
3475 dsw_ioctl32_t uabort32;
3476 _ii_info_t *ip;
3477 int rc;
3478 spcs_s_info_t kstatus;
3479
3480 if (ilp32) {
3481 if (copyin((void *)arg, &uabort32, sizeof (uabort32)) < 0)
3482 return (EFAULT);
3483 II_TAIL_COPY(uabort, uabort32, shadow_vol, dsw_ioctl_t);
3484 uabort.status = (spcs_s_info_t)uabort32.status;
3485 } else if (copyin((void *)arg, &uabort, sizeof (uabort)) < 0)
3486 return (EFAULT);
3487
3488 kstatus = spcs_s_kcreate();
3489 if (kstatus == NULL)
3490 return (ENOMEM);
3491
3492 if (!uabort.shadow_vol[0])
3493 return (spcs_s_ocopyoutf(&kstatus, uabort.status, DSW_EEMPTY));
3494
3495 mutex_enter(&_ii_info_mutex);
3496 ip = _ii_find_set(uabort.shadow_vol);
3497 mutex_exit(&_ii_info_mutex);
3498 if (ip == NULL)
3499 return (spcs_s_ocopyoutf(&kstatus, uabort.status,
3500 DSW_ENOTFOUND));
3501
3502 mutex_exit(&ip->bi_mutex);
3503
3504 rc = _ii_stopcopy(ip);
3505
3506 mutex_enter(&ip->bi_mutex);
3507 _ii_ioctl_done(ip);
3508 mutex_exit(&ip->bi_mutex);
3509
3510 return (spcs_s_ocopyoutf(&kstatus, uabort.status, rc));
3511 }
3512
3513
3514 /*
3515 * _ii_segment
3516 * Copy out II pair bitmaps (cpy, shd, idx) in segments
3517 *
3518 * Calling/Exit State:
3519 * Returns 0 if the operation succeeded. Otherwise an error code
3520 * is returned and any additional error information is copied
3521 * out to the user.
3522 *
3523 */
3524 int
_ii_segment(intptr_t arg,int ilp32,int * rvp)3525 _ii_segment(intptr_t arg, int ilp32, int *rvp)
3526 {
3527 dsw_segment_t usegment;
3528 dsw_segment32_t usegment32;
3529 _ii_info_t *ip;
3530 int rc, size;
3531 spcs_s_info_t kstatus;
3532 int32_t bi_idxfba;
3533
3534 *rvp = 0;
3535
3536 if (ilp32) {
3537 if (copyin((void *)arg, &usegment32, sizeof (usegment32)))
3538 return (EFAULT);
3539 usegment.status = (spcs_s_info_t)usegment32.status;
3540 bcopy(usegment32.shadow_vol, usegment.shadow_vol, DSW_NAMELEN);
3541 usegment.seg_number = (unsigned)usegment32.seg_number;
3542 usegment.shd_bitmap =
3543 (unsigned char *)(unsigned long)usegment32.shd_bitmap;
3544 usegment.shd_size = usegment32.shd_size;
3545 usegment.cpy_bitmap =
3546 (unsigned char *)(unsigned long)usegment32.cpy_bitmap;
3547 usegment.cpy_size = usegment32.cpy_size;
3548 usegment.idx_bitmap =
3549 (unsigned char *)(unsigned long)usegment32.idx_bitmap;
3550 usegment.idx_size = usegment32.idx_size;
3551 } else if (copyin((void *)arg, &usegment, sizeof (usegment)))
3552 return (EFAULT);
3553
3554 kstatus = spcs_s_kcreate();
3555 if (kstatus == NULL)
3556 return (ENOMEM);
3557
3558 if (usegment.shadow_vol[0]) {
3559 mutex_enter(&_ii_info_mutex);
3560 ip = _ii_find_set(usegment.shadow_vol);
3561 mutex_exit(&_ii_info_mutex);
3562 if (ip == NULL)
3563 return (spcs_s_ocopyoutf(&kstatus, usegment.status,
3564 DSW_ENOTFOUND));
3565 } else
3566 return (spcs_s_ocopyoutf(&kstatus, usegment.status,
3567 DSW_EEMPTY));
3568
3569 mutex_exit(&ip->bi_mutex);
3570
3571 size = ((((ip->bi_size + (DSW_SIZE-1))
3572 / DSW_SIZE) + (DSW_BITS-1))) / DSW_BITS;
3573 bi_idxfba = ip->bi_copyfba + (ip->bi_copyfba - ip->bi_shdfba);
3574 if (((nsc_size_t)usegment.seg_number > DSW_BM_FBA_LEN(ip->bi_size)) ||
3575 (usegment.shd_size > size) ||
3576 (usegment.cpy_size > size) ||
3577 (!(ip->bi_flags & DSW_GOLDEN) && (usegment.idx_size > size*32))) {
3578 _ii_ioctl_done(ip);
3579 return (spcs_s_ocopyoutf(&kstatus, usegment.status,
3580 DSW_EMISMATCH));
3581 }
3582
3583 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
3584 mutex_enter(&ip->bi_mutex);
3585 _ii_ioctl_done(ip);
3586 mutex_exit(&ip->bi_mutex);
3587 spcs_s_add(kstatus, rc);
3588 return (spcs_s_ocopyoutf(&kstatus, usegment.status,
3589 DSW_ERSRVFAIL));
3590 }
3591
3592 if (usegment.shd_bitmap && usegment.shd_size > 0)
3593 rc = II_CO_BMP(ip, ip->bi_shdfba+usegment.seg_number,
3594 usegment.shd_bitmap, usegment.shd_size);
3595 if (rc == 0 && usegment.cpy_bitmap && usegment.cpy_size > 0)
3596 rc = II_CO_BMP(ip, ip->bi_copyfba+usegment.seg_number,
3597 usegment.cpy_bitmap, usegment.cpy_size);
3598 if (!(ip->bi_flags & DSW_GOLDEN)) {
3599 if (rc == 0 && usegment.idx_bitmap && usegment.idx_size > 0)
3600 rc = II_CO_BMP(ip, bi_idxfba+usegment.seg_number*32,
3601 usegment.idx_bitmap, usegment.idx_size);
3602 }
3603
3604 _ii_rlse_devs(ip, BMP);
3605 mutex_enter(&ip->bi_mutex);
3606 _ii_ioctl_done(ip);
3607 mutex_exit(&ip->bi_mutex);
3608 if (rc) {
3609 spcs_s_add(kstatus, rc);
3610 return (spcs_s_ocopyoutf(&kstatus, usegment.status, DSW_EIO));
3611 }
3612
3613 spcs_s_kfree(kstatus);
3614 return (0);
3615 }
3616
3617
3618 /*
3619 * _ii_bitmap
3620 * Copy out II pair bitmaps to user program
3621 *
3622 * Calling/Exit State:
3623 * Returns 0 if the operation succeeded. Otherwise an error code
3624 * is returned and any additional error information is copied
3625 * out to the user.
3626 */
3627
3628 int
_ii_bitmap(intptr_t arg,int ilp32,int * rvp)3629 _ii_bitmap(intptr_t arg, int ilp32, int *rvp)
3630 {
3631 dsw_bitmap_t ubitmap;
3632 dsw_bitmap32_t ubitmap32;
3633 _ii_info_t *ip;
3634 int rc;
3635 spcs_s_info_t kstatus;
3636
3637 *rvp = 0;
3638
3639 if (ilp32) {
3640 if (copyin((void *)arg, &ubitmap32, sizeof (ubitmap32)))
3641 return (EFAULT);
3642 ubitmap.status = (spcs_s_info_t)ubitmap32.status;
3643 bcopy(ubitmap32.shadow_vol, ubitmap.shadow_vol, DSW_NAMELEN);
3644 ubitmap.shd_bitmap =
3645 (unsigned char *)(unsigned long)ubitmap32.shd_bitmap;
3646 ubitmap.shd_size = ubitmap32.shd_size;
3647 ubitmap.copy_bitmap =
3648 (unsigned char *)(unsigned long)ubitmap32.copy_bitmap;
3649 ubitmap.copy_size = ubitmap32.copy_size;
3650 } else if (copyin((void *)arg, &ubitmap, sizeof (ubitmap)))
3651 return (EFAULT);
3652
3653 kstatus = spcs_s_kcreate();
3654 if (kstatus == NULL)
3655 return (ENOMEM);
3656
3657 if (!ubitmap.shadow_vol[0])
3658 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EEMPTY));
3659
3660 mutex_enter(&_ii_info_mutex);
3661 ip = _ii_find_set(ubitmap.shadow_vol);
3662 mutex_exit(&_ii_info_mutex);
3663 if (ip == NULL)
3664 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3665 DSW_ENOTFOUND));
3666
3667 mutex_exit(&ip->bi_mutex);
3668
3669 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
3670 mutex_enter(&ip->bi_mutex);
3671 _ii_ioctl_done(ip);
3672 mutex_exit(&ip->bi_mutex);
3673 spcs_s_add(kstatus, rc);
3674 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3675 DSW_ERSRVFAIL));
3676 }
3677
3678 if (ubitmap.shd_bitmap && ubitmap.shd_size > 0)
3679 rc = II_CO_BMP(ip, ip->bi_shdfba, ubitmap.shd_bitmap,
3680 ubitmap.shd_size);
3681 if (rc == 0 && ubitmap.copy_bitmap && ubitmap.copy_size > 0)
3682 rc = II_CO_BMP(ip, ip->bi_copyfba, ubitmap.copy_bitmap,
3683 ubitmap.copy_size);
3684 _ii_rlse_devs(ip, BMP);
3685 mutex_enter(&ip->bi_mutex);
3686 _ii_ioctl_done(ip);
3687 mutex_exit(&ip->bi_mutex);
3688 if (rc) {
3689 spcs_s_add(kstatus, rc);
3690 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EIO));
3691 }
3692
3693 spcs_s_kfree(kstatus);
3694
3695 return (0);
3696 }
3697
3698 /*
3699 * _ii_export
3700 * Exports the shadow volume
3701 *
3702 * Calling/Exit State:
3703 * Returns 0 if the shadow was exported. Otherwise an error code
3704 * is returned and any additional error information is copied
3705 * out to the user.
3706 *
3707 * Description:
3708 */
3709
3710 int
_ii_export(intptr_t arg,int ilp32,int * rvp)3711 _ii_export(intptr_t arg, int ilp32, int *rvp)
3712 {
3713 dsw_ioctl_t uparms;
3714 dsw_ioctl32_t uparms32;
3715 _ii_info_t *ip;
3716 nsc_fd_t *fd;
3717 int rc = 0;
3718 spcs_s_info_t kstatus;
3719
3720 *rvp = 0;
3721
3722 if (ilp32) {
3723 if (copyin((void *)arg, &uparms32, sizeof (uparms32)) < 0)
3724 return (EFAULT);
3725 II_TAIL_COPY(uparms, uparms32, shadow_vol, dsw_ioctl_t);
3726 uparms.status = (spcs_s_info_t)uparms32.status;
3727 } else if (copyin((void *)arg, &uparms, sizeof (uparms)) < 0)
3728 return (EFAULT);
3729
3730 kstatus = spcs_s_kcreate();
3731 if (kstatus == NULL)
3732 return (ENOMEM);
3733
3734 if (!uparms.shadow_vol[0])
3735 return (spcs_s_ocopyoutf(&kstatus, uparms.status, DSW_EEMPTY));
3736
3737 mutex_enter(&_ii_info_mutex);
3738 ip = _ii_find_set(uparms.shadow_vol);
3739 mutex_exit(&_ii_info_mutex);
3740 if (ip == NULL)
3741 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
3742 DSW_ENOTFOUND));
3743
3744 if ((ip->bi_flags & DSW_GOLDEN) == 0 ||
3745 ((ip->bi_flags & (DSW_COPYING|DSW_SHDEXPORT|DSW_SHDIMPORT)) != 0)) {
3746 /*
3747 * Cannot export a dependent copy or while still copying or
3748 * the shadow is already in an exported state
3749 */
3750 rc = ip->bi_flags & (DSW_SHDEXPORT|DSW_SHDIMPORT)
3751 ? DSW_EALREADY : DSW_EDEPENDENCY;
3752 _ii_ioctl_done(ip);
3753 mutex_exit(&ip->bi_mutex);
3754 return (spcs_s_ocopyoutf(&kstatus, uparms.status, rc));
3755 }
3756 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
3757 _ii_ioctl_done(ip);
3758 mutex_exit(&ip->bi_mutex);
3759 spcs_s_add(kstatus, rc);
3760 return (spcs_s_ocopyoutf(&kstatus, uparms.status,
3761 DSW_ERSRVFAIL));
3762 }
3763 II_FLAG_SET(DSW_SHDEXPORT, ip);
3764
3765 mutex_exit(&ip->bi_mutex);
3766
3767 /* this rw_enter forces us to drain all active IO */
3768 rw_enter(&ip->bi_linkrw, RW_WRITER);
3769 rw_exit(&ip->bi_linkrw);
3770
3771 mutex_enter(&ip->bi_mutex);
3772
3773 _ii_rlse_devs(ip, BMP);
3774
3775 /* Shut shadow volume. */
3776 if (ip->bi_shdfd) {
3777 if (ip->bi_shdrsrv) {
3778 nsc_release(ip->bi_shdfd);
3779 ip->bi_shdrsrv = NULL;
3780 }
3781 fd = ip->bi_shdfd;
3782 ip->bi_shdfd = NULL;
3783 mutex_exit(&ip->bi_mutex);
3784 (void) nsc_close(fd);
3785 mutex_enter(&ip->bi_mutex);
3786 }
3787
3788 if (ip->bi_shdrfd) {
3789 if (ip->bi_shdrrsrv) {
3790 nsc_release(ip->bi_shdrfd);
3791 ip->bi_shdrrsrv = NULL;
3792 }
3793 fd = ip->bi_shdrfd;
3794 ip->bi_shdrfd = NULL;
3795 mutex_exit(&ip->bi_mutex);
3796 (void) nsc_close(fd);
3797 mutex_enter(&ip->bi_mutex);
3798 }
3799 _ii_ioctl_done(ip);
3800 mutex_exit(&ip->bi_mutex);
3801
3802 (void) _ii_reserve_begin(ip);
3803 if (ip->bi_shd_tok) {
3804 (void) _ii_unregister_path(ip->bi_shd_tok, 0, "shadow");
3805 ip->bi_shd_tok = NULL;
3806 }
3807
3808 if (ip->bi_shdr_tok) {
3809 (void) _ii_unregister_path(ip->bi_shdr_tok, 0,
3810 "raw shadow");
3811 ip->bi_shdr_tok = NULL;
3812 }
3813 _ii_reserve_end(ip);
3814
3815 spcs_s_kfree(kstatus);
3816
3817 return (0);
3818 }
3819
3820 /*
3821 * _ii_join
3822 * Rejoins the shadow volume
3823 *
3824 * Calling/Exit State:
3825 * Returns 0 if the shadow was exported. Otherwise an error code
3826 * is returned and any additional error information is copied
3827 * out to the user.
3828 *
3829 * Description:
3830 */
3831
3832 int
_ii_join(intptr_t arg,int ilp32,int * rvp)3833 _ii_join(intptr_t arg, int ilp32, int *rvp)
3834 {
3835 dsw_bitmap_t ubitmap;
3836 dsw_bitmap32_t ubitmap32;
3837 _ii_info_t *ip;
3838 uint64_t bm_size;
3839 int rc = 0;
3840 int rtype = 0;
3841 spcs_s_info_t kstatus;
3842
3843 *rvp = 0;
3844
3845 if (ilp32) {
3846 if (copyin((void *)arg, &ubitmap32, sizeof (ubitmap32)) < 0)
3847 return (EFAULT);
3848 II_TAIL_COPY(ubitmap, ubitmap32, shadow_vol, dsw_bitmap_t);
3849 ubitmap.status = (spcs_s_info_t)ubitmap32.status;
3850 ubitmap.shd_bitmap =
3851 (unsigned char *)(unsigned long)ubitmap32.shd_bitmap;
3852 ubitmap.shd_size = ubitmap32.shd_size;
3853 } else if (copyin((void *)arg, &ubitmap, sizeof (ubitmap)) < 0)
3854 return (EFAULT);
3855
3856 kstatus = spcs_s_kcreate();
3857 if (kstatus == NULL)
3858 return (ENOMEM);
3859
3860 if (!ubitmap.shadow_vol[0])
3861 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EEMPTY));
3862
3863 mutex_enter(&_ii_info_mutex);
3864 ip = _ii_find_set(ubitmap.shadow_vol);
3865 mutex_exit(&_ii_info_mutex);
3866 if (ip == NULL)
3867 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3868 DSW_ENOTFOUND));
3869
3870 /*
3871 * Check that group has shadow exported.
3872 */
3873 if ((ip->bi_flags & DSW_SHDEXPORT) == 0) {
3874 /*
3875 * Cannot join if the shadow isn't exported.
3876 */
3877 _ii_ioctl_done(ip);
3878 mutex_exit(&ip->bi_mutex);
3879 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3880 DSW_ENOTEXPORTED));
3881 }
3882 /* check bitmap is at least large enough for master volume size */
3883 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
3884 if (ubitmap.shd_size < bm_size) {
3885 /* bitmap is to small */
3886 _ii_ioctl_done(ip);
3887 mutex_exit(&ip->bi_mutex);
3888 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3889 DSW_EINVALBMP));
3890 }
3891 /* read in bitmap and or with differences bitmap */
3892 rtype = BMP;
3893 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
3894 _ii_ioctl_done(ip);
3895 mutex_exit(&ip->bi_mutex);
3896 spcs_s_add(kstatus, rc);
3897 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
3898 DSW_ERSRVFAIL));
3899 }
3900 rc = II_CI_BMP(ip, ip->bi_shdfba, ubitmap.shd_bitmap,
3901 ubitmap.shd_size);
3902 /* open up shadow */
3903 if ((rc = ii_open_shadow(ip, ip->bi_keyname)) != 0) {
3904 _ii_ioctl_done(ip);
3905 mutex_exit(&ip->bi_mutex);
3906 spcs_s_add(kstatus, rc);
3907 _ii_rlse_devs(ip, rtype);
3908 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EOPEN));
3909 }
3910 ii_register_shd(ip);
3911 if (!rc)
3912 II_FLAG_CLR(DSW_SHDEXPORT, ip);
3913 _ii_ioctl_done(ip);
3914 mutex_exit(&ip->bi_mutex);
3915 _ii_rlse_devs(ip, rtype);
3916
3917 if (rc) {
3918 spcs_s_add(kstatus, rc);
3919 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EIO));
3920 }
3921
3922 spcs_s_kfree(kstatus);
3923
3924 return (0);
3925 }
3926
3927
3928 /*
3929 * _ii_ocreate
3930 * Configures a volume suitable for use as an overflow volume.
3931 *
3932 * Calling/Exit State:
3933 * Returns 0 if the volume was configured successfully. Otherwise
3934 * an error code is returned and any additional error information
3935 * is copied out to the user.
3936 *
3937 * Description:
3938 */
3939
3940 int
_ii_ocreate(intptr_t arg,int ilp32,int * rvp)3941 _ii_ocreate(intptr_t arg, int ilp32, int *rvp)
3942 {
3943 dsw_ioctl_t uioctl;
3944 dsw_ioctl32_t uioctl32;
3945 _ii_overflow_t ov;
3946 _ii_overflow_t *op = &ov;
3947 int rc = 0;
3948 nsc_fd_t *fd;
3949 nsc_iodev_t *iodev;
3950 nsc_size_t vol_size;
3951 char *overflow_vol;
3952 spcs_s_info_t kstatus;
3953
3954 *rvp = 0;
3955
3956 if (ilp32) {
3957 if (copyin((void *)arg, &uioctl32, sizeof (uioctl32)) < 0)
3958 return (EFAULT);
3959 II_TAIL_COPY(uioctl, uioctl32, shadow_vol, dsw_ioctl_t);
3960 uioctl.status = (spcs_s_info_t)uioctl32.status;
3961 } else if (copyin((void *)arg, &uioctl, sizeof (uioctl)) < 0)
3962 return (EFAULT);
3963
3964 overflow_vol = uioctl.shadow_vol;
3965 kstatus = spcs_s_kcreate();
3966 if (kstatus == NULL)
3967 return (ENOMEM);
3968
3969 if (!overflow_vol[0])
3970 return (spcs_s_ocopyoutf(&kstatus, uioctl.status, DSW_EEMPTY));
3971
3972 if (ii_volume(overflow_vol, 0) != NONE)
3973 return (spcs_s_ocopyoutf(&kstatus, uioctl.status, DSW_EINUSE));
3974
3975 fd = nsc_open(overflow_vol,
3976 NSC_IIR_ID|NSC_FILE|NSC_RDWR, NULL, (blind_t)&(iodev), &rc);
3977 if (!fd)
3978 fd = nsc_open(uioctl.shadow_vol,
3979 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, NULL,
3980 (blind_t)&(iodev), &rc);
3981 if (fd == NULL) {
3982 spcs_s_add(kstatus, rc);
3983 return (spcs_s_ocopyoutf(&kstatus, uioctl.status, DSW_EIO));
3984 }
3985 if ((rc = nsc_reserve(fd, 0)) != 0) {
3986 spcs_s_add(kstatus, rc);
3987 (void) nsc_close(fd);
3988 return (spcs_s_ocopyoutf(&kstatus, uioctl.status,
3989 DSW_ERSRVFAIL));
3990 }
3991 /* setup magic number etc; */
3992 rc = nsc_partsize(fd, &vol_size);
3993 if (rc) {
3994 spcs_s_add(kstatus, rc);
3995 (void) nsc_close(fd);
3996 return (spcs_s_ocopyoutf(&kstatus, uioctl.status, DSW_EIO));
3997 }
3998 op->ii_hmagic = II_OMAGIC;
3999 /* take 1 off as chunk 0 contains header */
4000 op->ii_nchunks = (vol_size / DSW_SIZE) -1;
4001 op->ii_drefcnt = 0;
4002 op->ii_used = 1; /* we have used the header */
4003 op->ii_unused = op->ii_nchunks - op->ii_used;
4004 op->ii_freehead = II_NULLNODE;
4005 op->ii_hversion = OV_HEADER_VERSION;
4006 op->ii_flags = 0;
4007 op->ii_urefcnt = 0;
4008 (void) strncpy(op->ii_volname, uioctl.shadow_vol, DSW_NAMELEN);
4009 rc = _ii_nsc_io(0, KS_NA, fd, NSC_WRBUF, II_OHEADER_FBA,
4010 (unsigned char *)&op->ii_do, sizeof (op->ii_do));
4011 (void) nsc_release(fd);
4012 (void) nsc_close(fd);
4013 if (rc) {
4014 spcs_s_add(kstatus, rc);
4015 return (spcs_s_ocopyoutf(&kstatus, uioctl.status, DSW_EIO));
4016 }
4017
4018 spcs_s_kfree(kstatus);
4019
4020 return (0);
4021 }
4022
4023
4024 /*
4025 * _ii_oattach
4026 * Attaches the volume in the "bitmap_vol" field as an overflow volume.
4027 *
4028 * Calling/Exit State:
4029 * Returns 0 if the volume was attached. Fails if the shadow group
4030 * is of the wrong type (eg independent) or already has an overflow
4031 * volume attached.
4032 *
4033 * Description:
4034 */
4035
4036 int
_ii_oattach(intptr_t arg,int ilp32,int * rvp)4037 _ii_oattach(intptr_t arg, int ilp32, int *rvp)
4038 {
4039 dsw_config_t uconfig;
4040 dsw_config32_t uconfig32;
4041 _ii_info_t *ip;
4042 int rc = 0;
4043 int rtype = 0;
4044 ii_header_t *bm_header;
4045 nsc_buf_t *tmp = NULL;
4046 spcs_s_info_t kstatus;
4047
4048 *rvp = 0;
4049
4050 if (ilp32) {
4051 if (copyin((void *)arg, &uconfig32, sizeof (uconfig32)) < 0)
4052 return (EFAULT);
4053 II_TAIL_COPY(uconfig, uconfig32, shadow_vol, dsw_config_t);
4054 uconfig.status = (spcs_s_info_t)uconfig32.status;
4055 } else if (copyin((void *)arg, &uconfig, sizeof (uconfig)) < 0)
4056 return (EFAULT);
4057
4058 kstatus = spcs_s_kcreate();
4059 if (kstatus == NULL)
4060 return (ENOMEM);
4061
4062 if (!uconfig.shadow_vol[0])
4063 return (spcs_s_ocopyoutf(&kstatus, uconfig.status, DSW_EEMPTY));
4064
4065 switch (ii_volume(uconfig.bitmap_vol, 0)) {
4066 case NONE:
4067 case OVR:
4068 break;
4069 default:
4070 return (spcs_s_ocopyoutf(&kstatus, uconfig.status, DSW_EINUSE));
4071 }
4072 mutex_enter(&_ii_info_mutex);
4073 ip = _ii_find_set(uconfig.shadow_vol);
4074 mutex_exit(&_ii_info_mutex);
4075 if (ip == NULL)
4076 return (spcs_s_ocopyoutf(&kstatus, uconfig.status,
4077 DSW_ENOTFOUND));
4078
4079 /* check shadow doesn't already have an overflow volume */
4080 if (ip->bi_overflow) {
4081 _ii_ioctl_done(ip);
4082 mutex_exit(&ip->bi_mutex);
4083 return (spcs_s_ocopyoutf(&kstatus, uconfig.status,
4084 DSW_EALREADY));
4085 }
4086 /* check shadow is mapped so can have an overflow */
4087 if ((ip->bi_flags&DSW_TREEMAP) == 0) {
4088 _ii_ioctl_done(ip);
4089 mutex_exit(&ip->bi_mutex);
4090 return (spcs_s_ocopyoutf(&kstatus, uconfig.status,
4091 DSW_EWRONGTYPE));
4092 }
4093 rtype = BMP;
4094 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
4095 _ii_ioctl_done(ip);
4096 mutex_exit(&ip->bi_mutex);
4097 spcs_s_add(kstatus, rc);
4098 return (spcs_s_ocopyoutf(&kstatus, uconfig.status,
4099 DSW_ERSRVFAIL));
4100 }
4101 /* attach volume */
4102 if ((rc = ii_overflow_attach(ip, uconfig.bitmap_vol, 1)) != 0) {
4103 _ii_ioctl_done(ip);
4104 mutex_exit(&ip->bi_mutex);
4105 _ii_rlse_devs(ip, rtype);
4106 return (spcs_s_ocopyoutf(&kstatus, uconfig.status, rc));
4107 }
4108
4109 /* re-write header so shadow can be restarted with overflow volume */
4110
4111 bm_header = _ii_bm_header_get(ip, &tmp);
4112 if (bm_header == NULL) {
4113 /* detach volume */
4114 ii_overflow_free(ip, RECLAIM);
4115 _ii_ioctl_done(ip);
4116 mutex_exit(&ip->bi_mutex);
4117 _ii_rlse_devs(ip, rtype);
4118 return (spcs_s_ocopyoutf(&kstatus, uconfig.status,
4119 DSW_EHDRBMP));
4120 }
4121 (void) strncpy(bm_header->overflow_vol, uconfig.bitmap_vol,
4122 DSW_NAMELEN);
4123 (void) _ii_bm_header_put(bm_header, ip, tmp);
4124 _ii_rlse_devs(ip, rtype);
4125 _ii_ioctl_done(ip);
4126 mutex_exit(&ip->bi_mutex);
4127
4128 spcs_s_kfree(kstatus);
4129
4130 return (0);
4131 }
4132
4133
4134 /*
4135 * _ii_odetach
4136 * Breaks the link with the overflow volume.
4137 *
4138 * Calling/Exit State:
4139 * Returns 0 if the overflow volume was detached. Otherwise an error code
4140 * is returned and any additional error information is copied
4141 * out to the user.
4142 *
4143 * Description:
4144 */
4145
4146 int
_ii_odetach(intptr_t arg,int ilp32,int * rvp)4147 _ii_odetach(intptr_t arg, int ilp32, int *rvp)
4148 {
4149 dsw_bitmap_t ubitmap;
4150 dsw_bitmap32_t ubitmap32;
4151 _ii_info_t *ip;
4152 int rc = 0;
4153 int rtype = 0;
4154 ii_header_t *bm_header;
4155 nsc_buf_t *tmp = NULL;
4156 spcs_s_info_t kstatus;
4157
4158 *rvp = 0;
4159
4160 if (ilp32) {
4161 if (copyin((void *)arg, &ubitmap32, sizeof (ubitmap32)) < 0)
4162 return (EFAULT);
4163 II_TAIL_COPY(ubitmap, ubitmap32, shadow_vol, dsw_bitmap_t);
4164 ubitmap.status = (spcs_s_info_t)ubitmap32.status;
4165 } else if (copyin((void *)arg, &ubitmap, sizeof (ubitmap)) < 0)
4166 return (EFAULT);
4167
4168 kstatus = spcs_s_kcreate();
4169 if (kstatus == NULL)
4170 return (ENOMEM);
4171
4172 if (!ubitmap.shadow_vol[0])
4173 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EEMPTY));
4174
4175 mutex_enter(&_ii_info_mutex);
4176 ip = _ii_find_set(ubitmap.shadow_vol);
4177 mutex_exit(&_ii_info_mutex);
4178 if (ip == NULL)
4179 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
4180 DSW_ENOTFOUND));
4181
4182 if ((ip->bi_flags&DSW_VOVERFLOW) != 0) {
4183 _ii_ioctl_done(ip);
4184 mutex_exit(&ip->bi_mutex);
4185 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
4186 DSW_EODEPENDENCY));
4187 }
4188 rtype = BMP;
4189 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
4190 _ii_ioctl_done(ip);
4191 mutex_exit(&ip->bi_mutex);
4192 spcs_s_add(kstatus, rc);
4193 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
4194 DSW_ERSRVFAIL));
4195 }
4196 ii_overflow_free(ip, RECLAIM);
4197 /* re-write header to break link with overflow volume */
4198
4199 bm_header = _ii_bm_header_get(ip, &tmp);
4200 if (bm_header == NULL) {
4201 _ii_rlse_devs(ip, rtype);
4202 _ii_ioctl_done(ip);
4203 mutex_exit(&ip->bi_mutex);
4204 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status,
4205 DSW_EHDRBMP));
4206 }
4207 bzero(bm_header->overflow_vol, DSW_NAMELEN);
4208 (void) _ii_bm_header_put(bm_header, ip, tmp);
4209
4210 _ii_rlse_devs(ip, rtype);
4211 _ii_ioctl_done(ip);
4212
4213 mutex_exit(&ip->bi_mutex);
4214 if (rc) {
4215 spcs_s_add(kstatus, rc);
4216 return (spcs_s_ocopyoutf(&kstatus, ubitmap.status, DSW_EIO));
4217 }
4218
4219 spcs_s_kfree(kstatus);
4220
4221 --iigkstat.assoc_over.value.ul;
4222
4223 return (0);
4224 }
4225
4226
4227 /*
4228 * _ii_gc_list
4229 * Returns a list of all lists, or all entries in a list
4230 *
4231 */
4232 int
_ii_gc_list(intptr_t arg,int ilp32,int * rvp,kmutex_t * mutex,_ii_lsthead_t * lst)4233 _ii_gc_list(intptr_t arg, int ilp32, int *rvp, kmutex_t *mutex,
4234 _ii_lsthead_t *lst)
4235 {
4236 dsw_aioctl_t ulist;
4237 dsw_aioctl32_t ulist32;
4238 size_t name_offset;
4239 int i;
4240 spcs_s_info_t kstatus;
4241 char *carg = (char *)arg;
4242 uint64_t hash;
4243 _ii_lsthead_t *cp;
4244 _ii_lstinfo_t *np;
4245
4246 *rvp = 0;
4247 name_offset = offsetof(dsw_aioctl_t, shadow_vol[0]);
4248 if (ilp32) {
4249 if (copyin((void *) arg, &ulist32, sizeof (ulist32)) < 0)
4250 return (EFAULT);
4251 II_TAIL_COPY(ulist, ulist32, flags, dsw_aioctl_t);
4252 ulist.status = (spcs_s_info_t)ulist32.status;
4253 name_offset = offsetof(dsw_aioctl32_t, shadow_vol[0]);
4254 } else if (copyin((void *) arg, &ulist, sizeof (ulist)) < 0)
4255 return (EFAULT);
4256
4257 kstatus = spcs_s_kcreate();
4258 if (kstatus == NULL)
4259 return (ENOMEM);
4260
4261 mutex_enter(mutex);
4262 if (ulist.shadow_vol[ 0 ] != 0) {
4263 /* search for specific list */
4264 hash = nsc_strhash(ulist.shadow_vol);
4265 for (cp = lst; cp; cp = cp->lst_next) {
4266 if ((hash == cp->lst_hash) && strncmp(ulist.shadow_vol,
4267 cp->lst_name, DSW_NAMELEN) == 0) {
4268 break;
4269 }
4270 }
4271 if (cp) {
4272 for (i = 0, np = cp->lst_start; i < ulist.count && np;
4273 np = np->lst_next, carg += DSW_NAMELEN, i++) {
4274 if (copyout(np->lst_ip->bi_keyname,
4275 carg + name_offset, DSW_NAMELEN)) {
4276 mutex_exit(mutex);
4277 return (spcs_s_ocopyoutf(&kstatus,
4278 ulist.status, EFAULT));
4279 }
4280 }
4281 } else {
4282 i = 0;
4283 }
4284 } else {
4285 /* return full list */
4286 for (i = 0, cp = lst; i < ulist.count && cp;
4287 carg += DSW_NAMELEN, i++, cp = cp->lst_next) {
4288 if (copyout(cp->lst_name, carg + name_offset,
4289 DSW_NAMELEN)) {
4290 mutex_exit(mutex);
4291 return (spcs_s_ocopyoutf(&kstatus, ulist.status,
4292 EFAULT));
4293 }
4294 }
4295 }
4296 mutex_exit(mutex);
4297 ulist32.count = ulist.count = i;
4298
4299 if (ilp32) {
4300 if (copyout(&ulist32, (void *) arg, name_offset))
4301 return (EFAULT);
4302 } else {
4303 if (copyout(&ulist, (void*) arg, name_offset))
4304 return (EFAULT);
4305 }
4306
4307 return (spcs_s_ocopyoutf(&kstatus, ulist.status, 0));
4308 }
4309
4310 /*
4311 * _ii_olist
4312 * Breaks the link with the overflow volume.
4313 *
4314 * Calling/Exit State:
4315 * Returns 0 if the overflow volume was detached. Otherwise an error code
4316 * is returned and any additional error information is copied
4317 * out to the user.
4318 *
4319 * Description:
4320 */
4321
4322 int
_ii_olist(intptr_t arg,int ilp32,int * rvp)4323 _ii_olist(intptr_t arg, int ilp32, int *rvp)
4324 {
4325 dsw_aioctl_t ulist;
4326 dsw_aioctl32_t ulist32;
4327 _ii_overflow_t *op;
4328 size_t name_offset;
4329 int rc = 0;
4330 int i;
4331 char *carg = (char *)arg;
4332 spcs_s_info_t kstatus;
4333
4334 *rvp = 0;
4335
4336 name_offset = offsetof(dsw_aioctl_t, shadow_vol[0]);
4337 if (ilp32) {
4338 if (copyin((void *)arg, &ulist32, sizeof (ulist32)) < 0)
4339 return (EFAULT);
4340 II_TAIL_COPY(ulist, ulist32, flags, dsw_aioctl_t);
4341 ulist.status = (spcs_s_info_t)ulist32.status;
4342 name_offset = offsetof(dsw_aioctl32_t, shadow_vol[0]);
4343 } else if (copyin((void *)arg, &ulist, sizeof (ulist)) < 0)
4344 return (EFAULT);
4345
4346 kstatus = spcs_s_kcreate();
4347 if (kstatus == NULL)
4348 return (ENOMEM);
4349
4350 i = 0;
4351
4352 mutex_enter(&_ii_overflow_mutex);
4353 for (op = _ii_overflow_top; i < ulist.count && op;
4354 carg += DSW_NAMELEN) {
4355 if (copyout(op->ii_volname, carg+name_offset, DSW_NAMELEN)) {
4356 mutex_exit(&_ii_overflow_mutex);
4357 return (spcs_s_ocopyoutf(&kstatus, ulist.status,
4358 EFAULT));
4359 }
4360 i++;
4361 op = op->ii_next;
4362 }
4363 mutex_exit(&_ii_overflow_mutex);
4364 ulist32.count = ulist.count = i;
4365 /* return count of items listed to user */
4366 if (ilp32) {
4367 if (copyout(&ulist32, (void *)arg, name_offset))
4368 return (EFAULT);
4369 } else {
4370 if (copyout(&ulist, (void *)arg, name_offset))
4371 return (EFAULT);
4372 }
4373
4374 return (spcs_s_ocopyoutf(&kstatus, ulist.status, rc));
4375 }
4376
4377 /*
4378 * _ii_ostat
4379 * Breaks the link with the overflow volume.
4380 *
4381 * Calling/Exit State:
4382 * Returns 0 if the overflow volume was detached. Otherwise an error code
4383 * is returned and any additional error information is copied
4384 * out to the user.
4385 *
4386 * Description:
4387 */
4388
4389 int
_ii_ostat(intptr_t arg,int ilp32,int * rvp,int is_iost_2)4390 _ii_ostat(intptr_t arg, int ilp32, int *rvp, int is_iost_2)
4391 {
4392 dsw_ostat_t ustat;
4393 dsw_ostat32_t ustat32;
4394 _ii_overflow_t *op;
4395 spcs_s_info_t kstatus;
4396
4397 *rvp = 0;
4398
4399 if (ilp32) {
4400 if (copyin((void *)arg, &ustat32, sizeof (ustat32)) < 0)
4401 return (EFAULT);
4402 II_TAIL_COPY(ustat, ustat32, overflow_vol, dsw_ostat_t);
4403 ustat.status = (spcs_s_info_t)ustat32.status;
4404 } else if (copyin((void *)arg, &ustat, sizeof (ustat)) < 0)
4405 return (EFAULT);
4406
4407 kstatus = spcs_s_kcreate();
4408 if (kstatus == NULL)
4409 return (ENOMEM);
4410 if (!ustat.overflow_vol[0])
4411 return (spcs_s_ocopyoutf(&kstatus, ustat.status, DSW_EEMPTY));
4412
4413 op = _ii_find_overflow(ustat.overflow_vol);
4414 if (op == NULL)
4415 return (spcs_s_ocopyoutf(&kstatus, ustat.status,
4416 DSW_ENOTFOUND));
4417
4418 ustat.nchunks = op->ii_nchunks;
4419 ustat.used = op->ii_used;
4420 ustat.unused = op->ii_unused;
4421 ustat.drefcnt = op->ii_drefcnt;
4422 ustat.crefcnt = op->ii_crefcnt;
4423 if (is_iost_2) {
4424 ustat.hversion = op->ii_hversion;
4425 ustat.flags = op->ii_flags;
4426 ustat.hmagic = op->ii_hmagic;
4427 }
4428
4429 spcs_s_kfree(kstatus);
4430 if (ilp32) {
4431 ustat32.nchunks = ustat.nchunks;
4432 ustat32.used = ustat.used;
4433 ustat32.unused = ustat.unused;
4434 ustat32.drefcnt = ustat.drefcnt;
4435 ustat32.crefcnt = ustat.crefcnt;
4436 if (is_iost_2) {
4437 ustat32.hversion = ustat.hversion;
4438 ustat32.flags = ustat.flags;
4439 ustat32.hmagic = ustat.hmagic;
4440 }
4441 if (copyout(&ustat32, (void *)arg, sizeof (ustat32)))
4442 return (EFAULT);
4443 } else {
4444 if (copyout(&ustat, (void *)arg, sizeof (ustat)))
4445 return (EFAULT);
4446 }
4447 return (0);
4448 }
4449
4450 /*
4451 * _ii_move_grp()
4452 * Move a set from one group to another, possibly creating the new
4453 * group.
4454 */
4455
4456 int
_ii_move_grp(intptr_t arg,int ilp32,int * rvp)4457 _ii_move_grp(intptr_t arg, int ilp32, int *rvp)
4458 {
4459 dsw_movegrp_t umove;
4460 dsw_movegrp32_t umove32;
4461 spcs_s_info_t kstatus;
4462 _ii_info_t *ip;
4463 int rc = 0;
4464 nsc_buf_t *tmp;
4465 ii_header_t *bm_header;
4466
4467 *rvp = 0;
4468
4469 if (ilp32) {
4470 if (copyin((void *)arg, &umove32, sizeof (umove32)) < 0)
4471 return (EFAULT);
4472 II_TAIL_COPY(umove, umove32, shadow_vol, dsw_movegrp_t);
4473 umove.status = (spcs_s_info_t)umove32.status;
4474 } else if (copyin((void *)arg, &umove, sizeof (umove)) < 0)
4475 return (EFAULT);
4476
4477 kstatus = spcs_s_kcreate();
4478 if (kstatus == NULL)
4479 return (ENOMEM);
4480
4481 if (!umove.shadow_vol[0])
4482 return (spcs_s_ocopyoutf(&kstatus, umove.status, DSW_EEMPTY));
4483
4484 mutex_enter(&_ii_info_mutex);
4485 ip = _ii_find_set(umove.shadow_vol);
4486 mutex_exit(&_ii_info_mutex);
4487
4488 if (!ip)
4489 return (spcs_s_ocopyoutf(&kstatus, umove.status,
4490 DSW_ENOTFOUND));
4491
4492 if (!umove.new_group[0]) {
4493 /* are we clearing the group association? */
4494 if (ip->bi_group) {
4495 DTRACE_PROBE2(_ii_move_grp1, char *, ip->bi_keyname,
4496 char *, ip->bi_group);
4497 rc = II_UNLINK_GROUP(ip);
4498 }
4499 } else if (!ip->bi_group) {
4500 rc = II_LINK_GROUP(ip, umove.new_group);
4501 DTRACE_PROBE2(_ii_move_grp2, char *, ip->bi_keyname,
4502 char *, ip->bi_group);
4503 } else {
4504 /* remove it from one group and add it to the other */
4505 DTRACE_PROBE3(_ii_move_grp, char *, ip->bi_keyname,
4506 char *, ip->bi_group, char *, umove.new_group);
4507 rc = II_UNLINK_GROUP(ip);
4508 if (!rc)
4509 rc = II_LINK_GROUP(ip, umove.new_group);
4510 }
4511
4512 /* ** BEGIN UPDATE BITMAP HEADER ** */
4513 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
4514 _ii_ioctl_done(ip);
4515 mutex_exit(&ip->bi_mutex);
4516 spcs_s_add(kstatus, rc);
4517 return (spcs_s_ocopyoutf(&kstatus, umove.status,
4518 DSW_ERSRVFAIL));
4519 }
4520 bm_header = _ii_bm_header_get(ip, &tmp);
4521 if (bm_header) {
4522 (void) strncpy(bm_header->group_name, umove.new_group,
4523 DSW_NAMELEN);
4524 (void) _ii_bm_header_put(bm_header, ip, tmp);
4525 }
4526 _ii_rlse_devs(ip, BMP);
4527 /* ** END UPDATE BITMAP HEADER ** */
4528
4529 _ii_ioctl_done(ip);
4530 mutex_exit(&ip->bi_mutex);
4531
4532 return (spcs_s_ocopyoutf(&kstatus, umove.status, rc));
4533 }
4534
4535 /*
4536 * _ii_change_tag()
4537 * Move a set from one group to another, possibly creating the new
4538 * group.
4539 */
4540
4541 int
_ii_change_tag(intptr_t arg,int ilp32,int * rvp)4542 _ii_change_tag(intptr_t arg, int ilp32, int *rvp)
4543 {
4544 dsw_movegrp_t umove;
4545 dsw_movegrp32_t umove32;
4546 spcs_s_info_t kstatus;
4547 _ii_info_t *ip;
4548 int rc = 0;
4549 nsc_buf_t *tmp;
4550 ii_header_t *bm_header;
4551
4552 *rvp = 0;
4553
4554 if (ilp32) {
4555 if (copyin((void *)arg, &umove32, sizeof (umove32)) < 0)
4556 return (EFAULT);
4557 II_TAIL_COPY(umove, umove32, shadow_vol, dsw_movegrp_t);
4558 umove.status = (spcs_s_info_t)umove32.status;
4559 } else if (copyin((void *)arg, &umove, sizeof (umove)) < 0)
4560 return (EFAULT);
4561
4562 kstatus = spcs_s_kcreate();
4563 if (kstatus == NULL)
4564 return (ENOMEM);
4565
4566 if (!umove.shadow_vol[0])
4567 return (spcs_s_ocopyoutf(&kstatus, umove.status, DSW_EEMPTY));
4568
4569 mutex_enter(&_ii_info_mutex);
4570 ip = _ii_find_set(umove.shadow_vol);
4571 mutex_exit(&_ii_info_mutex);
4572
4573 if (!ip)
4574 return (spcs_s_ocopyoutf(&kstatus, umove.status,
4575 DSW_ENOTFOUND));
4576
4577 if (!umove.new_group[0]) {
4578 /* are we clearing the group association? */
4579 if (ip->bi_cluster) {
4580 DTRACE_PROBE2(_ii_change_tag, char *, ip->bi_keyname,
4581 char *, ip->bi_cluster);
4582 rc = II_UNLINK_CLUSTER(ip);
4583 }
4584 } else if (!ip->bi_cluster) {
4585 /* are we adding it to a group for the first time? */
4586 rc = II_LINK_CLUSTER(ip, umove.new_group);
4587 DTRACE_PROBE2(_ii_change_tag, char *, ip->bi_keyname,
4588 char *, ip->bi_cluster);
4589 } else {
4590 /* remove it from one group and add it to the other */
4591 DTRACE_PROBE3(_ii_change_tag_2, char *, ip->bi_keyname,
4592 char *, ip->bi_cluster, char *, umove.new_group);
4593 rc = II_UNLINK_CLUSTER(ip);
4594 if (!rc)
4595 rc = II_LINK_CLUSTER(ip, umove.new_group);
4596 }
4597
4598 /* ** BEGIN UPDATE BITMAP HEADER ** */
4599 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
4600 _ii_ioctl_done(ip);
4601 mutex_exit(&ip->bi_mutex);
4602 spcs_s_add(kstatus, rc);
4603 return (spcs_s_ocopyoutf(&kstatus, umove.status,
4604 DSW_ERSRVFAIL));
4605 }
4606 bm_header = _ii_bm_header_get(ip, &tmp);
4607 if (bm_header) {
4608 (void) strncpy(bm_header->clstr_name, umove.new_group,
4609 DSW_NAMELEN);
4610 (void) _ii_bm_header_put(bm_header, ip, tmp);
4611 }
4612 _ii_rlse_devs(ip, BMP);
4613 /* ** END UPDATE BITMAP HEADER ** */
4614
4615 _ii_ioctl_done(ip);
4616 mutex_exit(&ip->bi_mutex);
4617
4618 return (spcs_s_ocopyoutf(&kstatus, umove.status, rc));
4619 }
4620
4621
4622 /*
4623 * _ii_spcs_s_ocopyoutf()
4624 * Wrapper for spcs_s_ocopyoutf() used by _ii_chk_copy() which permits
4625 * the spcs_s_info_t argument to be NULL. _ii_chk_copy() requires this
4626 * functionality as it is sometimes called by _ii_control_copy() which
4627 * has no user context to copy any errors into. At all other times a NULL
4628 * spcs_s_info_t argument would indicate a bug in the calling function.
4629 */
4630
4631 static int
_ii_spcs_s_ocopyoutf(spcs_s_info_t * kstatusp,spcs_s_info_t ustatus,int err)4632 _ii_spcs_s_ocopyoutf(spcs_s_info_t *kstatusp, spcs_s_info_t ustatus, int err)
4633 {
4634 if (ustatus)
4635 return (spcs_s_ocopyoutf(kstatusp, ustatus, err));
4636 spcs_s_kfree(*kstatusp);
4637 return (err);
4638 }
4639
4640 static int
_ii_chk_copy(_ii_info_t * ip,int flags,spcs_s_info_t * kstatusp,pid_t pid,spcs_s_info_t ustatus)4641 _ii_chk_copy(_ii_info_t *ip, int flags, spcs_s_info_t *kstatusp, pid_t pid,
4642 spcs_s_info_t ustatus)
4643 {
4644 _ii_info_t *xip;
4645 int rc;
4646 int rtype;
4647
4648 if ((ip->bi_flags & DSW_COPYINGP) != 0) {
4649 _ii_ioctl_done(ip);
4650 mutex_exit(&ip->bi_mutex);
4651 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus, DSW_ECOPYING));
4652 }
4653
4654 if (ip->bi_flags & DSW_OFFLINE) {
4655 _ii_ioctl_done(ip);
4656 mutex_exit(&ip->bi_mutex);
4657 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus, DSW_EOFFLINE));
4658 }
4659
4660 if ((ip->bi_flags & (DSW_SHDIMPORT|DSW_SHDEXPORT)) != 0) {
4661 _ii_ioctl_done(ip);
4662 mutex_exit(&ip->bi_mutex);
4663 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4664 DSW_EISEXPORTED));
4665 }
4666
4667 if ((flags & CV_SHD2MST) == CV_SHD2MST) {
4668 if ((ip->bi_flags & DSW_COPYINGM) != 0) {
4669 _ii_ioctl_done(ip);
4670 mutex_exit(&ip->bi_mutex);
4671 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4672 DSW_ECOPYING));
4673 }
4674 /* check if any sibling shadow is copying towards this master */
4675 for (xip = ip->bi_head; xip; xip = xip->bi_sibling) {
4676 if (ip != xip && (xip->bi_flags & DSW_COPYINGS) != 0) {
4677 _ii_ioctl_done(ip);
4678 mutex_exit(&ip->bi_mutex);
4679 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4680 DSW_ECOPYING));
4681 }
4682 }
4683 }
4684
4685 if (((flags & CV_SHD2MST) == 0) &&
4686 ((ip->bi_flags & DSW_COPYINGS) != 0)) {
4687 _ii_ioctl_done(ip);
4688 mutex_exit(&ip->bi_mutex);
4689 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus, DSW_ECOPYING));
4690 }
4691
4692 if (ip->bi_flags & DSW_TREEMAP) {
4693 if ((ip->bi_flags & DSW_OVERFLOW) && (flags & CV_SHD2MST)) {
4694 _ii_ioctl_done(ip);
4695 mutex_exit(&ip->bi_mutex);
4696 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4697 DSW_EINCOMPLETE));
4698 }
4699 }
4700
4701 /* Assure that no other PID owns this copy/update */
4702 if (ip->bi_locked_pid == 0) {
4703 if (flags & CV_LOCK_PID)
4704 ip->bi_locked_pid = pid;
4705 } else if (ip->bi_locked_pid != pid) {
4706 _ii_ioctl_done(ip);
4707 mutex_exit(&ip->bi_mutex);
4708 return (spcs_s_ocopyoutf(kstatusp, ustatus, DSW_EINUSE));
4709 }
4710
4711 mutex_exit(&ip->bi_mutex);
4712
4713 rtype = MSTR|SHDR|BMP;
4714 if ((rc = _ii_rsrv_devs(ip, rtype, II_INTERNAL)) != 0) {
4715 mutex_enter(&ip->bi_mutex);
4716 _ii_ioctl_done(ip);
4717 mutex_exit(&ip->bi_mutex);
4718 spcs_s_add(*kstatusp, rc);
4719 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4720 DSW_ERSRVFAIL));
4721 }
4722
4723 if (ii_update_denied(ip, *kstatusp, flags & CV_SHD2MST, 0)) {
4724 mutex_enter(&ip->bi_mutex);
4725 _ii_ioctl_done(ip);
4726 mutex_exit(&ip->bi_mutex);
4727 _ii_rlse_devs(ip, rtype);
4728 return (_ii_spcs_s_ocopyoutf(kstatusp, ustatus,
4729 DSW_EOPACKAGE));
4730 }
4731
4732 return (0);
4733 }
4734
4735 static int
_ii_do_copy(_ii_info_t * ip,int flags,spcs_s_info_t kstatus,int waitflag)4736 _ii_do_copy(_ii_info_t *ip, int flags, spcs_s_info_t kstatus, int waitflag)
4737 {
4738 int rc = 0;
4739 int rtype = MSTR|SHDR|BMP;
4740 _ii_overflow_t *op;
4741 int quick_update = 0;
4742
4743 waitflag = (waitflag != 0);
4744 /*
4745 * a copy of a tree-mapped device must be downgraded to
4746 * an update.
4747 */
4748 if (ip->bi_flags & DSW_TREEMAP)
4749 flags |= CV_BMP_ONLY;
4750
4751 /*
4752 * If we want to update the dependent shadow we only need to zero
4753 * the shadow bitmap.
4754 */
4755
4756 if (((ip->bi_flags & DSW_GOLDEN) == 0) &&
4757 (flags & (CV_BMP_ONLY|CV_SHD2MST)) == CV_BMP_ONLY) {
4758
4759 DTRACE_PROBE(DEPENDENT);
4760
4761 /* assign updating time */
4762 ip->bi_mtime = ddi_get_time();
4763
4764 if (ip->bi_flags & DSW_TREEMAP) {
4765 DTRACE_PROBE(COMPACT_DEPENDENT);
4766
4767 if (ip->bi_overflow &&
4768 (ip->bi_overflow->ii_flags & IIO_VOL_UPDATE) == 0) {
4769 /* attempt to do a quick update */
4770 quick_update = 1;
4771 ip->bi_overflow->ii_flags |= IIO_VOL_UPDATE;
4772 ip->bi_overflow->ii_detachcnt = 1;
4773 }
4774
4775 rc = ii_tinit(ip);
4776
4777 if (quick_update && ip->bi_overflow) {
4778 /* clean up */
4779 ip->bi_overflow->ii_flags &= ~(IIO_VOL_UPDATE);
4780 ip->bi_overflow->ii_detachcnt = 0;
4781 }
4782 }
4783
4784 if (rc == 0)
4785 rc = II_ZEROBM(ip); /* update copy of shadow */
4786 if (((op = ip->bi_overflow) != NULL) &&
4787 (op->ii_hversion >= 1) && (op->ii_hmagic == II_OMAGIC)) {
4788 mutex_enter(&_ii_overflow_mutex);
4789 if (ip->bi_flags & DSW_OVRHDRDRTY) {
4790 mutex_enter(&ip->bi_mutex);
4791 ip->bi_flags &= ~DSW_OVRHDRDRTY;
4792 mutex_exit(&ip->bi_mutex);
4793 ASSERT(op->ii_urefcnt > 0);
4794 op->ii_urefcnt--;
4795 }
4796 if (op->ii_urefcnt == 0) {
4797 op->ii_flags &= ~IIO_CNTR_INVLD;
4798 op->ii_unused = op->ii_nchunks - 1;
4799 }
4800 mutex_exit(&_ii_overflow_mutex);
4801 }
4802 mutex_enter(&ip->bi_mutex);
4803 II_FLAG_CLR(DSW_OVERFLOW, ip);
4804 mutex_exit(&ip->bi_mutex);
4805
4806 _ii_unlock_chunk(ip, II_NULLCHUNK);
4807 mutex_enter(&ip->bi_mutex);
4808 _ii_ioctl_done(ip);
4809 mutex_exit(&ip->bi_mutex);
4810 _ii_rlse_devs(ip, rtype);
4811 if (rc) {
4812 spcs_s_add(kstatus, rc);
4813 return (DSW_EIO);
4814 } else {
4815 DTRACE_PROBE(_ii_do_copy_end);
4816 return (0);
4817 }
4818 }
4819
4820 /*
4821 * need to perform an actual copy.
4822 */
4823
4824 /*
4825 * Perform bitmap copy if asked or from dependent shadow to master.
4826 */
4827 if ((flags & CV_BMP_ONLY) ||
4828 ((flags & CV_SHD2MST) &&
4829 ((ip->bi_flags & DSW_GOLDEN) == 0))) {
4830 DTRACE_PROBE(INDEPENDENT_fast);
4831 rc = II_ORBM(ip); /* save shadow bits for copy */
4832 } else {
4833 DTRACE_PROBE(INDEPENDENT_slow);
4834 rc = ii_fill_copy_bmp(ip); /* set bits for independent copy */
4835 }
4836 if (rc == 0)
4837 rc = II_ZEROBM(ip);
4838 _ii_unlock_chunk(ip, II_NULLCHUNK);
4839 if (rc == 0) {
4840 mutex_enter(&ip->bi_mutex);
4841 if (ip->bi_flags & (DSW_COPYINGP | DSW_SHDEXPORT)) {
4842 rc = (ip->bi_flags & DSW_COPYINGP)
4843 ? DSW_ECOPYING : DSW_EISEXPORTED;
4844
4845 _ii_ioctl_done(ip);
4846 mutex_exit(&ip->bi_mutex);
4847 _ii_rlse_devs(ip, rtype);
4848 return (rc);
4849 }
4850
4851 /* assign copying time */
4852 ip->bi_mtime = ddi_get_time();
4853
4854 if (flags & CV_SHD2MST)
4855 II_FLAG_SET(DSW_COPYINGS | DSW_COPYINGP, ip);
4856 else
4857 II_FLAG_SET(DSW_COPYINGM | DSW_COPYINGP, ip);
4858 mutex_exit(&ip->bi_mutex);
4859 rc = _ii_copyvol(ip, (flags & CV_SHD2MST),
4860 rtype, kstatus, waitflag);
4861 } else {
4862 mutex_enter(&ip->bi_mutex);
4863 _ii_ioctl_done(ip);
4864 mutex_exit(&ip->bi_mutex);
4865 }
4866
4867 if (waitflag)
4868 _ii_rlse_devs(ip, rtype);
4869
4870 return (rc);
4871 }
4872
4873 /*
4874 * _ii_copy
4875 * Copy or update (take snapshot) II volume.
4876 *
4877 * Calling/Exit State:
4878 * Returns 0 if the operation succeeded. Otherwise an error code
4879 * is returned and any additional error information is copied
4880 * out to the user.
4881 */
4882
4883 int
_ii_copy(intptr_t arg,int ilp32,int * rvp)4884 _ii_copy(intptr_t arg, int ilp32, int *rvp)
4885 {
4886 dsw_ioctl_t ucopy;
4887 dsw_ioctl32_t ucopy32;
4888 _ii_info_t *ip;
4889 int rc = 0;
4890 spcs_s_info_t kstatus;
4891
4892 *rvp = 0;
4893
4894 if (ilp32) {
4895 if (copyin((void *)arg, &ucopy32, sizeof (ucopy32)) < 0)
4896 return (EFAULT);
4897 II_TAIL_COPY(ucopy, ucopy32, shadow_vol, dsw_ioctl_t);
4898 ucopy.status = (spcs_s_info_t)ucopy32.status;
4899 } else if (copyin((void *)arg, &ucopy, sizeof (ucopy)) < 0)
4900 return (EFAULT);
4901
4902 kstatus = spcs_s_kcreate();
4903 if (kstatus == NULL)
4904 return (ENOMEM);
4905
4906 if (!ucopy.shadow_vol[0])
4907 return (spcs_s_ocopyoutf(&kstatus, ucopy.status, DSW_EEMPTY));
4908
4909 mutex_enter(&_ii_info_mutex);
4910 ip = _ii_find_set(ucopy.shadow_vol);
4911 mutex_exit(&_ii_info_mutex);
4912 if (ip == NULL)
4913 return (spcs_s_ocopyoutf(&kstatus, ucopy.status,
4914 DSW_ENOTFOUND));
4915
4916 /* Check that the copy/update makes sense */
4917 if ((rc = _ii_chk_copy(ip, ucopy.flags, &kstatus, ucopy.pid,
4918 ucopy.status)) == 0) {
4919 /* perform the copy */
4920 _ii_lock_chunk(ip, II_NULLCHUNK);
4921 /* _ii_do_copy() calls _ii_ioctl_done() */
4922 rc = _ii_do_copy(ip, ucopy.flags, kstatus, 1);
4923 return (spcs_s_ocopyoutf(&kstatus, ucopy.status, rc));
4924 }
4925
4926 return (rc);
4927 }
4928
4929 /*
4930 * _ii_mass_copy
4931 * Copies/updates the sets pointed to in the ipa array.
4932 *
4933 * Calling/Exit State:
4934 * Returns 0 if the operations was successful. Otherwise an
4935 * error code.
4936 */
4937 int
_ii_mass_copy(_ii_info_t ** ipa,dsw_aioctl_t * ucopy,int wait)4938 _ii_mass_copy(_ii_info_t **ipa, dsw_aioctl_t *ucopy, int wait)
4939 {
4940 int i;
4941 int rc = 0;
4942 int failed;
4943 int rtype = MSTR|SHDR|BMP;
4944 _ii_info_t *ip;
4945 spcs_s_info_t kstatus;
4946
4947 kstatus = spcs_s_kcreate();
4948 if (kstatus == NULL)
4949 return (ENOMEM);
4950
4951 /* Check copy validitity */
4952 for (i = 0; i < ucopy->count; i++) {
4953 ip = ipa[i];
4954
4955 rc = _ii_chk_copy(ip, ucopy->flags, &kstatus, ucopy->pid,
4956 ucopy->status);
4957
4958 if (rc) {
4959 /* Clean up the mess */
4960
4961 DTRACE_PROBE1(_ii_mass_copy_end1, int, rc);
4962
4963 /*
4964 * The array ipa now looks like:
4965 * 0..(i-1): needs mutex_enter/ioctl_done/mutex_exit
4966 * i: needs nothing (_ii_chk_copy does cleanup)
4967 * (i+1)..n: needs just ioctl_done/mutex_exit
4968 */
4969
4970 failed = i;
4971
4972 for (i = 0; i < failed; i++) {
4973 mutex_enter(&(ipa[i]->bi_mutex));
4974 _ii_ioctl_done(ipa[i]);
4975 mutex_exit(&(ipa[i]->bi_mutex));
4976 _ii_rlse_devs(ipa[i], rtype);
4977 }
4978
4979 /* skip 'failed', start with failed + 1 */
4980
4981 for (i = failed + 1; i < ucopy->count; i++) {
4982 _ii_ioctl_done(ipa[i]);
4983 mutex_exit(&(ipa[i]->bi_mutex));
4984 }
4985
4986 return (rc);
4987 }
4988 }
4989
4990 /* Check for duplicate shadows in same II group */
4991 if (ucopy->flags & CV_SHD2MST) {
4992 /* Reset the state of all masters */
4993 for (i = 0; i < ucopy->count; i++) {
4994 ip = ipa[i];
4995 ip->bi_master->bi_state &= ~DSW_MSTTARGET;
4996 }
4997
4998 for (i = 0; i < ucopy->count; i++) {
4999 ip = ipa[i];
5000 /*
5001 * Check the state of the master. If DSW_MSTTARGET is
5002 * set, it's because this master is attached to another
5003 * shadow within this set.
5004 */
5005 if (ip->bi_master->bi_state & DSW_MSTTARGET) {
5006 rc = EINVAL;
5007 break;
5008 }
5009
5010 /*
5011 * Set the DSW_MSTTARGET bit on the master associated
5012 * with this shadow. This will allow us to detect
5013 * multiple shadows pointing to this master within
5014 * this loop.
5015 */
5016 ip->bi_master->bi_state |= DSW_MSTTARGET;
5017 }
5018 }
5019
5020 /* Handle error */
5021 if (rc) {
5022 DTRACE_PROBE1(_ii_mass_copy_end2, int, rc);
5023 for (i = 0; i < ucopy->count; i++) {
5024 ip = ipa[i];
5025
5026 _ii_rlse_devs(ip, rtype);
5027
5028 mutex_enter(&ip->bi_mutex);
5029 _ii_ioctl_done(ip);
5030 mutex_exit(&ip->bi_mutex);
5031 }
5032
5033 return (spcs_s_ocopyoutf(&kstatus, ucopy->status, rc));
5034 }
5035
5036 /* Lock bitmaps & prepare counts */
5037 for (i = 0; i < ucopy->count; i++) {
5038 ip = ipa[i];
5039 _ii_lock_chunk(ip, II_NULLCHUNK);
5040 if (ip->bi_overflow) {
5041 ip->bi_overflow->ii_detachcnt = 0;
5042 }
5043 }
5044
5045 /* determine which volumes we're dealing with */
5046 for (i = 0; i < ucopy->count; i++) {
5047 ip = ipa[i];
5048 if (ip->bi_overflow) {
5049 ip->bi_overflow->ii_flags |= IIO_VOL_UPDATE;
5050 if ((ucopy->flags & (CV_BMP_ONLY|CV_SHD2MST)) ==
5051 CV_BMP_ONLY) {
5052 ++ip->bi_overflow->ii_detachcnt;
5053 }
5054 }
5055 }
5056
5057 /* Perform copy */
5058 for (i = 0; i < ucopy->count; i++) {
5059 ip = ipa[i];
5060 rc = _ii_do_copy(ip, ucopy->flags, kstatus, wait);
5061 /* Hum... what to do if one of these fails? */
5062 }
5063
5064 /* clear out flags so as to prevent any accidental reuse */
5065 for (i = 0; i < ucopy->count; i++) {
5066 ip = ipa[i];
5067 if (ip->bi_overflow)
5068 ip->bi_overflow->ii_flags &= ~(IIO_VOL_UPDATE);
5069 }
5070
5071 /*
5072 * We can only clean up the kstatus structure if there are
5073 * no waiters. If someone's waiting for the information,
5074 * _ii_copyvolp() uses spcs_s_add to write to kstatus. Panic
5075 * would ensue if we freed it up now.
5076 */
5077 if (!wait)
5078 rc = spcs_s_ocopyoutf(&kstatus, ucopy->status, rc);
5079
5080 return (rc);
5081 }
5082
5083 /*
5084 * _ii_list_copy
5085 * Retrieve a list from a character array and use _ii_mass_copy to
5086 * initiate a copy/update operation on all of the specified sets.
5087 *
5088 * Calling/Exit State:
5089 * Returns 0 if the operations was successful. Otherwise an
5090 * error code.
5091 */
5092 int
_ii_list_copy(char * list,dsw_aioctl_t * ucopy,int wait)5093 _ii_list_copy(char *list, dsw_aioctl_t *ucopy, int wait)
5094 {
5095 int i;
5096 int rc = 0;
5097 char *name;
5098 _ii_info_t *ip;
5099 _ii_info_t **ipa;
5100
5101 ipa = kmem_zalloc(sizeof (_ii_info_t *) * ucopy->count, KM_SLEEP);
5102
5103 /* Reserve devices */
5104 name = list;
5105 mutex_enter(&_ii_info_mutex);
5106 for (i = 0; i < ucopy->count; i++, name += DSW_NAMELEN) {
5107 ip = _ii_find_set(name);
5108
5109 if (ip == NULL) {
5110 rc = DSW_ENOTFOUND;
5111 break;
5112 }
5113
5114 ipa[i] = ip;
5115 }
5116
5117 if (rc != 0) {
5118 /* Failed to find all sets, release those we do have */
5119 while (i-- > 0) {
5120 ip = ipa[i];
5121 mutex_enter(&ip->bi_mutex);
5122 _ii_ioctl_done(ip);
5123 mutex_exit(&ip->bi_mutex);
5124 }
5125 } else {
5126 /* Begin copy operation */
5127 rc = _ii_mass_copy(ipa, ucopy, wait);
5128 }
5129
5130 mutex_exit(&_ii_info_mutex);
5131
5132 kmem_free(ipa, sizeof (_ii_info_t *) * ucopy->count);
5133
5134 return (rc);
5135 }
5136
5137 /*
5138 * _ii_group_copy
5139 * Retrieve list of sets in a group and use _ii_mass_copy to initiate
5140 * a copy/update of all of them.
5141 *
5142 * Calling/Exit State:
5143 * Returns 0 if the operations was successful. Otherwise an
5144 * error code.
5145 */
5146 int
_ii_group_copy(char * name,dsw_aioctl_t * ucopy,int wait)5147 _ii_group_copy(char *name, dsw_aioctl_t *ucopy, int wait)
5148 {
5149 int i;
5150 int rc;
5151 uint64_t hash;
5152 _ii_info_t **ipa;
5153 _ii_lsthead_t *head;
5154 _ii_lstinfo_t *np;
5155
5156 /* find group */
5157 hash = nsc_strhash(name);
5158
5159 mutex_enter(&_ii_group_mutex);
5160
5161 for (head = _ii_group_top; head; head = head->lst_next) {
5162 if (hash == head->lst_hash && strncmp(head->lst_name,
5163 name, DSW_NAMELEN) == 0)
5164 break;
5165 }
5166
5167 if (!head) {
5168 mutex_exit(&_ii_group_mutex);
5169 DTRACE_PROBE(_ii_group_copy);
5170 return (DSW_EGNOTFOUND);
5171 }
5172
5173 /* Count entries */
5174 for (ucopy->count = 0, np = head->lst_start; np; np = np->lst_next)
5175 ++ucopy->count;
5176
5177 if (ucopy->count == 0) {
5178 mutex_exit(&_ii_group_mutex);
5179 return (DSW_EGNOTFOUND);
5180 }
5181
5182 ipa = kmem_zalloc(sizeof (_ii_info_t *) * ucopy->count, KM_SLEEP);
5183 if (ipa == NULL) {
5184 mutex_exit(&_ii_group_mutex);
5185 return (ENOMEM);
5186 }
5187
5188 /* Create list */
5189 mutex_enter(&_ii_info_mutex);
5190 np = head->lst_start;
5191 for (i = 0; i < ucopy->count; i++) {
5192 ASSERT(np != 0);
5193
5194 ipa[i] = np->lst_ip;
5195
5196 mutex_enter(&ipa[i]->bi_mutex);
5197 ipa[i]->bi_ioctl++;
5198
5199 np = np->lst_next;
5200 }
5201
5202 /* Begin copy operation */
5203 rc = _ii_mass_copy(ipa, ucopy, wait);
5204
5205 mutex_exit(&_ii_info_mutex);
5206 mutex_exit(&_ii_group_mutex);
5207
5208 kmem_free(ipa, sizeof (_ii_info_t *) * ucopy->count);
5209
5210 return (rc);
5211 }
5212
5213 /*
5214 * _ii_acopy
5215 * Copy or update (take snapshot) II multiple volumes.
5216 *
5217 * Calling/Exit State:
5218 * Returns 0 if the operation succeeded. Otherwise an error code
5219 * is returned and any additional error information is copied
5220 * out to the user.
5221 */
5222 int
_ii_acopy(intptr_t arg,int ilp32,int * rvp)5223 _ii_acopy(intptr_t arg, int ilp32, int *rvp)
5224 {
5225 int rc;
5226 size_t name_offset;
5227 char *list;
5228 char *nptr;
5229 char name[DSW_NAMELEN];
5230 dsw_aioctl_t ucopy;
5231 dsw_aioctl32_t ucopy32;
5232 spcs_s_info_t kstatus;
5233
5234 *rvp = 0;
5235
5236 name_offset = offsetof(dsw_aioctl_t, shadow_vol[0]);
5237
5238 if (ilp32) {
5239 if (copyin((void *)arg, &ucopy32, sizeof (ucopy32)) < 0)
5240 return (EFAULT);
5241 II_TAIL_COPY(ucopy, ucopy32, flags, dsw_ioctl_t);
5242 ucopy.status = (spcs_s_info_t)ucopy32.status;
5243 name_offset = offsetof(dsw_aioctl32_t, shadow_vol[0]);
5244 } else if (copyin((void *)arg, &ucopy, sizeof (ucopy)) < 0)
5245 return (EFAULT);
5246
5247 kstatus = spcs_s_kcreate();
5248
5249 if (kstatus == NULL)
5250 return (ENOMEM);
5251
5252 nptr = (char *)arg + name_offset;
5253 rc = 0;
5254
5255 if (ucopy.flags & CV_IS_GROUP) {
5256 if (copyin(nptr, name, DSW_NAMELEN) < 0)
5257 return (spcs_s_ocopyoutf(&kstatus, ucopy.status,
5258 EFAULT));
5259
5260 /* kstatus information is handled within _ii_group_copy */
5261 rc = _ii_group_copy(name, &ucopy, 0);
5262 } else if (ucopy.count > 0) {
5263 list = kmem_alloc(DSW_NAMELEN * ucopy.count, KM_SLEEP);
5264
5265 if (list == NULL)
5266 return (spcs_s_ocopyoutf(&kstatus, ucopy.status,
5267 ENOMEM));
5268
5269 if (copyin(nptr, list, DSW_NAMELEN * ucopy.count) < 0)
5270 return (spcs_s_ocopyoutf(&kstatus, ucopy.status,
5271 EFAULT));
5272
5273 rc = _ii_list_copy(list, &ucopy, 0);
5274 kmem_free(list, DSW_NAMELEN * ucopy.count);
5275 }
5276
5277 return (spcs_s_ocopyoutf(&kstatus, ucopy.status, rc));
5278 }
5279
5280 /*
5281 * _ii_bitsset
5282 * Copy out II pair bitmaps to user program
5283 *
5284 * Calling/Exit State:
5285 * Returns 0 if the operation succeeded. Otherwise an error code
5286 * is returned and any additional error information is copied
5287 * out to the user.
5288 */
5289 int
_ii_bitsset(intptr_t arg,int ilp32,int cmd,int * rvp)5290 _ii_bitsset(intptr_t arg, int ilp32, int cmd, int *rvp)
5291 {
5292 dsw_bitsset_t ubitsset;
5293 dsw_bitsset32_t ubitsset32;
5294 nsc_size_t nbitsset;
5295 _ii_info_t *ip;
5296 int rc;
5297 spcs_s_info_t kstatus;
5298 int bitmap_size;
5299
5300 *rvp = 0;
5301
5302 if (ilp32) {
5303 if (copyin((void *)arg, &ubitsset32, sizeof (ubitsset32)))
5304 return (EFAULT);
5305 ubitsset.status = (spcs_s_info_t)ubitsset32.status;
5306 bcopy(ubitsset32.shadow_vol, ubitsset.shadow_vol, DSW_NAMELEN);
5307 } else if (copyin((void *)arg, &ubitsset, sizeof (ubitsset)))
5308 return (EFAULT);
5309
5310 kstatus = spcs_s_kcreate();
5311 if (kstatus == NULL)
5312 return (ENOMEM);
5313
5314 if (!ubitsset.shadow_vol[0])
5315 return (spcs_s_ocopyoutf(&kstatus, ubitsset.status,
5316 DSW_EEMPTY));
5317
5318 mutex_enter(&_ii_info_mutex);
5319 ip = _ii_find_set(ubitsset.shadow_vol);
5320 mutex_exit(&_ii_info_mutex);
5321 if (ip == NULL)
5322 return (spcs_s_ocopyoutf(&kstatus, ubitsset.status,
5323 DSW_ENOTFOUND));
5324
5325 mutex_exit(&ip->bi_mutex);
5326
5327 if ((rc = _ii_rsrv_devs(ip, BMP, II_INTERNAL)) != 0) {
5328 mutex_enter(&ip->bi_mutex);
5329 _ii_ioctl_done(ip);
5330 mutex_exit(&ip->bi_mutex);
5331 spcs_s_add(kstatus, rc);
5332 return (spcs_s_ocopyoutf(&kstatus, ubitsset.status,
5333 DSW_ERSRVFAIL));
5334 }
5335
5336 ubitsset.tot_size = ip->bi_size / DSW_SIZE;
5337 if ((ip->bi_size % DSW_SIZE) != 0)
5338 ++ubitsset.tot_size;
5339 bitmap_size = (ubitsset.tot_size + 7) / 8;
5340 if (cmd == DSWIOC_SBITSSET)
5341 rc = II_CNT_BITS(ip, ip->bi_shdfba, &nbitsset, bitmap_size);
5342 else
5343 rc = II_CNT_BITS(ip, ip->bi_copyfba, &nbitsset, bitmap_size);
5344 ubitsset.tot_set = nbitsset;
5345 _ii_rlse_devs(ip, BMP);
5346 mutex_enter(&ip->bi_mutex);
5347 _ii_ioctl_done(ip);
5348 mutex_exit(&ip->bi_mutex);
5349 if (rc) {
5350 spcs_s_add(kstatus, rc);
5351 return (spcs_s_ocopyoutf(&kstatus, ubitsset.status, DSW_EIO));
5352 }
5353
5354 spcs_s_kfree(kstatus);
5355 /* return the fetched names to the user */
5356 if (ilp32) {
5357 ubitsset32.status = (spcs_s_info32_t)ubitsset.status;
5358 ubitsset32.tot_size = ubitsset.tot_size;
5359 ubitsset32.tot_set = ubitsset.tot_set;
5360 rc = copyout(&ubitsset32, (void *)arg, sizeof (ubitsset32));
5361 } else {
5362 rc = copyout(&ubitsset, (void *)arg, sizeof (ubitsset));
5363 }
5364
5365 return (rc);
5366 }
5367
5368 /*
5369 * _ii_stopvol
5370 * Stop any copying process for shadow, and stop shadowing
5371 *
5372 */
5373
5374 static void
_ii_stopvol(_ii_info_t * ip)5375 _ii_stopvol(_ii_info_t *ip)
5376 {
5377 nsc_path_t *mst_tok;
5378 nsc_path_t *mstr_tok;
5379 nsc_path_t *shd_tok;
5380 nsc_path_t *shdr_tok;
5381 nsc_path_t *bmp_tok;
5382 int rc;
5383
5384 while (_ii_stopcopy(ip) == EINTR)
5385 ;
5386
5387 DTRACE_PROBE(_ii_stopvol);
5388
5389 mutex_enter(&ip->bi_mutex);
5390 mst_tok = ip->bi_mst_tok;
5391 mstr_tok = ip->bi_mstr_tok;
5392 shd_tok = ip->bi_shd_tok;
5393 shdr_tok = ip->bi_shdr_tok;
5394 bmp_tok = ip->bi_bmp_tok;
5395 ip->bi_shd_tok = 0;
5396 ip->bi_shdr_tok = 0;
5397 if (!NSHADOWS(ip)) {
5398 ip->bi_mst_tok = 0;
5399 ip->bi_mstr_tok = 0;
5400 }
5401 ip->bi_bmp_tok = 0;
5402
5403 /* Wait for any _ii_open() calls to complete */
5404
5405 while (ip->bi_ioctl) {
5406 ip->bi_state |= DSW_IOCTL;
5407 cv_wait(&ip->bi_ioctlcv, &ip->bi_mutex);
5408 }
5409 mutex_exit(&ip->bi_mutex);
5410
5411 rc = _ii_reserve_begin(ip);
5412 if (rc) {
5413 cmn_err(CE_WARN, "!_ii_stopvol: _ii_reserve_begin %d", rc);
5414 }
5415 if (!NSHADOWS(ip)) {
5416 if (mst_tok) {
5417 rc = _ii_unregister_path(mst_tok, NSC_PCATCH,
5418 "master");
5419 if (rc)
5420 cmn_err(CE_WARN, "!ii: unregister master %d",
5421 rc);
5422 }
5423
5424 if (mstr_tok) {
5425 rc = _ii_unregister_path(mstr_tok, NSC_PCATCH,
5426 "raw master");
5427 if (rc)
5428 cmn_err(CE_WARN, "!ii: unregister raw "
5429 "master %d", rc);
5430 }
5431 }
5432
5433 if (shd_tok) {
5434 rc = _ii_unregister_path(shd_tok, NSC_PCATCH, "shadow");
5435 if (rc)
5436 cmn_err(CE_WARN, "!ii: unregister shadow %d", rc);
5437 }
5438
5439 if (shdr_tok) {
5440 rc = _ii_unregister_path(shdr_tok, NSC_PCATCH, "raw shadow");
5441 if (rc)
5442 cmn_err(CE_WARN, "!ii: unregister raw shadow %d", rc);
5443 }
5444
5445 if (bmp_tok) {
5446 rc = _ii_unregister_path(bmp_tok, NSC_PCATCH, "bitmap");
5447 if (rc)
5448 cmn_err(CE_WARN, "!ii: unregister bitmap %d", rc);
5449 }
5450 _ii_reserve_end(ip);
5451
5452 /* Wait for all necessary _ii_close() calls to complete */
5453 mutex_enter(&ip->bi_mutex);
5454
5455 while (total_ref(ip) != 0) {
5456 ip->bi_state |= DSW_CLOSING;
5457 cv_wait(&ip->bi_closingcv, &ip->bi_mutex);
5458 }
5459 if (!NSHADOWS(ip)) {
5460 nsc_set_owner(ip->bi_mstfd, NULL);
5461 nsc_set_owner(ip->bi_mstrfd, NULL);
5462 }
5463 nsc_set_owner(ip->bi_shdfd, NULL);
5464 nsc_set_owner(ip->bi_shdrfd, NULL);
5465 mutex_exit(&ip->bi_mutex);
5466
5467 }
5468
5469
5470 /*
5471 * _ii_ioctl_done
5472 * If this is the last one to complete, wakeup all processes waiting
5473 * for ioctls to complete
5474 *
5475 */
5476
5477 static void
_ii_ioctl_done(_ii_info_t * ip)5478 _ii_ioctl_done(_ii_info_t *ip)
5479 {
5480 ASSERT(ip->bi_ioctl > 0);
5481 ip->bi_ioctl--;
5482 if (ip->bi_ioctl == 0 && (ip->bi_state & DSW_IOCTL)) {
5483 ip->bi_state &= ~DSW_IOCTL;
5484 cv_broadcast(&ip->bi_ioctlcv);
5485 }
5486
5487 }
5488
5489 /*
5490 * _ii_find_vol
5491 * Search the configured shadows list for the supplied volume.
5492 * If found, flag an ioctl in progress and return the locked _ii_info_t.
5493 *
5494 * The caller must check to see if the bi_disable flag is set and
5495 * treat it appropriately.
5496 *
5497 * ASSUMPTION:
5498 * _ii_info_mutex must be locked prior to calling this function
5499 *
5500 */
5501
5502 static _ii_info_t *
_ii_find_vol(char * volume,int vol)5503 _ii_find_vol(char *volume, int vol)
5504 {
5505 _ii_info_t **xip, *ip;
5506
5507 for (xip = &_ii_info_top; *xip; xip = &(*xip)->bi_next) {
5508 if ((*xip)->bi_disabled)
5509 continue;
5510 if (strcmp(volume, vol == MST ? ii_pathname((*xip)->bi_mstfd) :
5511 (*xip)->bi_keyname) == 0) {
5512 break;
5513 }
5514 }
5515
5516 if (!*xip) {
5517 DTRACE_PROBE(VolNotFound);
5518 return (NULL);
5519 }
5520
5521 ip = *xip;
5522 if (!ip->bi_shd_tok && ((ip->bi_flags & DSW_SHDEXPORT) == 0)) {
5523 /* Not fully configured until bi_shd_tok is set */
5524 DTRACE_PROBE(SetNotConfiged);
5525 return (NULL);
5526
5527 }
5528 mutex_enter(&ip->bi_mutex);
5529 ip->bi_ioctl++;
5530
5531 return (ip);
5532 }
5533
5534 static _ii_info_t *
_ii_find_set(char * volume)5535 _ii_find_set(char *volume)
5536 {
5537 return (_ii_find_vol(volume, SHD));
5538 }
5539
5540 /*
5541 * _ii_find_overflow
5542 * Search the configured shadows list for the supplied overflow volume.
5543 *
5544 */
5545
5546 static _ii_overflow_t *
_ii_find_overflow(char * volume)5547 _ii_find_overflow(char *volume)
5548 {
5549 _ii_overflow_t **xop, *op;
5550
5551 mutex_enter(&_ii_overflow_mutex);
5552
5553 DTRACE_PROBE(_ii_find_overflowmutex);
5554
5555 for (xop = &_ii_overflow_top; *xop; xop = &(*xop)->ii_next) {
5556 if (strcmp(volume, (*xop)->ii_volname) == 0) {
5557 break;
5558 }
5559 }
5560
5561 if (!*xop) {
5562 mutex_exit(&_ii_overflow_mutex);
5563 return (NULL);
5564 }
5565
5566 op = *xop;
5567 mutex_exit(&_ii_overflow_mutex);
5568
5569 return (op);
5570 }
5571
5572 /*
5573 * _ii_bm_header_get
5574 * Fetch the bitmap volume header
5575 *
5576 */
5577
5578 ii_header_t *
_ii_bm_header_get(_ii_info_t * ip,nsc_buf_t ** tmp)5579 _ii_bm_header_get(_ii_info_t *ip, nsc_buf_t **tmp)
5580 {
5581 ii_header_t *hdr;
5582 nsc_off_t read_fba;
5583 int rc;
5584
5585 ASSERT(ip->bi_bmprsrv); /* assert bitmap is reserved */
5586 ASSERT(MUTEX_HELD(&ip->bi_mutex));
5587
5588 if ((ip->bi_flags & DSW_BMPOFFLINE) != 0)
5589 return (NULL);
5590
5591 *tmp = NULL;
5592 read_fba = 0;
5593
5594 II_READ_START(ip, bitmap);
5595 rc = nsc_alloc_buf(ip->bi_bmpfd, read_fba,
5596 FBA_LEN(sizeof (ii_header_t)), NSC_RDWRBUF, tmp);
5597 II_READ_END(ip, bitmap, rc, FBA_LEN(sizeof (ii_header_t)));
5598 if (!II_SUCCESS(rc)) {
5599 if (ii_debug > 2)
5600 cmn_err(CE_WARN, "!ii: nsc_alloc_buf returned 0x%x",
5601 rc);
5602 if (*tmp)
5603 (void) nsc_free_buf(*tmp);
5604 *tmp = NULL;
5605 mutex_exit(&ip->bi_mutex);
5606 _ii_error(ip, DSW_BMPOFFLINE);
5607 mutex_enter(&ip->bi_mutex);
5608 return (NULL);
5609 }
5610
5611 hdr = (ii_header_t *)(*tmp)->sb_vec[0].sv_addr;
5612
5613 return (hdr);
5614 }
5615
5616
5617 /*
5618 * _ii_bm_header_free
5619 * Free the bitmap volume header
5620 *
5621 */
5622
5623 /* ARGSUSED */
5624
5625 void
_ii_bm_header_free(ii_header_t * hdr,_ii_info_t * ip,nsc_buf_t * tmp)5626 _ii_bm_header_free(ii_header_t *hdr, _ii_info_t *ip, nsc_buf_t *tmp)
5627 {
5628 (void) nsc_free_buf(tmp);
5629
5630 }
5631
5632 /*
5633 * _ii_bm_header_put
5634 * Write out the modified bitmap volume header and free it
5635 *
5636 */
5637
5638 /* ARGSUSED */
5639
5640 int
_ii_bm_header_put(ii_header_t * hdr,_ii_info_t * ip,nsc_buf_t * tmp)5641 _ii_bm_header_put(ii_header_t *hdr, _ii_info_t *ip, nsc_buf_t *tmp)
5642 {
5643 nsc_off_t write_fba;
5644 int rc;
5645
5646 ASSERT(MUTEX_HELD(&ip->bi_mutex));
5647
5648 write_fba = 0;
5649
5650 II_NSC_WRITE(ip, bitmap, rc, tmp, write_fba,
5651 FBA_LEN(sizeof (ii_header_t)), 0);
5652
5653 (void) nsc_free_buf(tmp);
5654 if (!II_SUCCESS(rc)) {
5655 mutex_exit(&ip->bi_mutex);
5656 _ii_error(ip, DSW_BMPOFFLINE);
5657 mutex_enter(&ip->bi_mutex);
5658 DTRACE_PROBE(_ii_bm_header_put);
5659 return (rc);
5660 } else {
5661 DTRACE_PROBE(_ii_bm_header_put_end);
5662 return (0);
5663 }
5664 }
5665
5666 /*
5667 * _ii_flag_op
5668 * Clear or set a flag in bi_flags and dsw_state.
5669 * This relies on the ownership of the header block's nsc_buf
5670 * for locking.
5671 *
5672 */
5673
5674 void
_ii_flag_op(and,or,ip,update)5675 _ii_flag_op(and, or, ip, update)
5676 int and, or;
5677 _ii_info_t *ip;
5678 int update;
5679 {
5680 ii_header_t *bm_header;
5681 nsc_buf_t *tmp;
5682
5683 ip->bi_flags &= and;
5684 ip->bi_flags |= or;
5685
5686 if (update == TRUE) {
5687
5688 /*
5689 * No point trying to access bitmap header if it's offline
5690 * or has been disassociated from set via DSW_HANGING
5691 */
5692 if ((ip->bi_flags & (DSW_BMPOFFLINE|DSW_HANGING)) == 0) {
5693 bm_header = _ii_bm_header_get(ip, &tmp);
5694 if (bm_header == NULL) {
5695 if (tmp)
5696 (void) nsc_free_buf(tmp);
5697 DTRACE_PROBE(_ii_flag_op_end);
5698 return;
5699 }
5700 bm_header->ii_state &= and;
5701 bm_header->ii_state |= or;
5702 /* copy over the mtime */
5703 bm_header->ii_mtime = ip->bi_mtime;
5704 (void) _ii_bm_header_put(bm_header, ip, tmp);
5705 }
5706 }
5707
5708 }
5709
5710 /*
5711 * _ii_nsc_io
5712 * Perform read or write on an underlying nsc device
5713 * fd - nsc file descriptor
5714 * flag - nsc io direction and characteristics flag
5715 * fba_pos - offset from beginning of device in FBAs
5716 * io_addr - pointer to data buffer
5717 * io_len - length of io in bytes
5718 */
5719
5720 int
_ii_nsc_io(_ii_info_t * ip,int ks,nsc_fd_t * fd,int flag,nsc_off_t fba_pos,unsigned char * io_addr,nsc_size_t io_len)5721 _ii_nsc_io(_ii_info_t *ip, int ks, nsc_fd_t *fd, int flag, nsc_off_t fba_pos,
5722 unsigned char *io_addr, nsc_size_t io_len)
5723 {
5724 nsc_buf_t *tmp = NULL;
5725 nsc_vec_t *vecp;
5726 uchar_t *vaddr;
5727 size_t copy_len;
5728 int64_t vlen;
5729 int rc;
5730 nsc_size_t fba_req, fba_len;
5731 nsc_size_t maxfbas = 0;
5732 nsc_size_t tocopy;
5733 unsigned char *toaddr;
5734
5735 rc = nsc_maxfbas(fd, 0, &maxfbas);
5736 if (!II_SUCCESS(rc)) {
5737 #ifdef DEBUG
5738 cmn_err(CE_WARN, "!_ii_nsc_io: maxfbas failed (%d)", rc);
5739 #endif
5740 maxfbas = DSW_CBLK_FBA;
5741 }
5742
5743 toaddr = io_addr;
5744 fba_req = FBA_LEN(io_len);
5745
5746 #ifdef DEBUG_SPLIT_IO
5747 cmn_err(CE_NOTE, "!_ii_nsc_io: maxfbas = %08x", maxfbas);
5748 cmn_err(CE_NOTE, "!_ii_nsc_io: toaddr=%08x, io_len=%08x, fba_req=%08x",
5749 toaddr, io_len, fba_req);
5750 #endif
5751
5752 loop:
5753 tmp = NULL;
5754 fba_len = min(fba_req, maxfbas);
5755 tocopy = min(io_len, FBA_SIZE(fba_len));
5756
5757 DTRACE_PROBE2(_ii_nsc_io_buffer, nsc_off_t, fba_pos,
5758 nsc_size_t, fba_len);
5759
5760 #ifdef DEBUG_SPLIT_IO
5761 cmn_err(CE_NOTE, "!_ii_nsc_io: fba_pos=%08x, fba_len=%08x",
5762 fba_pos, fba_len);
5763 #endif
5764
5765 #ifndef DISABLE_KSTATS
5766 if (flag & NSC_READ) {
5767 switch (ks) {
5768 case KS_MST:
5769 II_READ_START(ip, master);
5770 break;
5771 case KS_SHD:
5772 II_READ_START(ip, shadow);
5773 break;
5774 case KS_BMP:
5775 II_READ_START(ip, bitmap);
5776 break;
5777 case KS_OVR:
5778 II_READ_START(ip, overflow);
5779 break;
5780 default:
5781 cmn_err(CE_WARN, "!Invalid kstats type %d", ks);
5782 break;
5783 }
5784 }
5785 #endif
5786
5787 rc = nsc_alloc_buf(fd, fba_pos, fba_len, flag, &tmp);
5788
5789 #ifndef DISABLE_KSTATS
5790 if (flag & NSC_READ) {
5791 switch (ks) {
5792 case KS_MST:
5793 II_READ_END(ip, master, rc, fba_len);
5794 break;
5795 case KS_SHD:
5796 II_READ_END(ip, shadow, rc, fba_len);
5797 break;
5798 case KS_BMP:
5799 II_READ_END(ip, bitmap, rc, fba_len);
5800 break;
5801 case KS_OVR:
5802 II_READ_END(ip, overflow, rc, fba_len);
5803 break;
5804 }
5805 }
5806 #endif
5807
5808 if (!II_SUCCESS(rc)) {
5809 if (tmp) {
5810 (void) nsc_free_buf(tmp);
5811 }
5812
5813 return (EIO);
5814 }
5815
5816 if ((flag & (NSC_WRITE|NSC_READ)) == NSC_WRITE &&
5817 (FBA_OFF(io_len) != 0)) {
5818 /*
5819 * Not overwriting all of the last FBA, so read in the
5820 * old contents now before we overwrite it with the new
5821 * data.
5822 */
5823 #ifdef DEBUG_SPLIT_IO
5824 cmn_err(CE_NOTE, "!_ii_nsc_io: Read-B4-Write %08x",
5825 fba_pos+FBA_NUM(io_len));
5826 #endif
5827
5828 #ifdef DISABLE_KSTATS
5829 rc = nsc_read(tmp, fba_pos+FBA_NUM(io_len), 1, 0);
5830 #else
5831 switch (ks) {
5832 case KS_MST:
5833 II_NSC_READ(ip, master, rc, tmp,
5834 fba_pos+FBA_NUM(io_len), 1, 0);
5835 break;
5836 case KS_SHD:
5837 II_NSC_READ(ip, shadow, rc, tmp,
5838 fba_pos+FBA_NUM(io_len), 1, 0);
5839 break;
5840 case KS_BMP:
5841 II_NSC_READ(ip, bitmap, rc, tmp,
5842 fba_pos+FBA_NUM(io_len), 1, 0);
5843 break;
5844 case KS_OVR:
5845 II_NSC_READ(ip, overflow, rc, tmp,
5846 fba_pos+FBA_NUM(io_len), 1, 0);
5847 break;
5848 case KS_NA:
5849 rc = nsc_read(tmp, fba_pos+FBA_NUM(io_len), 1, 0);
5850 break;
5851 default:
5852 cmn_err(CE_WARN, "!Invalid kstats type %d", ks);
5853 rc = nsc_read(tmp, fba_pos+FBA_NUM(io_len), 1, 0);
5854 break;
5855 }
5856 #endif
5857 if (!II_SUCCESS(rc)) {
5858 (void) nsc_free_buf(tmp);
5859 return (EIO);
5860 }
5861 }
5862
5863 vecp = tmp->sb_vec;
5864 vlen = vecp->sv_len;
5865 vaddr = vecp->sv_addr;
5866
5867 while (tocopy > 0) {
5868 if (vecp->sv_addr == 0 || vecp->sv_len == 0) {
5869 #ifdef DEBUG
5870 cmn_err(CE_WARN, "!_ii_nsc_io: ran off end of handle");
5871 #endif
5872 break;
5873 }
5874
5875 copy_len = (size_t)min(vlen, tocopy);
5876
5877 DTRACE_PROBE1(_ii_nsc_io_bcopy, size_t, copy_len);
5878
5879 if (flag & NSC_WRITE)
5880 bcopy(io_addr, vaddr, copy_len);
5881 else
5882 bcopy(vaddr, io_addr, copy_len);
5883
5884 toaddr += copy_len;
5885 tocopy -= copy_len;
5886 io_addr += copy_len;
5887 io_len -= copy_len;
5888 vaddr += copy_len;
5889 vlen -= copy_len;
5890
5891 if (vlen <= 0) {
5892 vecp++;
5893 vaddr = vecp->sv_addr;
5894 vlen = vecp->sv_len;
5895 }
5896 }
5897
5898 if (flag & NSC_WRITE) {
5899 #ifdef DISABLE_KSTATS
5900 rc = nsc_write(tmp, tmp->sb_pos, tmp->sb_len, 0);
5901 #else
5902 switch (ks) {
5903 case KS_MST:
5904 II_NSC_WRITE(ip, master, rc, tmp, tmp->sb_pos,
5905 tmp->sb_len, 0);
5906 break;
5907 case KS_SHD:
5908 II_NSC_WRITE(ip, shadow, rc, tmp, tmp->sb_pos,
5909 tmp->sb_len, 0);
5910 break;
5911 case KS_BMP:
5912 II_NSC_WRITE(ip, bitmap, rc, tmp, tmp->sb_pos,
5913 tmp->sb_len, 0);
5914 break;
5915 case KS_OVR:
5916 II_NSC_WRITE(ip, overflow, rc, tmp, tmp->sb_pos,
5917 tmp->sb_len, 0);
5918 break;
5919 case KS_NA:
5920 rc = nsc_write(tmp, tmp->sb_pos, tmp->sb_len, 0);
5921 break;
5922 default:
5923 cmn_err(CE_WARN, "!Invalid kstats type %d", ks);
5924 rc = nsc_write(tmp, tmp->sb_pos, tmp->sb_len, 0);
5925 break;
5926 }
5927 #endif
5928 if (!II_SUCCESS(rc)) {
5929 (void) nsc_free_buf(tmp);
5930 return (rc);
5931 }
5932 }
5933
5934 (void) nsc_free_buf(tmp);
5935
5936 fba_pos += fba_len;
5937 fba_req -= fba_len;
5938 if (fba_req > 0)
5939 goto loop;
5940
5941 return (0);
5942 }
5943
5944
5945 /*
5946 * ii_overflow_attach
5947 */
5948 static int
ii_overflow_attach(_ii_info_t * ip,char * name,int first)5949 ii_overflow_attach(_ii_info_t *ip, char *name, int first)
5950 {
5951 _ii_overflow_t *op;
5952 int rc = 0;
5953 int reserved = 0;
5954 int mutex_set = 0;
5955 int II_OLD_OMAGIC = 0x426c7565; /* "Blue" */
5956
5957 mutex_enter(&_ii_overflow_mutex);
5958 /* search for name in list */
5959 for (op = _ii_overflow_top; op; op = op->ii_next) {
5960 if (strncmp(op->ii_volname, name, DSW_NAMELEN) == 0)
5961 break;
5962 }
5963 if (op) {
5964 ip->bi_overflow = op;
5965 op->ii_crefcnt++;
5966 op->ii_drefcnt++;
5967 if ((op->ii_flags & IIO_CNTR_INVLD) && (op->ii_hversion >= 1)) {
5968 if (!first)
5969 mutex_enter(&ip->bi_mutex);
5970 ip->bi_flags |= DSW_OVRHDRDRTY;
5971 if (!first)
5972 mutex_exit(&ip->bi_mutex);
5973 op->ii_urefcnt++;
5974 }
5975 #ifndef DISABLE_KSTATS
5976 ip->bi_kstat_io.overflow = op->ii_overflow;
5977 (void) strlcpy(ip->bi_kstat_io.ovrio, op->ii_ioname,
5978 KSTAT_DATA_CHAR_LEN);
5979 #endif
5980 /* write header */
5981 if (!(rc = nsc_reserve(op->ii_dev->bi_fd, NSC_MULTI))) {
5982 rc = _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd,
5983 NSC_WRBUF, II_OHEADER_FBA,
5984 (unsigned char *)&op->ii_do, sizeof (op->ii_do));
5985 (void) nsc_release(op->ii_dev->bi_fd);
5986 ++iigkstat.assoc_over.value.ul;
5987 }
5988 mutex_exit(&_ii_overflow_mutex);
5989 return (rc);
5990 }
5991 if ((op = kmem_zalloc(sizeof (*op), KM_SLEEP)) == NULL) {
5992 mutex_exit(&_ii_overflow_mutex);
5993 return (ENOMEM);
5994 }
5995 if ((op->ii_dev = kmem_zalloc(sizeof (_ii_info_dev_t), KM_SLEEP))
5996 == NULL) {
5997 kmem_free(op, sizeof (*op));
5998 mutex_exit(&_ii_overflow_mutex);
5999 return (ENOMEM);
6000 }
6001 #ifndef DISABLE_KSTATS
6002 if ((op->ii_overflow = _ii_overflow_kstat_create(ip, op))) {
6003 ip->bi_kstat_io.overflow = op->ii_overflow;
6004 (void) strlcpy(op->ii_ioname, ip->bi_kstat_io.ovrio,
6005 KSTAT_DATA_CHAR_LEN);
6006 } else {
6007 goto fail;
6008 }
6009 #endif
6010 /* open overflow volume */
6011 op->ii_dev->bi_fd = nsc_open(name, NSC_IIR_ID|NSC_FILE|NSC_RDWR, NULL,
6012 (blind_t)&(op->ii_dev->bi_iodev), &rc);
6013 if (!op->ii_dev->bi_fd)
6014 op->ii_dev->bi_fd = nsc_open(name,
6015 NSC_IIR_ID|NSC_DEVICE|NSC_RDWR, NULL,
6016 (blind_t)&(op->ii_dev->bi_iodev), &rc);
6017 if (op->ii_dev->bi_fd == NULL) {
6018 goto fail;
6019 }
6020 if ((rc = nsc_reserve(op->ii_dev->bi_fd, 0)) != 0)
6021 goto fail;
6022 reserved = 1;
6023 /* register path */
6024 op->ii_dev->bi_tok = _ii_register_path(name, NSC_DEVICE,
6025 _ii_ior);
6026 if (!op->ii_dev->bi_tok) {
6027 goto fail;
6028 }
6029 /* read header */
6030 rc = _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_RDBUF,
6031 II_OHEADER_FBA, (unsigned char *)&op->ii_do, sizeof (op->ii_do));
6032 if (!II_SUCCESS(rc)) {
6033 _ii_error(ip, DSW_OVROFFLINE);
6034 goto fail;
6035 }
6036 /* On resume, check for old hmagic */
6037 if (strncmp(op->ii_volname, name, DSW_NAMELEN) ||
6038 ((op->ii_hmagic != II_OLD_OMAGIC) &&
6039 (op->ii_hmagic != II_OMAGIC))) {
6040 rc = DSW_EOMAGIC;
6041 goto fail;
6042 }
6043 /* set up counts */
6044 op->ii_crefcnt = 1;
6045 op->ii_drefcnt = 0;
6046 op->ii_urefcnt = 0;
6047 op->ii_hmagic = II_OMAGIC;
6048 if (!first) {
6049 /* if header version > 0, check if header written */
6050 if (((op->ii_flags & IIO_HDR_WRTN) == 0) &&
6051 (op->ii_hversion >= 1)) {
6052 op->ii_flags |= IIO_CNTR_INVLD;
6053 mutex_enter(&ip->bi_mutex);
6054 ip->bi_flags |= DSW_OVRHDRDRTY;
6055 mutex_exit(&ip->bi_mutex);
6056 op->ii_urefcnt++;
6057 }
6058 }
6059 op->ii_flags &= ~IIO_HDR_WRTN;
6060 op->ii_drefcnt++;
6061 /* write header */
6062 rc = _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_WRBUF,
6063 II_OHEADER_FBA, (unsigned char *)&op->ii_do, sizeof (op->ii_do));
6064 nsc_release(op->ii_dev->bi_fd);
6065 reserved = 0;
6066 if (!II_SUCCESS(rc)) {
6067 _ii_error(ip, DSW_OVROFFLINE);
6068 goto fail;
6069 }
6070
6071 mutex_init(&op->ii_mutex, NULL, MUTEX_DRIVER, NULL);
6072 mutex_set++;
6073
6074 /* link onto list */
6075 op->ii_next = _ii_overflow_top;
6076 _ii_overflow_top = op;
6077 ip->bi_overflow = op;
6078
6079 ++iigkstat.assoc_over.value.ul;
6080 mutex_exit(&_ii_overflow_mutex);
6081
6082 DTRACE_PROBE(_ii_overflow_attach_end);
6083 return (0);
6084 fail:
6085 #ifndef DISABLE_KSTATS
6086 /* Clean-up kstat stuff */
6087 if (op->ii_overflow) {
6088 kstat_delete(op->ii_overflow);
6089 mutex_destroy(&op->ii_kstat_mutex);
6090 }
6091 #endif
6092 /* clean up mutex if we made it that far */
6093 if (mutex_set) {
6094 mutex_destroy(&op->ii_mutex);
6095 }
6096
6097 if (op->ii_dev) {
6098 if (op->ii_dev->bi_tok) {
6099 (void) _ii_unregister_path(op->ii_dev->bi_tok, 0,
6100 "overflow");
6101 }
6102 if (reserved)
6103 (void) nsc_release(op->ii_dev->bi_fd);
6104 if (op->ii_dev->bi_fd)
6105 (void) nsc_close(op->ii_dev->bi_fd);
6106 kmem_free(op->ii_dev, sizeof (_ii_info_dev_t));
6107 }
6108 kmem_free(op, sizeof (*op));
6109 mutex_exit(&_ii_overflow_mutex);
6110
6111 return (rc);
6112 }
6113
6114 /*
6115 * ii_overflow_free
6116 * Assumes that ip is locked for I/O
6117 */
6118 static void
ii_overflow_free(_ii_info_t * ip,int reclaim)6119 ii_overflow_free(_ii_info_t *ip, int reclaim)
6120 {
6121 _ii_overflow_t *op, **xp;
6122
6123 if ((op = ip->bi_overflow) == NULL)
6124 return;
6125 ip->bi_kstat_io.overflow = NULL;
6126 mutex_enter(&_ii_overflow_mutex);
6127 switch (reclaim) {
6128 case NO_RECLAIM:
6129 if (--(op->ii_drefcnt) == 0) {
6130 /* indicate header written */
6131 op->ii_flags |= IIO_HDR_WRTN;
6132 /* write out header */
6133 ASSERT(op->ii_dev->bi_fd);
6134 (void) nsc_reserve(op->ii_dev->bi_fd, NSC_MULTI);
6135 (void) _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd,
6136 NSC_WRBUF, II_OHEADER_FBA,
6137 (unsigned char *)&op->ii_do,
6138 sizeof (op->ii_do));
6139 nsc_release(op->ii_dev->bi_fd);
6140 }
6141 break;
6142 case RECLAIM:
6143 ii_reclaim_overflow(ip);
6144 /* FALLTHRU */
6145 case INIT_OVR:
6146 if (--(op->ii_drefcnt) == 0) {
6147 /* reset to new condition, c.f. _ii_ocreate() */
6148 op->ii_used = 1;
6149 op->ii_unused = op->ii_nchunks - op->ii_used;
6150 op->ii_freehead = II_NULLNODE;
6151 }
6152
6153 /* write out header */
6154 ASSERT(op->ii_dev->bi_fd);
6155 (void) nsc_reserve(op->ii_dev->bi_fd, NSC_MULTI);
6156 (void) _ii_nsc_io(ip, KS_OVR, op->ii_dev->bi_fd, NSC_WRBUF,
6157 II_OHEADER_FBA, (unsigned char *)&op->ii_do,
6158 sizeof (op->ii_do));
6159 nsc_release(op->ii_dev->bi_fd);
6160 }
6161
6162 if (--(op->ii_crefcnt) == 0) {
6163 /* Close fd and unlink from active chain; */
6164
6165 (void) _ii_unregister_path(op->ii_dev->bi_tok, 0, "overflow");
6166 (void) nsc_close(op->ii_dev->bi_fd);
6167
6168 for (xp = &_ii_overflow_top; *xp && *xp != op;
6169 xp = &((*xp)->ii_next))
6170 /* NULL statement */;
6171 *xp = op->ii_next;
6172
6173 if (op->ii_overflow) {
6174 kstat_delete(op->ii_overflow);
6175 }
6176
6177 /* Clean up ii_overflow_t mutexs */
6178 mutex_destroy(&op->ii_kstat_mutex);
6179 mutex_destroy(&op->ii_mutex);
6180
6181 if (op->ii_dev)
6182 kmem_free(op->ii_dev, sizeof (_ii_info_dev_t));
6183 kmem_free(op, sizeof (*op));
6184 }
6185 ip->bi_overflow = NULL;
6186 --iigkstat.assoc_over.value.ul;
6187 mutex_exit(&_ii_overflow_mutex);
6188
6189 }
6190
6191 /*
6192 * ii_sibling_free
6193 * Free resources and unlink the sibling chains etc.
6194 */
6195
6196 static void
ii_sibling_free(_ii_info_t * ip)6197 ii_sibling_free(_ii_info_t *ip)
6198 {
6199 _ii_info_t *hip, *yip;
6200
6201 if (!ip)
6202 return;
6203
6204 if (ip->bi_shdr_tok)
6205 (void) _ii_unregister_path(ip->bi_shdr_tok, 0, "raw shadow");
6206
6207 if (ip->bi_shd_tok)
6208 (void) _ii_unregister_path(ip->bi_shd_tok, 0, "shadow");
6209
6210 rw_enter(&ip->bi_linkrw, RW_WRITER);
6211
6212 ip->bi_shd_tok = NULL;
6213 ip->bi_shdr_tok = NULL;
6214
6215 if (NSHADOWS(ip)) {
6216 mutex_enter(&_ii_info_mutex);
6217 if (ip->bi_head == ip) { /* removing head of list */
6218 hip = ip->bi_sibling;
6219 for (yip = hip; yip; yip = yip->bi_sibling)
6220 yip->bi_head = hip;
6221
6222 } else { /* removing member of list */
6223 hip = ip->bi_head;
6224 for (yip = ip->bi_head; yip; yip = yip->bi_sibling) {
6225 if (yip->bi_sibling == ip) {
6226 yip->bi_sibling = ip->bi_sibling;
6227 break;
6228 }
6229 }
6230 }
6231 hip->bi_master->bi_head = hip;
6232 if (ip->bi_master == ip) { /* master I/O goes through this */
6233 mutex_exit(&_ii_info_mutex);
6234 _ii_info_freeshd(ip);
6235 rw_exit(&ip->bi_linkrw);
6236 return;
6237 }
6238 mutex_exit(&_ii_info_mutex);
6239 } else {
6240 if (ip->bi_master != ip) /* last ref to master side ip */
6241 _ii_info_free(ip->bi_master); /* ==A== */
6242 }
6243
6244 if (ip->bi_master != ip) { /* info_free ==A== will close these */
6245 /*
6246 * Null out any pointers to shared master side resources
6247 * that should only be freed once when the last reference
6248 * to this master is freed and calls _ii_info_free().
6249 */
6250 ip->bi_mstdev = NULL;
6251 ip->bi_mstrdev = NULL;
6252 ip->bi_kstat_io.master = NULL;
6253 }
6254 rw_exit(&ip->bi_linkrw);
6255 _ii_info_free(ip);
6256
6257 }
6258
6259 /*
6260 * _ii_info_freeshd
6261 * Free shadow side resources
6262 *
6263 * Calling/Exit State:
6264 * No mutexes should be held on entry to this function.
6265 *
6266 * Description:
6267 * Frees the system resources associated with the shadow
6268 * access, leaving the master side alone. This allows the
6269 * original master side to continue in use while there are
6270 * outstanding references to this _ii_info_t.
6271 */
6272
6273 static void
_ii_info_freeshd(_ii_info_t * ip)6274 _ii_info_freeshd(_ii_info_t *ip)
6275 {
6276 if (!ip)
6277 return;
6278 if ((ip->bi_flags&DSW_HANGING) == DSW_HANGING)
6279 return; /* this work has already been completed */
6280
6281 II_FLAG_SETX(DSW_HANGING, ip);
6282
6283 if (ip->bi_cluster)
6284 (void) II_UNLINK_CLUSTER(ip);
6285 if (ip->bi_group)
6286 (void) II_UNLINK_GROUP(ip);
6287
6288 if (ip->bi_shdfd && ip->bi_shdrsrv)
6289 nsc_release(ip->bi_shdfd);
6290 if (ip->bi_shdrfd && ip->bi_shdrrsrv)
6291 nsc_release(ip->bi_shdrfd);
6292 if (ip->bi_bmpfd && ip->bi_bmprsrv)
6293 nsc_release(ip->bi_bmpfd);
6294
6295 if (ip->bi_bmp_tok)
6296 (void) _ii_unregister_path(ip->bi_bmp_tok, 0, "bitmap");
6297
6298 if (ip->bi_shdr_tok)
6299 (void) _ii_unregister_path(ip->bi_shdr_tok, 0, "raw shadow");
6300
6301 if (ip->bi_shd_tok)
6302 (void) _ii_unregister_path(ip->bi_shd_tok, 0, "shadow");
6303 ip->bi_shd_tok = NULL;
6304 ip->bi_shdr_tok = NULL;
6305
6306 if (ip->bi_shdfd)
6307 (void) nsc_close(ip->bi_shdfd);
6308
6309 if (ip->bi_shdrfd)
6310 (void) nsc_close(ip->bi_shdrfd);
6311
6312 if (ip->bi_bmpfd)
6313 (void) nsc_close(ip->bi_bmpfd);
6314
6315 ip->bi_shdfd = NULL;
6316 ip->bi_shdrfd = NULL;
6317 ip->bi_bmpfd = NULL;
6318
6319 if (ip->bi_busy)
6320 kmem_free(ip->bi_busy,
6321 1 + (ip->bi_size / (DSW_SIZE * DSW_BITS)));
6322 ip->bi_busy = NULL;
6323
6324 if (ip->bi_kstat_io.shadow) {
6325 kstat_delete(ip->bi_kstat_io.shadow);
6326 ip->bi_kstat_io.shadow = NULL;
6327 }
6328 if (ip->bi_kstat_io.bitmap) {
6329 kstat_delete(ip->bi_kstat_io.bitmap);
6330 ip->bi_kstat_io.bitmap = NULL;
6331 }
6332 if (ip->bi_kstat) {
6333 kstat_delete(ip->bi_kstat);
6334 ip->bi_kstat = NULL;
6335 }
6336
6337 }
6338
6339 /*
6340 * _ii_info_free
6341 * Free resources
6342 *
6343 * Calling/Exit State:
6344 * No mutexes should be held on entry to this function.
6345 *
6346 * Description:
6347 * Frees the system resources associated with the specified
6348 * II information structure.
6349 */
6350
6351 static void
_ii_info_free(_ii_info_t * ip)6352 _ii_info_free(_ii_info_t *ip)
6353 {
6354 _ii_info_t **xip;
6355
6356 if (!ip)
6357 return;
6358
6359 mutex_enter(&_ii_info_mutex);
6360 for (xip = &_ii_mst_top; *xip; xip = &((*xip)->bi_nextmst)) {
6361 if (ip == *xip) {
6362 *xip = ip->bi_nextmst;
6363 break;
6364 }
6365 }
6366 mutex_exit(&_ii_info_mutex);
6367
6368 /* this rw_enter forces us to wait until all nsc_buffers are freed */
6369 rw_enter(&ip->bi_linkrw, RW_WRITER);
6370 if (ip->bi_mstdev && ip->bi_mstfd && ip->bi_mstrsrv)
6371 nsc_release(ip->bi_mstfd);
6372 if (ip->bi_mstrdev && ip->bi_mstrfd && ip->bi_mstrrsrv)
6373 nsc_release(ip->bi_mstrfd);
6374
6375 if (ip->bi_mstdev && ip->bi_mst_tok)
6376 (void) _ii_unregister_path(ip->bi_mst_tok, 0, "master");
6377 if (ip->bi_mstrdev && ip->bi_mstr_tok)
6378 (void) _ii_unregister_path(ip->bi_mstr_tok, 0, "raw master");
6379
6380 if (ip->bi_mstdev && ip->bi_mstfd)
6381 (void) nsc_close(ip->bi_mstfd);
6382 if (ip->bi_mstrdev && ip->bi_mstrfd)
6383 (void) nsc_close(ip->bi_mstrfd);
6384 rw_exit(&ip->bi_linkrw);
6385
6386 if (ip->bi_mstdev) {
6387 nsc_kmem_free(ip->bi_mstdev, sizeof (*ip->bi_mstdev));
6388 }
6389 if (ip->bi_mstrdev) {
6390 nsc_kmem_free(ip->bi_mstrdev, sizeof (*ip->bi_mstrdev));
6391 }
6392
6393 if (ip->bi_kstat_io.master) {
6394 kstat_delete(ip->bi_kstat_io.master);
6395 }
6396 if (ip->bi_kstat_io.shadow) {
6397 kstat_delete(ip->bi_kstat_io.shadow);
6398 ip->bi_kstat_io.shadow = 0;
6399 }
6400 if (ip->bi_kstat_io.bitmap) {
6401 kstat_delete(ip->bi_kstat_io.bitmap);
6402 ip->bi_kstat_io.bitmap = 0;
6403 }
6404 if (ip->bi_kstat) {
6405 kstat_delete(ip->bi_kstat);
6406 ip->bi_kstat = NULL;
6407 }
6408
6409 /* this rw_enter forces us to wait until all nsc_buffers are freed */
6410 rw_enter(&ip->bi_linkrw, RW_WRITER);
6411 rw_exit(&ip->bi_linkrw);
6412
6413 mutex_destroy(&ip->bi_mutex);
6414 mutex_destroy(&ip->bi_rsrvmutex);
6415 mutex_destroy(&ip->bi_rlsemutex);
6416 mutex_destroy(&ip->bi_bmpmutex);
6417 mutex_destroy(&ip->bi_chksmutex);
6418 cv_destroy(&ip->bi_copydonecv);
6419 cv_destroy(&ip->bi_reservecv);
6420 cv_destroy(&ip->bi_releasecv);
6421 cv_destroy(&ip->bi_ioctlcv);
6422 cv_destroy(&ip->bi_closingcv);
6423 cv_destroy(&ip->bi_busycv);
6424 rw_destroy(&ip->bi_busyrw);
6425 rw_destroy(&ip->bi_linkrw);
6426
6427 _ii_info_freeshd(ip);
6428
6429 #ifdef DEBUG
6430 ip->bi_head = (_ii_info_t *)0xdeadbeef;
6431 #endif
6432
6433 nsc_kmem_free(ip, sizeof (*ip));
6434
6435 }
6436
6437 /*
6438 * _ii_copy_chunks
6439 * Perform a copy of some chunks
6440 *
6441 * Calling/Exit State:
6442 * Returns 0 if the data was copied successfully, otherwise
6443 * error code.
6444 *
6445 * Description:
6446 * flag is set to CV_SHD2MST if the data is to be copied from the shadow
6447 * to the master, 0 if it is to be copied from the master to the shadow.
6448 */
6449
6450 static int
_ii_copy_chunks(_ii_info_t * ip,int flag,chunkid_t chunk_num,int nchunks)6451 _ii_copy_chunks(_ii_info_t *ip, int flag, chunkid_t chunk_num, int nchunks)
6452 {
6453 int mst_flag;
6454 int shd_flag;
6455 int ovr_flag;
6456 nsc_off_t pos;
6457 nsc_size_t len;
6458 int rc;
6459 nsc_off_t shd_pos;
6460 chunkid_t shd_chunk;
6461 nsc_buf_t *mst_tmp = NULL;
6462 nsc_buf_t *shd_tmp = NULL;
6463
6464 if (ip->bi_flags & DSW_MSTOFFLINE) {
6465 DTRACE_PROBE(_ii_copy_chunks_end);
6466 return (EIO);
6467 }
6468
6469 if (ip->bi_flags & (DSW_SHDOFFLINE|DSW_SHDEXPORT|DSW_SHDIMPORT)) {
6470 DTRACE_PROBE(_ii_copy_chunks_end);
6471 return (EIO);
6472 }
6473
6474 if (flag == CV_SHD2MST) {
6475 mst_flag = NSC_WRBUF|NSC_WRTHRU;
6476 shd_flag = NSC_RDBUF;
6477 } else {
6478 shd_flag = NSC_WRBUF|NSC_WRTHRU;
6479 mst_flag = NSC_RDBUF;
6480 }
6481
6482 pos = DSW_CHK2FBA(chunk_num);
6483 len = DSW_SIZE * nchunks;
6484 if (pos + len > ip->bi_size)
6485 len = ip->bi_size - pos;
6486 if (ip->bi_flags & DSW_TREEMAP) {
6487 ASSERT(nchunks == 1);
6488 shd_chunk = ii_tsearch(ip, chunk_num);
6489 if (shd_chunk == II_NULLNODE) {
6490 /* shadow is full */
6491 mutex_enter(&ip->bi_mutex);
6492 II_FLAG_SET(DSW_OVERFLOW, ip);
6493 mutex_exit(&ip->bi_mutex);
6494 DTRACE_PROBE(_ii_copy_chunks_end);
6495 return (EIO);
6496 }
6497
6498 ovr_flag = II_ISOVERFLOW(shd_chunk);
6499 shd_pos = DSW_CHK2FBA((ovr_flag) ?
6500 II_2OVERFLOW(shd_chunk) : shd_chunk);
6501 } else {
6502 ovr_flag = FALSE;
6503 shd_chunk = chunk_num;
6504 shd_pos = pos;
6505 }
6506
6507 /*
6508 * Always allocate the master side before the shadow to
6509 * avoid deadlocks on the same chunk.
6510 */
6511
6512 DTRACE_PROBE2(_ii_copy_chunks_alloc, nsc_off_t, pos, nsc_size_t, len);
6513
6514 II_ALLOC_BUF(ip, master, rc, MSTFD(ip), pos, len, mst_flag, &mst_tmp);
6515 if (!II_SUCCESS(rc)) {
6516 if (mst_tmp)
6517 (void) nsc_free_buf(mst_tmp);
6518 _ii_error(ip, DSW_MSTOFFLINE);
6519 DTRACE_PROBE(_ii_copy_chunks_end);
6520 return (rc);
6521 }
6522
6523 if (ovr_flag) {
6524 /* use overflow volume */
6525 (void) nsc_reserve(OVRFD(ip), NSC_MULTI);
6526 II_ALLOC_BUF(ip, overflow, rc, OVRFD(ip), shd_pos, len,
6527 shd_flag, &shd_tmp);
6528 } else {
6529 II_ALLOC_BUF(ip, shadow, rc, SHDFD(ip), shd_pos, len, shd_flag,
6530 &shd_tmp);
6531 }
6532 if (!II_SUCCESS(rc)) {
6533 (void) nsc_free_buf(mst_tmp);
6534 if (shd_tmp)
6535 (void) nsc_free_buf(shd_tmp);
6536 if (ovr_flag)
6537 nsc_release(OVRFD(ip));
6538 _ii_error(ip, DSW_SHDOFFLINE);
6539 if (ovr_flag)
6540 _ii_error(ip, DSW_OVROFFLINE);
6541 DTRACE_PROBE(_ii_copy_chunks_end);
6542 return (rc);
6543 }
6544
6545 /*
6546 * The direction of copy is determined by the mst_flag.
6547 */
6548 DTRACE_PROBE2(_ii_copy_chunks_copy, kstat_named_t, ii_copy_direct,
6549 int, mst_flag);
6550
6551 if (ii_copy_direct) {
6552 if (mst_flag & NSC_WRBUF) {
6553 if (ovr_flag) {
6554 II_NSC_COPY_DIRECT(ip, overflow, master, rc,
6555 shd_tmp, mst_tmp, shd_pos, pos, len)
6556 } else {
6557 II_NSC_COPY_DIRECT(ip, shadow, master, rc,
6558 shd_tmp, mst_tmp, shd_pos, pos, len)
6559 }
6560 if (!II_SUCCESS(rc)) {
6561 /* A copy has failed - something is wrong */
6562 _ii_error(ip, DSW_MSTOFFLINE);
6563 _ii_error(ip, DSW_SHDOFFLINE);
6564 if (ovr_flag)
6565 _ii_error(ip, DSW_OVROFFLINE);
6566 }
6567 } else {
6568 if (ovr_flag) {
6569 II_NSC_COPY_DIRECT(ip, master, overflow, rc,
6570 mst_tmp, shd_tmp, pos, shd_pos, len);
6571 } else {
6572 II_NSC_COPY_DIRECT(ip, master, shadow, rc,
6573 mst_tmp, shd_tmp, pos, shd_pos, len);
6574 }
6575 if (!II_SUCCESS(rc)) {
6576 /*
6577 * A failure has occurred during the above copy.
6578 * The macro calls nsc_copy_direct, which will
6579 * never return a read failure, only a write
6580 * failure. With this assumption, we should
6581 * take only the target volume offline.
6582 */
6583 _ii_error(ip, DSW_SHDOFFLINE);
6584 if (ovr_flag)
6585 _ii_error(ip, DSW_OVROFFLINE);
6586 }
6587 }
6588 } else {
6589 if (mst_flag & NSC_WRBUF) {
6590 rc = nsc_copy(shd_tmp, mst_tmp, shd_pos, pos, len);
6591 if (II_SUCCESS(rc)) {
6592 II_NSC_WRITE(ip, master, rc, mst_tmp, pos, len,
6593 0);
6594 if (!II_SUCCESS(rc))
6595 _ii_error(ip, DSW_MSTOFFLINE);
6596 } else {
6597 /* A copy has failed - something is wrong */
6598 _ii_error(ip, DSW_MSTOFFLINE);
6599 _ii_error(ip, DSW_SHDOFFLINE);
6600 }
6601 } else {
6602 rc = nsc_copy(mst_tmp, shd_tmp, pos, shd_pos, len);
6603 if (II_SUCCESS(rc)) {
6604 if (ovr_flag) {
6605 II_NSC_WRITE(ip, overflow, rc, shd_tmp,
6606 shd_pos, len, 0);
6607 } else {
6608 II_NSC_WRITE(ip, shadow, rc, shd_tmp,
6609 shd_pos, len, 0);
6610 }
6611 if (!II_SUCCESS(rc)) {
6612 _ii_error(ip, DSW_SHDOFFLINE);
6613 if (ovr_flag)
6614 _ii_error(ip, DSW_OVROFFLINE);
6615 }
6616 } else {
6617 /* A copy has failed - something is wrong */
6618 _ii_error(ip, DSW_MSTOFFLINE);
6619 _ii_error(ip, DSW_SHDOFFLINE);
6620 }
6621 }
6622 }
6623
6624 (void) nsc_free_buf(mst_tmp);
6625 (void) nsc_free_buf(shd_tmp);
6626 if (ovr_flag)
6627 nsc_release(OVRFD(ip));
6628
6629 DTRACE_PROBE(_ii_copy_chunks);
6630
6631 if (II_SUCCESS(rc)) {
6632 (void) II_CLR_COPY_BITS(ip, chunk_num, nchunks);
6633 rc = 0;
6634 }
6635
6636 return (rc);
6637 }
6638
6639
6640 /*
6641 * _ii_copy_on_write
6642 *
6643 * Calling/Exit State:
6644 * Returns 0 on success, otherwise error code.
6645 *
6646 * Description:
6647 * Determines if a copy on write is necessary, and performs it.
6648 * A copy on write is necessary in the following cases:
6649 * - No copy is in progress and the shadow bit is clear, which
6650 * means this is the first write to this track.
6651 * - A copy is in progress and the copy bit is set, which means
6652 * that a track copy is required.
6653 * If a copy to the master is to be done, make a recursive call to this
6654 * function to do any necessary copy on write on other InstantImage groups
6655 * that share the same master volume.
6656 */
6657
6658 static int
_ii_copy_on_write(_ii_info_t * ip,int flag,chunkid_t chunk_num,int nchunks)6659 _ii_copy_on_write(_ii_info_t *ip, int flag, chunkid_t chunk_num, int nchunks)
6660 {
6661 int rc = 0;
6662 int rtype;
6663 int hanging = (ip->bi_flags&DSW_HANGING);
6664
6665 if (hanging ||
6666 (flag & (CV_SIBLING|CV_SHD2MST)) == CV_SHD2MST && NSHADOWS(ip)) {
6667 _ii_info_t *xip;
6668 /*
6669 * Preserve copy of master for all other shadows of this master
6670 * before writing our data onto the master.
6671 */
6672
6673 /*
6674 * Avoid deadlock with COW on same chunk of sibling shadow
6675 * by unlocking this chunk before copying all other sibling
6676 * chunks.
6677 */
6678
6679 /*
6680 * Only using a single chunk when copying to master avoids
6681 * complex code here.
6682 */
6683
6684 ASSERT(nchunks == 1);
6685 if (!hanging)
6686 _ii_unlock_chunk(ip, chunk_num);
6687 for (xip = ip->bi_head; xip; xip = xip->bi_sibling) {
6688 if (xip == ip) /* don't copy ourselves again */
6689 continue;
6690
6691 DTRACE_PROBE(_ii_copy_on_write);
6692
6693 rw_enter(&xip->bi_linkrw, RW_READER);
6694 mutex_enter(&xip->bi_mutex);
6695 if (xip->bi_disabled) {
6696 mutex_exit(&xip->bi_mutex);
6697 rw_exit(&xip->bi_linkrw);
6698 continue; /* this set is stopping */
6699 }
6700 xip->bi_shdref++;
6701 mutex_exit(&xip->bi_mutex);
6702 /* don't waste time asking for MST as ip shares it */
6703 rtype = SHDR|BMP;
6704 (void) _ii_rsrv_devs(xip, rtype, II_INTERNAL);
6705 _ii_lock_chunk(xip, chunk_num);
6706 rc = _ii_copy_on_write(xip, flag | CV_SIBLING,
6707 chunk_num, 1);
6708
6709 /*
6710 * See comments in _ii_shadow_write()
6711 */
6712 if (rc == 0 ||
6713 (rc == EIO && (xip->bi_flags&DSW_OVERFLOW) != 0))
6714 (void) II_SET_SHD_BIT(xip, chunk_num);
6715
6716 _ii_unlock_chunk(xip, chunk_num);
6717 _ii_rlse_devs(xip, rtype);
6718 mutex_enter(&xip->bi_mutex);
6719 xip->bi_shdref--;
6720 if (xip->bi_state & DSW_CLOSING) {
6721 if (total_ref(xip) == 0) {
6722 cv_signal(&xip->bi_closingcv);
6723 }
6724 }
6725 mutex_exit(&xip->bi_mutex);
6726 rw_exit(&xip->bi_linkrw);
6727 }
6728 if (hanging) {
6729 DTRACE_PROBE(_ii_copy_on_write_end);
6730 return (0);
6731 }
6732 /*
6733 * Reacquire chunk lock and check that a COW by a sibling
6734 * has not already copied this chunk.
6735 */
6736 _ii_lock_chunk(ip, chunk_num);
6737 rc = II_TST_SHD_BIT(ip, chunk_num);
6738 if (rc < 0) {
6739 DTRACE_PROBE(_ii_copy_on_write_end);
6740 return (EIO);
6741 }
6742 if (rc != 0) {
6743 DTRACE_PROBE(_ii_copy_on_write_end);
6744 return (0);
6745 }
6746 }
6747
6748 if ((ip->bi_flags & DSW_COPYING) == 0) {
6749 /* Not copying at all */
6750
6751 if ((ip->bi_flags & DSW_GOLDEN) == DSW_GOLDEN) {
6752 /* No copy-on-write as it is independent */
6753 DTRACE_PROBE(_ii_copy_on_write_end);
6754 return (0);
6755 }
6756
6757 /* Dependent, so depends on shadow bit */
6758
6759 if ((flag == CV_SHD2MST) &&
6760 ((ip->bi_flags & DSW_SHDOFFLINE) != 0)) {
6761 /*
6762 * Writing master but shadow is offline, so
6763 * no need to copy on write or set shadow bit
6764 */
6765 DTRACE_PROBE(_ii_copy_on_write_end);
6766 return (0);
6767 }
6768 if (ip->bi_flags & DSW_BMPOFFLINE) {
6769 DTRACE_PROBE(_ii_copy_on_write_end);
6770 return (EIO);
6771 }
6772 rc = II_TST_SHD_BIT(ip, chunk_num);
6773 if (rc < 0) {
6774 DTRACE_PROBE(_ii_copy_on_write_end);
6775 return (EIO);
6776 }
6777 if (rc == 0) {
6778 /* Shadow bit clear, copy master to shadow */
6779 rc = _ii_copy_chunks(ip, 0, chunk_num, nchunks);
6780 }
6781 } else {
6782 /* Copying one way or the other */
6783 if (ip->bi_flags & DSW_BMPOFFLINE) {
6784 DTRACE_PROBE(_ii_copy_on_write_end);
6785 return (EIO);
6786 }
6787 rc = II_TST_COPY_BIT(ip, chunk_num);
6788 if (rc < 0) {
6789 DTRACE_PROBE(_ii_copy_on_write_end);
6790 return (EIO);
6791 }
6792 if (rc) {
6793 /* Copy bit set, do a copy */
6794 if ((ip->bi_flags & DSW_COPYINGS) == 0) {
6795 /* Copy master to shadow */
6796 rc = _ii_copy_chunks(ip, 0, chunk_num, nchunks);
6797 } else {
6798 /* Copy shadow to master */
6799 rc = _ii_copy_chunks(ip, CV_SHD2MST, chunk_num,
6800 nchunks);
6801 }
6802 }
6803 }
6804 return (rc);
6805 }
6806
6807 #ifdef DEBUG
6808 int ii_maxchunks = 0;
6809 #endif
6810
6811 /*
6812 * _ii_copyvolp()
6813 * Copy volume process.
6814 *
6815 * Calling/Exit State:
6816 * Passes 0 back to caller when the copy is complete or has been aborted,
6817 * otherwise error code.
6818 *
6819 * Description:
6820 * According to the flag, copy the master to the shadow volume or the
6821 * shadow to the master volume. Upon return wakeup all processes waiting
6822 * for this copy.
6823 *
6824 */
6825
6826 static void
_ii_copyvolp(struct copy_args * ca)6827 _ii_copyvolp(struct copy_args *ca)
6828 {
6829 chunkid_t chunk_num;
6830 int rc = 0;
6831 chunkid_t max_chunk;
6832 nsc_size_t nc_max;
6833 int nc_try, nc_got;
6834 nsc_size_t mst_max, shd_max;
6835 _ii_info_t *ip;
6836 int flag;
6837 nsc_size_t bitmap_size;
6838 nsc_size_t shadow_set, copy_set;
6839 int chunkcount = 0;
6840 int rsrv = 1;
6841 spcs_s_info_t kstatus;
6842
6843 ip = ca->ip;
6844 flag = ca->flag;
6845 kstatus = ca->kstatus;
6846
6847 if (ip->bi_disabled) {
6848 rc = DSW_EABORTED;
6849 goto skip;
6850 }
6851 max_chunk = ip->bi_size / DSW_SIZE;
6852 if ((ip->bi_size % DSW_SIZE) != 0)
6853 ++max_chunk;
6854 if ((ip->bi_flags&DSW_TREEMAP))
6855 nc_max = 1;
6856 else {
6857 mst_max = shd_max = 0;
6858 (void) nsc_maxfbas(MSTFD(ip), 0, &mst_max);
6859 (void) nsc_maxfbas(SHDFD(ip), 0, &shd_max);
6860 nc_max = (mst_max < shd_max) ? mst_max : shd_max;
6861 nc_max /= DSW_SIZE;
6862 ASSERT(nc_max > 0 && nc_max < 1000);
6863 }
6864 #ifdef DEBUG
6865 if (ii_maxchunks > 0)
6866 nc_max = ii_maxchunks;
6867 #endif
6868 for (chunk_num = nc_got = 0; /* CSTYLED */; /* CSTYLED */) {
6869 if ((flag & CV_SHD2MST) && NSHADOWS(ip))
6870 nc_try = 1;
6871 else
6872 nc_try = (int)nc_max;
6873 chunk_num = II_NEXT_COPY_BIT(ip, chunk_num + nc_got,
6874 max_chunk, nc_try, &nc_got);
6875
6876 if (chunk_num >= max_chunk) /* loop complete */
6877 break;
6878 if (ip->bi_flags & DSW_COPYINGX) {
6879 /* request to abort copy */
6880 _ii_unlock_chunks(ip, chunk_num, nc_got);
6881 rc = DSW_EABORTED;
6882 break;
6883 }
6884
6885 sema_p(&_ii_concopy_sema);
6886 rc = _ii_copy_on_write(ip, (flag & CV_SHD2MST), chunk_num,
6887 nc_got);
6888 sema_v(&_ii_concopy_sema);
6889 if (ip->bi_flags & DSW_TREEMAP)
6890 ii_tdelete(ip, chunk_num);
6891 _ii_unlock_chunks(ip, chunk_num, nc_got);
6892 if (!II_SUCCESS(rc)) {
6893 if (ca->wait)
6894 spcs_s_add(kstatus, rc);
6895 rc = DSW_EIO;
6896 break;
6897 }
6898 if (ip->bi_release ||
6899 (++chunkcount % ip->bi_throttle_unit) == 0) {
6900 _ii_rlse_devs(ip, (ca->rtype&(~BMP)));
6901 rsrv = 0;
6902 delay(ip->bi_throttle_delay);
6903 ca->rtype = MSTR|SHDR|(ca->rtype&BMP);
6904 if ((rc = _ii_rsrv_devs(ip, (ca->rtype&(~BMP)),
6905 II_INTERNAL)) != 0) {
6906 if (ca->wait)
6907 spcs_s_add(kstatus, rc);
6908 rc = DSW_EIO;
6909 break;
6910 }
6911 rsrv = 1;
6912 if (nc_max > 1) {
6913 /*
6914 * maxfbas could have changed during the
6915 * release/reserve, so recalculate the size
6916 * of transfer we can do.
6917 */
6918 (void) nsc_maxfbas(MSTFD(ip), 0, &mst_max);
6919 (void) nsc_maxfbas(SHDFD(ip), 0, &shd_max);
6920 nc_max = (mst_max < shd_max) ?
6921 mst_max : shd_max;
6922 nc_max /= DSW_SIZE;
6923 }
6924 }
6925 }
6926 skip:
6927 mutex_enter(&ip->bi_mutex);
6928 if (ip->bi_flags & DSW_COPYINGX)
6929 II_FLAG_CLR(DSW_COPYINGP|DSW_COPYINGX, ip);
6930 else
6931 II_FLAG_CLR(DSW_COPY_FLAGS, ip);
6932
6933 if ((ip->bi_flags & DSW_TREEMAP) && (flag & CV_SHD2MST) &&
6934 (ip->bi_flags & DSW_VOVERFLOW)) {
6935 int rs;
6936 bitmap_size = ip->bi_size / DSW_SIZE;
6937 if ((ip->bi_size % DSW_SIZE) != 0)
6938 ++bitmap_size;
6939 bitmap_size += 7;
6940 bitmap_size /= 8;
6941
6942 /* Count the number of copy bits set */
6943 rs = II_CNT_BITS(ip, ip->bi_copyfba, ©_set, bitmap_size);
6944 if ((rs == 0) && (copy_set == 0)) {
6945 /*
6946 * If we counted successfully and completed the copy
6947 * see if any writes have forced the set into the
6948 * overflow
6949 */
6950 rs = II_CNT_BITS(ip, ip->bi_shdfba, &shadow_set,
6951 bitmap_size);
6952 if ((rs == 0) && (shadow_set <
6953 (nsc_size_t)ip->bi_shdchks)) {
6954 II_FLAG_CLR(DSW_VOVERFLOW, ip);
6955 --iigkstat.spilled_over.value.ul;
6956 }
6957 }
6958 }
6959
6960 ca->rc = rc;
6961 cv_broadcast(&ip->bi_copydonecv);
6962 mutex_exit(&ip->bi_mutex);
6963 if (!ca->wait) {
6964 if (rsrv)
6965 _ii_rlse_devs(ip, ca->rtype);
6966 kmem_free(ca, sizeof (*ca));
6967 }
6968
6969 }
6970
6971 /*
6972 * _ii_copyvol()
6973 * Copy a volume.
6974 *
6975 * Calling/Exit State:
6976 * Returns 0 when the copy is complete or has been aborted,
6977 * otherwise error code.
6978 *
6979 * Description:
6980 * According to the flag, copy the master to the shadow volume or the
6981 * shadow to the master volume. Upon return wakeup all processes waiting
6982 * for this copy. Uses a separate process (_ii_copyvolp) to allow the
6983 * caller to be interrupted.
6984 */
6985
6986 static int
_ii_copyvol(_ii_info_t * ip,int flag,int rtype,spcs_s_info_t kstatus,int wait)6987 _ii_copyvol(_ii_info_t *ip, int flag, int rtype, spcs_s_info_t kstatus,
6988 int wait)
6989 {
6990 struct copy_args *ca;
6991 int rc;
6992
6993 /*
6994 * start copy in separate process.
6995 */
6996
6997 ca = (struct copy_args *)kmem_alloc(sizeof (*ca), KM_SLEEP);
6998 ca->ip = ip;
6999 ca->flag = flag;
7000 ca->rtype = rtype;
7001 ca->kstatus = kstatus;
7002 ca->wait = wait;
7003 ca->rc = 0;
7004
7005 if (rc = nsc_create_process((void (*)(void *))_ii_copyvolp,
7006 (void *)ca, FALSE)) {
7007 mutex_enter(&ip->bi_mutex);
7008 _ii_ioctl_done(ip);
7009 mutex_exit(&ip->bi_mutex);
7010 cmn_err(CE_NOTE, "!Can't create II copy process");
7011 kmem_free(ca, sizeof (*ca));
7012 return (rc);
7013 }
7014 mutex_enter(&ip->bi_mutex);
7015 if (wait == 0) {
7016 _ii_ioctl_done(ip);
7017 mutex_exit(&ip->bi_mutex);
7018 return (0);
7019 }
7020 while (ip->bi_flags & DSW_COPYINGP) {
7021 (void) cv_wait_sig(&ip->bi_copydonecv, &ip->bi_mutex);
7022 }
7023 _ii_ioctl_done(ip);
7024 mutex_exit(&ip->bi_mutex);
7025 rc = ca->rc;
7026 kmem_free(ca, sizeof (*ca));
7027
7028 return (rc);
7029 }
7030
7031 /*
7032 * _ii_stopcopy
7033 * Stops any copy process on ip.
7034 *
7035 * Calling/Exit State:
7036 * Returns 0 if the copy was stopped, otherwise error code.
7037 *
7038 * Description:
7039 * Stop an in-progress copy by setting the DSW_COPYINGX flag, then
7040 * wait for the copy to complete.
7041 */
7042
7043 static int
_ii_stopcopy(_ii_info_t * ip)7044 _ii_stopcopy(_ii_info_t *ip)
7045 {
7046 mutex_enter(&ip->bi_mutex);
7047 DTRACE_PROBE1(_ii_stopcopy_flags,
7048 uint_t, ip->bi_flags);
7049
7050 while (ip->bi_flags & DSW_COPYINGP) {
7051
7052 DTRACE_PROBE(_ii_stopcopy);
7053
7054 II_FLAG_SET(DSW_COPYINGX, ip);
7055
7056 if (cv_wait_sig(&ip->bi_copydonecv, &ip->bi_mutex) == 0) {
7057 /* Awoken by a signal */
7058 mutex_exit(&ip->bi_mutex);
7059 DTRACE_PROBE(_ii_stopcopy);
7060 return (EINTR);
7061 }
7062 }
7063
7064 mutex_exit(&ip->bi_mutex);
7065
7066 return (0);
7067 }
7068
7069 /*
7070 * _ii_error
7071 * Given the error type that occurred, and the current state of the
7072 * shadowing, set the appropriate error condition(s).
7073 *
7074 */
7075
7076 void
_ii_error(_ii_info_t * ip,int error_type)7077 _ii_error(_ii_info_t *ip, int error_type)
7078 {
7079 int copy_flags;
7080 int golden;
7081 int flags;
7082 int recursive_call = (error_type & DSW_OVERFLOW) != 0;
7083 int offline_bits = DSW_OFFLINE;
7084 _ii_info_t *xip;
7085 int rc;
7086
7087 error_type &= ~DSW_OVERFLOW;
7088
7089 mutex_enter(&ip->bi_mutex);
7090 flags = (ip->bi_flags) & offline_bits;
7091 if ((flags ^ error_type) == 0) {
7092 /* nothing new offline */
7093 mutex_exit(&ip->bi_mutex);
7094 return;
7095 }
7096
7097 if (error_type == DSW_BMPOFFLINE &&
7098 (ip->bi_flags & DSW_BMPOFFLINE) == 0) {
7099 /* first, let nskerd know */
7100 rc = _ii_report_bmp(ip);
7101 if (rc) {
7102 if (ii_debug > 0) {
7103 cmn_err(CE_WARN, "!Unable to mark bitmap bad in"
7104 " config DB; rc = %d", rc);
7105 }
7106 ip->bi_flags |= DSW_CFGOFFLINE;
7107 }
7108 }
7109
7110 flags = ip->bi_flags;
7111 golden = ((flags & DSW_GOLDEN) == DSW_GOLDEN);
7112 copy_flags = flags & DSW_COPYING;
7113
7114 switch (error_type) {
7115
7116 case DSW_BMPOFFLINE:
7117 /* prevent further use of bitmap */
7118 flags |= DSW_BMPOFFLINE;
7119 if (ii_debug > 0)
7120 cmn_err(CE_NOTE, "!ii: Bitmap offline");
7121
7122 switch (copy_flags) {
7123
7124 case DSW_COPYINGM:
7125 /* Bitmap offline, copying master to shadow */
7126 flags |= DSW_SHDOFFLINE;
7127 if (ii_debug > 0)
7128 cmn_err(CE_NOTE, "!ii: Implied shadow offline");
7129 break;
7130
7131 case DSW_COPYINGS:
7132 /* Bitmap offline, copying shadow to master */
7133 if (golden) {
7134 /* Shadow is still usable */
7135 if (ii_debug > 0)
7136 cmn_err(CE_NOTE,
7137 "!ii: Implied master offline");
7138 flags |= DSW_MSTOFFLINE;
7139 } else {
7140 /*
7141 * Snapshot restore from shadow to master
7142 * is a dumb thing to do anyway. Lose both.
7143 */
7144 flags |= DSW_SHDOFFLINE | DSW_MSTOFFLINE;
7145 if (ii_debug > 0)
7146 cmn_err(CE_NOTE,
7147 "ii: Implied master and "
7148 "shadow offline");
7149 }
7150 break;
7151
7152 case 0:
7153 /* Bitmap offline, no copying in progress */
7154 if (!golden) {
7155 if (ii_debug > 0)
7156 cmn_err(CE_NOTE,
7157 "!ii: Implied shadow offline");
7158 flags |= DSW_SHDOFFLINE;
7159 }
7160 break;
7161 }
7162 break;
7163
7164 case DSW_OVROFFLINE:
7165 flags |= DSW_OVROFFLINE;
7166 ASSERT(ip->bi_overflow);
7167 if (ii_debug > 0)
7168 cmn_err(CE_NOTE, "!ii: Overflow offline");
7169 /* FALLTHRU */
7170 case DSW_SHDOFFLINE:
7171 flags |= DSW_SHDOFFLINE;
7172 if (ii_debug > 0)
7173 cmn_err(CE_NOTE, "!ii: Shadow offline");
7174
7175 if (copy_flags == DSW_COPYINGS) {
7176 /* Shadow offline, copying shadow to master */
7177 if (ii_debug > 0)
7178 cmn_err(CE_NOTE, "!ii: Implied master offline");
7179 flags |= DSW_MSTOFFLINE;
7180 }
7181 break;
7182
7183 case DSW_MSTOFFLINE:
7184 flags |= DSW_MSTOFFLINE;
7185 if (ii_debug > 0)
7186 cmn_err(CE_NOTE, "!ii: Master offline");
7187
7188 switch (copy_flags) {
7189
7190 case DSW_COPYINGM:
7191 /* Master offline, copying master to shadow */
7192 flags |= DSW_SHDOFFLINE;
7193 if (ii_debug > 0)
7194 cmn_err(CE_NOTE, "!ii: Implied shadow offline");
7195 break;
7196
7197 case DSW_COPYINGS:
7198 /* Master offline, copying shadow to master */
7199 if (!golden) {
7200 flags |= DSW_SHDOFFLINE;
7201 if (ii_debug > 0)
7202 cmn_err(CE_NOTE,
7203 "!ii: Implied shadow offline");
7204 }
7205 break;
7206
7207 case 0:
7208 /* Master offline, no copying in progress */
7209 if (!golden) {
7210 flags |= DSW_SHDOFFLINE;
7211 if (ii_debug > 0)
7212 cmn_err(CE_NOTE,
7213 "!ii: Implied shadow offline");
7214 }
7215 break;
7216 }
7217 break;
7218
7219 default:
7220 break;
7221 }
7222
7223 II_FLAG_SET(flags, ip);
7224 mutex_exit(&ip->bi_mutex);
7225
7226 if (!recursive_call &&
7227 NSHADOWS(ip) && (flags&DSW_MSTOFFLINE) == DSW_MSTOFFLINE) {
7228 /* take master offline for all other sibling shadows */
7229 for (xip = ip->bi_head; xip; xip = xip->bi_sibling) {
7230 if (xip == ip)
7231 continue;
7232 if (_ii_rsrv_devs(xip, BMP, II_INTERNAL) != 0)
7233 continue;
7234 /* overload DSW_OVERFLOW */
7235 _ii_error(xip, DSW_MSTOFFLINE|DSW_OVERFLOW);
7236 _ii_rlse_devs(xip, BMP);
7237 }
7238 }
7239
7240 }
7241
7242
7243 /*
7244 * _ii_lock_chunk
7245 * Locks access to the specified chunk
7246 *
7247 */
7248
7249 static void
_ii_lock_chunk(_ii_info_t * ip,chunkid_t chunk)7250 _ii_lock_chunk(_ii_info_t *ip, chunkid_t chunk)
7251 {
7252 if (chunk == II_NULLCHUNK) {
7253
7254 DTRACE_PROBE(_ii_lock_chunk_type);
7255
7256 rw_enter(&ip->bi_busyrw, RW_WRITER);
7257
7258 } else {
7259
7260 DTRACE_PROBE(_ii_lock_chunk_type);
7261
7262 if (ip->bi_busy == NULL) {
7263 DTRACE_PROBE(_ii_lock_chunk_end);
7264 return;
7265 }
7266
7267 rw_enter(&ip->bi_busyrw, RW_READER);
7268 mutex_enter(&ip->bi_mutex);
7269 while (DSW_BIT_ISSET(ip->bi_busy[chunk / DSW_BITS],
7270 chunk % DSW_BITS))
7271 cv_wait(&ip->bi_busycv, &ip->bi_mutex);
7272 DSW_BIT_SET(ip->bi_busy[chunk / DSW_BITS], chunk % DSW_BITS);
7273 mutex_exit(&ip->bi_mutex);
7274 }
7275
7276 }
7277
7278
7279 /*
7280 * _ii_trylock_chunk
7281 * Tries to lock access to the specified chunk
7282 * Returns non-zero on success.
7283 *
7284 */
7285
7286 static int
_ii_trylock_chunk(_ii_info_t * ip,chunkid_t chunk)7287 _ii_trylock_chunk(_ii_info_t *ip, chunkid_t chunk)
7288 {
7289 int rc;
7290
7291 ASSERT(chunk != II_NULLCHUNK);
7292 if (rw_tryenter(&ip->bi_busyrw, RW_READER) == 0) {
7293 DTRACE_PROBE(_ii_trylock_chunk);
7294 return (0);
7295 }
7296
7297 if (ip->bi_busy == NULL) {
7298 DTRACE_PROBE(_ii_trylock_chunk_end);
7299 return (0);
7300 }
7301
7302 mutex_enter(&ip->bi_mutex);
7303 if (DSW_BIT_ISSET(ip->bi_busy[chunk / DSW_BITS], chunk % DSW_BITS)) {
7304 rw_exit(&ip->bi_busyrw); /* RW_READER */
7305 rc = 0;
7306 } else {
7307 DSW_BIT_SET(ip->bi_busy[chunk / DSW_BITS], chunk % DSW_BITS);
7308 rc = 1;
7309 }
7310 mutex_exit(&ip->bi_mutex);
7311
7312 return (rc);
7313 }
7314
7315 /*
7316 * _ii_unlock_chunks
7317 * Unlocks access to the specified chunks
7318 *
7319 */
7320
7321 static void
_ii_unlock_chunks(_ii_info_t * ip,chunkid_t chunk,int n)7322 _ii_unlock_chunks(_ii_info_t *ip, chunkid_t chunk, int n)
7323 {
7324 if (chunk == II_NULLCHUNK) {
7325
7326 DTRACE_PROBE(_ii_unlock_chunks);
7327
7328 rw_exit(&ip->bi_busyrw); /* RW_WRITER */
7329
7330 } else {
7331
7332 if (ip->bi_busy == NULL) {
7333 DTRACE_PROBE(_ii_unlock_chunks_end);
7334 return;
7335 }
7336 mutex_enter(&ip->bi_mutex);
7337
7338 DTRACE_PROBE(_ii_unlock_chunks);
7339
7340 for (; n-- > 0; chunk++) {
7341 ASSERT(DSW_BIT_ISSET(ip->bi_busy[chunk / DSW_BITS],
7342 chunk % DSW_BITS));
7343 DSW_BIT_CLR(ip->bi_busy[chunk / DSW_BITS],
7344 chunk % DSW_BITS);
7345 rw_exit(&ip->bi_busyrw); /* RW_READER */
7346 }
7347 cv_broadcast(&ip->bi_busycv);
7348 mutex_exit(&ip->bi_mutex);
7349
7350 }
7351 }
7352
7353 /*
7354 * Copyout the bit map.
7355 */
7356 static int
_ii_ab_co_bmp(_ii_info_t * ip,nsc_off_t bm_offset,unsigned char * user_bm,int user_bm_size)7357 _ii_ab_co_bmp(_ii_info_t *ip, nsc_off_t bm_offset, unsigned char *user_bm,
7358 int user_bm_size)
7359 {
7360 nsc_off_t last_fba;
7361 nsc_buf_t *tmp;
7362 nsc_vec_t *nsc_vecp;
7363 nsc_off_t fba_pos;
7364 int buf_fba_len;
7365 int buf_byte_len;
7366 size_t co_len;
7367 int rc;
7368
7369 DTRACE_PROBE2(_ii_ab_co_bmp_start, nsc_off_t, bm_offset,
7370 nsc_size_t, user_bm_size);
7371
7372 if (ip->bi_flags & DSW_BMPOFFLINE)
7373 return (EIO);
7374
7375 /* First calculate the size of the shadow and copy bitmaps */
7376 co_len = DSW_BM_FBA_LEN(ip->bi_size);
7377 ASSERT((ip->bi_copyfba - ip->bi_shdfba) == co_len);
7378
7379 /* Are we in the ranges of the various bitmaps/indexes? */
7380 if (bm_offset < ip->bi_shdfba)
7381 return (EIO);
7382 else if (bm_offset < (last_fba = ip->bi_shdfba + co_len))
7383 /*EMPTY*/;
7384 else if (bm_offset < (last_fba = ip->bi_copyfba + co_len))
7385 /*EMPTY*/;
7386 else if ((ip->bi_flags & DSW_TREEMAP) &&
7387 (bm_offset < (last_fba = last_fba + (co_len * 32))))
7388 /*EMPTY*/;
7389 else return (EIO);
7390
7391 /* Are we within the size of the segment being copied? */
7392 if (FBA_LEN(user_bm_size) > last_fba - bm_offset)
7393 return (EIO);
7394
7395 for (fba_pos = bm_offset; fba_pos < last_fba && user_bm_size > 0;
7396 fba_pos += DSW_CBLK_FBA) {
7397 tmp = NULL;
7398 buf_fba_len = fba_pos + DSW_CBLK_FBA < last_fba ?
7399 DSW_CBLK_FBA : last_fba - fba_pos;
7400 II_READ_START(ip, bitmap);
7401 rc = nsc_alloc_buf(ip->bi_bmpfd, fba_pos, buf_fba_len,
7402 NSC_RDBUF, &tmp);
7403 II_READ_END(ip, bitmap, rc, buf_fba_len);
7404 if (!II_SUCCESS(rc)) {
7405 if (tmp)
7406 (void) nsc_free_buf(tmp);
7407
7408 _ii_error(ip, DSW_BMPOFFLINE);
7409 return (EIO);
7410 }
7411
7412 /* copyout each nsc_vec's worth of data */
7413 buf_byte_len = FBA_SIZE(buf_fba_len);
7414 for (nsc_vecp = tmp->sb_vec;
7415 buf_byte_len > 0 && user_bm_size > 0;
7416 nsc_vecp++) {
7417 co_len = (user_bm_size > nsc_vecp->sv_len) ?
7418 nsc_vecp->sv_len : user_bm_size;
7419 if (copyout(nsc_vecp->sv_addr, user_bm, co_len)) {
7420 (void) nsc_free_buf(tmp);
7421 return (EFAULT);
7422 }
7423 user_bm += co_len;
7424 user_bm_size -= co_len;
7425 buf_byte_len -= co_len;
7426 }
7427
7428
7429 (void) nsc_free_buf(tmp);
7430 }
7431
7432 return (0);
7433 }
7434
7435 /*
7436 * Copyin a bit map and or with differences bitmap.
7437 */
7438 static int
_ii_ab_ci_bmp(_ii_info_t * ip,nsc_off_t bm_offset,unsigned char * user_bm,int user_bm_size)7439 _ii_ab_ci_bmp(_ii_info_t *ip, nsc_off_t bm_offset, unsigned char *user_bm,
7440 int user_bm_size)
7441 {
7442 nsc_off_t last_fba;
7443 nsc_buf_t *tmp;
7444 nsc_vec_t *nsc_vecp;
7445 nsc_off_t fba_pos;
7446 int buf_fba_len;
7447 int buf_byte_len;
7448 size_t ci_len;
7449 int rc;
7450 int n;
7451 unsigned char *tmp_buf, *tmpp, *tmpq;
7452
7453 DTRACE_PROBE2(_ii_ab_ci_bmp_start, nsc_off_t, bm_offset,
7454 nsc_size_t, user_bm_size);
7455
7456 if (ip->bi_flags & DSW_BMPOFFLINE)
7457 return (EIO);
7458
7459 tmp_buf = NULL;
7460 last_fba = bm_offset + DSW_BM_FBA_LEN(ip->bi_size);
7461
7462 for (fba_pos = bm_offset; fba_pos < last_fba && user_bm_size > 0;
7463 fba_pos += DSW_CBLK_FBA) {
7464 tmp = NULL;
7465 buf_fba_len = fba_pos + DSW_CBLK_FBA < last_fba ?
7466 DSW_CBLK_FBA : last_fba - fba_pos;
7467 II_READ_START(ip, bitmap);
7468 rc = nsc_alloc_buf(ip->bi_bmpfd, fba_pos, buf_fba_len,
7469 NSC_RDWRBUF, &tmp);
7470 II_READ_END(ip, bitmap, rc, buf_fba_len);
7471 if (!II_SUCCESS(rc)) {
7472 if (tmp)
7473 (void) nsc_free_buf(tmp);
7474
7475 _ii_error(ip, DSW_BMPOFFLINE);
7476 return (EIO);
7477 }
7478
7479 /* copyin each nsc_vec's worth of data */
7480 buf_byte_len = FBA_SIZE(buf_fba_len);
7481 for (nsc_vecp = tmp->sb_vec;
7482 buf_byte_len > 0 && user_bm_size > 0;
7483 nsc_vecp++) {
7484 ci_len = (user_bm_size > nsc_vecp->sv_len) ?
7485 nsc_vecp->sv_len : user_bm_size;
7486 tmpp = tmp_buf = kmem_alloc(ci_len, KM_SLEEP);
7487 tmpq = nsc_vecp->sv_addr;
7488 if (copyin(user_bm, tmpp, ci_len)) {
7489 (void) nsc_free_buf(tmp);
7490 kmem_free(tmp_buf, ci_len);
7491 return (EFAULT);
7492 }
7493 for (n = ci_len; n-- > 0; /* CSTYLED */)
7494 *tmpq++ |= *tmpp++;
7495 user_bm += ci_len;
7496 user_bm_size -= ci_len;
7497 buf_byte_len -= ci_len;
7498 kmem_free(tmp_buf, ci_len);
7499 }
7500
7501 II_NSC_WRITE(ip, bitmap, rc, tmp, fba_pos, buf_fba_len, 0);
7502 if (!II_SUCCESS(rc)) {
7503 (void) nsc_free_buf(tmp);
7504 _ii_error(ip, DSW_BMPOFFLINE);
7505 return (EIO);
7506 }
7507
7508 (void) nsc_free_buf(tmp);
7509 }
7510
7511 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
7512
7513 return (0);
7514 }
7515
7516 /*
7517 * Completely zero the bit map.
7518 *
7519 * Returns 0 if no error
7520 * Returns non-zero if there was an error
7521 */
7522 static int
_ii_ab_zerobm(_ii_info_t * ip)7523 _ii_ab_zerobm(_ii_info_t *ip)
7524 {
7525 nsc_off_t fba_pos;
7526 int rc;
7527 nsc_size_t len;
7528 nsc_size_t size;
7529 nsc_buf_t *tmp;
7530
7531 size = DSW_BM_FBA_LEN(ip->bi_size) + ip->bi_shdfba;
7532 for (fba_pos = ip->bi_shdfba; fba_pos < size; fba_pos += DSW_CBLK_FBA) {
7533 tmp = NULL;
7534 len = fba_pos + DSW_CBLK_FBA < size ?
7535 DSW_CBLK_FBA : size - fba_pos;
7536 II_READ_START(ip, bitmap);
7537 rc = nsc_alloc_buf(ip->bi_bmpfd, fba_pos, len, NSC_RDWRBUF,
7538 &tmp);
7539 II_READ_END(ip, bitmap, rc, len);
7540 if (!II_SUCCESS(rc)) {
7541 if (tmp)
7542 (void) nsc_free_buf(tmp);
7543
7544 _ii_error(ip, DSW_BMPOFFLINE);
7545 return (rc);
7546 }
7547
7548 rc = nsc_zero(tmp, fba_pos, len, 0);
7549 if (II_SUCCESS(rc)) {
7550 II_NSC_WRITE(ip, bitmap, rc, tmp, fba_pos, len, 0);
7551 }
7552
7553 (void) nsc_free_buf(tmp);
7554 if (!II_SUCCESS(rc)) {
7555 _ii_error(ip, DSW_BMPOFFLINE);
7556 return (rc);
7557 }
7558 }
7559
7560 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
7561
7562 return (0);
7563 }
7564
7565
7566 /*
7567 * Copy shadow bitmap to copy bitmap
7568 */
7569 static int
_ii_ab_copybm(_ii_info_t * ip)7570 _ii_ab_copybm(_ii_info_t *ip)
7571 {
7572 nsc_off_t copy_fba_pos, shd_fba_pos;
7573 int rc;
7574 nsc_size_t len;
7575 nsc_off_t size;
7576 nsc_buf_t *copy_tmp, *shd_tmp;
7577
7578 size = DSW_BM_FBA_LEN(ip->bi_size) + ip->bi_shdfba;
7579 copy_fba_pos = ip->bi_copyfba;
7580 for (shd_fba_pos = ip->bi_shdfba; shd_fba_pos < size;
7581 copy_fba_pos += DSW_CBLK_FBA, shd_fba_pos += DSW_CBLK_FBA) {
7582 shd_tmp = NULL;
7583 len = shd_fba_pos + DSW_CBLK_FBA < size ?
7584 DSW_CBLK_FBA : size - shd_fba_pos;
7585 II_READ_START(ip, bitmap);
7586 rc = nsc_alloc_buf(ip->bi_bmpfd, shd_fba_pos, len, NSC_RDBUF,
7587 &shd_tmp);
7588 II_READ_END(ip, bitmap, rc, len);
7589 if (!II_SUCCESS(rc)) {
7590 if (shd_tmp)
7591 (void) nsc_free_buf(shd_tmp);
7592
7593 _ii_error(ip, DSW_BMPOFFLINE);
7594 if (ii_debug > 1)
7595 cmn_err(CE_NOTE, "!ii: copybm failed 1 rc %d",
7596 rc);
7597
7598 return (rc);
7599 }
7600
7601 copy_tmp = NULL;
7602 rc = nsc_alloc_buf(ip->bi_bmpfd, copy_fba_pos, len, NSC_WRBUF,
7603 ©_tmp);
7604 if (!II_SUCCESS(rc)) {
7605 (void) nsc_free_buf(shd_tmp);
7606 if (copy_tmp)
7607 (void) nsc_free_buf(copy_tmp);
7608
7609 _ii_error(ip, DSW_BMPOFFLINE);
7610 if (ii_debug > 1)
7611 cmn_err(CE_NOTE, "!ii: copybm failed 2 rc %d",
7612 rc);
7613
7614 return (rc);
7615 }
7616 rc = nsc_copy(shd_tmp, copy_tmp, shd_fba_pos, copy_fba_pos,
7617 len);
7618 if (II_SUCCESS(rc)) {
7619 II_NSC_WRITE(ip, bitmap, rc, copy_tmp, copy_fba_pos,
7620 len, 0);
7621 }
7622
7623 (void) nsc_free_buf(shd_tmp);
7624 (void) nsc_free_buf(copy_tmp);
7625 if (!II_SUCCESS(rc)) {
7626 if (ii_debug > 1)
7627 cmn_err(CE_NOTE, "!ii: copybm failed 4 rc %d",
7628 rc);
7629 _ii_error(ip, DSW_BMPOFFLINE);
7630 return (rc);
7631 }
7632 }
7633
7634 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
7635
7636 return (0);
7637 }
7638
7639
7640 /*
7641 * stolen from nsc_copy_h()
7642 */
7643
7644 static int
_ii_nsc_or(nsc_buf_t * h1,nsc_buf_t * h2,nsc_off_t pos1,nsc_off_t pos2,nsc_size_t len)7645 _ii_nsc_or(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1, nsc_off_t pos2,
7646 nsc_size_t len)
7647 {
7648 unsigned char *a1, *a2;
7649 unsigned char *b1, *b2;
7650 nsc_vec_t *v1, *v2;
7651 int i, sz, l1, l2;
7652
7653 if (pos1 < h1->sb_pos || pos1 + len > h1->sb_pos + h1->sb_len ||
7654 pos2 < h2->sb_pos || pos2 + len > h2->sb_pos + h2->sb_len)
7655 return (EINVAL);
7656
7657 if (!len)
7658 return (0);
7659
7660 /* find starting point in "from" vector */
7661
7662 v1 = h1->sb_vec;
7663 pos1 -= h1->sb_pos;
7664
7665 for (; pos1 >= FBA_NUM(v1->sv_len); v1++)
7666 pos1 -= FBA_NUM(v1->sv_len);
7667
7668 a1 = v1->sv_addr + FBA_SIZE(pos1);
7669 l1 = v1->sv_len - FBA_SIZE(pos1);
7670
7671 /* find starting point in "to" vector */
7672
7673 v2 = h2->sb_vec;
7674 pos2 -= h2->sb_pos;
7675
7676 for (; pos2 >= FBA_NUM(v2->sv_len); v2++)
7677 pos2 -= FBA_NUM(v2->sv_len);
7678
7679 a2 = v2->sv_addr + FBA_SIZE(pos2);
7680 l2 = v2->sv_len - FBA_SIZE(pos2);
7681
7682 /* copy required data */
7683
7684 len = FBA_SIZE(len);
7685
7686 while (len) {
7687 sz = min(l1, l2);
7688 sz = (int)min((nsc_size_t)sz, len);
7689
7690 b1 = a1;
7691 b2 = a2;
7692 for (i = sz; i-- > 0; /* CSTYLED */)
7693 *b2++ |= *b1++;
7694
7695 l1 -= sz;
7696 l2 -= sz;
7697 a1 += sz;
7698 a2 += sz;
7699 len -= sz;
7700
7701 if (!l1) {
7702 a1 = (++v1)->sv_addr;
7703 l1 = v1->sv_len;
7704 }
7705 if (!l2) {
7706 a2 = (++v2)->sv_addr;
7707 l2 = v2->sv_len;
7708 }
7709 }
7710
7711 return (0);
7712 }
7713
7714
7715 /*
7716 * Or the shadow bitmap in to the copy bitmap, clear the
7717 * shadow bitmap.
7718 */
7719 static int
_ii_ab_orbm(_ii_info_t * ip)7720 _ii_ab_orbm(_ii_info_t *ip)
7721 {
7722 nsc_off_t copy_fba_pos, shd_fba_pos;
7723 int rc;
7724 nsc_size_t len;
7725 size_t size;
7726 nsc_buf_t *copy_tmp, *shd_tmp;
7727
7728 if (ip->bi_flags & DSW_BMPOFFLINE)
7729 return (EIO);
7730
7731 size = DSW_BM_FBA_LEN(ip->bi_size) + ip->bi_shdfba;
7732 copy_fba_pos = ip->bi_copyfba;
7733 for (shd_fba_pos = ip->bi_shdfba; shd_fba_pos < size;
7734 copy_fba_pos += DSW_CBLK_FBA, shd_fba_pos += DSW_CBLK_FBA) {
7735 shd_tmp = NULL;
7736 len = shd_fba_pos + DSW_CBLK_FBA < size ?
7737 DSW_CBLK_FBA : size - shd_fba_pos;
7738 II_READ_START(ip, bitmap);
7739 rc = nsc_alloc_buf(ip->bi_bmpfd, shd_fba_pos, len,
7740 NSC_RDBUF|NSC_WRBUF, &shd_tmp);
7741 II_READ_END(ip, bitmap, rc, len);
7742 if (!II_SUCCESS(rc)) {
7743 if (shd_tmp)
7744 (void) nsc_free_buf(shd_tmp);
7745
7746 _ii_error(ip, DSW_BMPOFFLINE);
7747 return (rc);
7748 }
7749
7750 copy_tmp = NULL;
7751 II_READ_START(ip, bitmap);
7752 rc = nsc_alloc_buf(ip->bi_bmpfd, copy_fba_pos, len,
7753 NSC_RDBUF|NSC_WRBUF, ©_tmp);
7754 II_READ_END(ip, bitmap, rc, len);
7755 if (!II_SUCCESS(rc)) {
7756 (void) nsc_free_buf(shd_tmp);
7757 if (copy_tmp)
7758 (void) nsc_free_buf(copy_tmp);
7759
7760 _ii_error(ip, DSW_BMPOFFLINE);
7761 return (rc);
7762 }
7763 rc = _ii_nsc_or(shd_tmp, copy_tmp, shd_fba_pos, copy_fba_pos,
7764 len);
7765 if (II_SUCCESS(rc)) {
7766 II_NSC_WRITE(ip, bitmap, rc, copy_tmp, copy_fba_pos,
7767 len, 0);
7768 }
7769 if (II_SUCCESS(rc))
7770 rc = nsc_zero(shd_tmp, shd_fba_pos, len, 0);
7771 if (II_SUCCESS(rc)) {
7772 II_NSC_WRITE(ip, bitmap, rc, shd_tmp, shd_fba_pos, len,
7773 0);
7774 }
7775
7776 (void) nsc_free_buf(shd_tmp);
7777 (void) nsc_free_buf(copy_tmp);
7778 if (!II_SUCCESS(rc)) {
7779 _ii_error(ip, DSW_BMPOFFLINE);
7780 return (rc);
7781 }
7782 }
7783
7784 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
7785
7786 return (0);
7787 }
7788
7789 /*
7790 * _ii_ab_tst_shd_bit
7791 * Determine if a chunk has been copied to the shadow device
7792 * Relies on the alloc_buf/free_buf semantics for locking.
7793 *
7794 * Calling/Exit State:
7795 * Returns 1 if the modified bit has been set for the shadow device,
7796 * Returns 0 if the modified bit has not been set for the shadow device,
7797 * Returns -1 if there was an error
7798 */
7799
7800 static int
_ii_ab_tst_shd_bit(_ii_info_t * ip,chunkid_t chunk)7801 _ii_ab_tst_shd_bit(_ii_info_t *ip, chunkid_t chunk)
7802 {
7803 int rc;
7804 nsc_off_t fba;
7805 nsc_buf_t *tmp = NULL;
7806
7807 if (ip->bi_flags & DSW_BMPOFFLINE)
7808 return (EIO);
7809
7810 fba = ip->bi_shdfba + chunk / (FBA_SIZE(1) * DSW_BITS);
7811 chunk %= FBA_SIZE(1) * DSW_BITS;
7812 II_READ_START(ip, bitmap);
7813 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF, &tmp);
7814 II_READ_END(ip, bitmap, rc, 1);
7815 if (!II_SUCCESS(rc)) {
7816 _ii_error(ip, DSW_BMPOFFLINE);
7817 if (tmp)
7818 (void) nsc_free_buf(tmp);
7819 return (-1);
7820 }
7821 rc = DSW_BIT_ISSET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7822 chunk%DSW_BITS);
7823 (void) nsc_free_buf(tmp);
7824
7825 return (rc);
7826 }
7827
7828
7829 /*
7830 * _ii_ab_set_shd_bit
7831 * Records that a chunk has been copied to the shadow device
7832 *
7833 * Returns non-zero if an error is encountered
7834 * Returns 0 if no error
7835 */
7836
7837 static int
_ii_ab_set_shd_bit(_ii_info_t * ip,chunkid_t chunk)7838 _ii_ab_set_shd_bit(_ii_info_t *ip, chunkid_t chunk)
7839 {
7840 int rc;
7841 nsc_off_t fba;
7842 nsc_buf_t *tmp = NULL;
7843
7844 if (ip->bi_flags & DSW_BMPOFFLINE)
7845 return (EIO);
7846
7847 fba = ip->bi_shdfba + chunk / (FBA_SIZE(1) * DSW_BITS);
7848 chunk %= FBA_SIZE(1) * DSW_BITS;
7849 II_READ_START(ip, bitmap);
7850 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF|NSC_WRBUF, &tmp);
7851 II_READ_END(ip, bitmap, rc, 1);
7852 if (!II_SUCCESS(rc)) {
7853 _ii_error(ip, DSW_BMPOFFLINE);
7854 if (tmp)
7855 (void) nsc_free_buf(tmp);
7856 return (rc);
7857 }
7858 if (DSW_BIT_ISSET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7859 chunk%DSW_BITS) == 0) {
7860 DSW_BIT_SET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7861 chunk%DSW_BITS);
7862 II_NSC_WRITE(ip, bitmap, rc, tmp, fba, 1, 0);
7863 if ((ip->bi_state & DSW_CNTSHDBITS) == 0)
7864 ip->bi_shdbits++;
7865 }
7866 (void) nsc_free_buf(tmp);
7867 if (!II_SUCCESS(rc)) {
7868 _ii_error(ip, DSW_BMPOFFLINE);
7869 return (rc);
7870 }
7871
7872 return (0);
7873 }
7874
7875
7876 /*
7877 * _ii_ab_tst_copy_bit
7878 * Determine if a chunk needs to be copied during updates.
7879 *
7880 * Calling/Exit State:
7881 * Returns 1 if the copy bit for the chunk is set
7882 * Returns 0 if the copy bit for the chunk is not set
7883 * Returns -1 if an error is encountered
7884 */
7885
7886 static int
_ii_ab_tst_copy_bit(_ii_info_t * ip,chunkid_t chunk)7887 _ii_ab_tst_copy_bit(_ii_info_t *ip, chunkid_t chunk)
7888 {
7889 int rc;
7890 nsc_off_t fba;
7891 nsc_buf_t *tmp = NULL;
7892
7893 if (ip->bi_flags & DSW_BMPOFFLINE)
7894 return (-1);
7895
7896 fba = ip->bi_copyfba + chunk / (FBA_SIZE(1) * DSW_BITS);
7897 chunk %= FBA_SIZE(1) * DSW_BITS;
7898 II_READ_START(ip, bitmap);
7899 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF, &tmp);
7900 II_READ_END(ip, bitmap, rc, 1);
7901 if (!II_SUCCESS(rc)) {
7902 if (tmp)
7903 (void) nsc_free_buf(tmp);
7904 _ii_error(ip, DSW_BMPOFFLINE);
7905 return (-1);
7906 }
7907 rc = DSW_BIT_ISSET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7908 chunk%DSW_BITS);
7909 (void) nsc_free_buf(tmp);
7910
7911 return (rc);
7912 }
7913
7914
7915 /*
7916 * _ii_ab_set_copy_bit
7917 * Records that a chunk has been copied to the shadow device
7918 *
7919 * Returns non-zero if an error is encountered
7920 * Returns 0 if no error
7921 */
7922
7923 static int
_ii_ab_set_copy_bit(_ii_info_t * ip,chunkid_t chunk)7924 _ii_ab_set_copy_bit(_ii_info_t *ip, chunkid_t chunk)
7925 {
7926 int rc;
7927 nsc_off_t fba;
7928 nsc_buf_t *tmp = NULL;
7929
7930 if (ip->bi_flags & DSW_BMPOFFLINE)
7931 return (EIO);
7932
7933 fba = ip->bi_copyfba + chunk / (FBA_SIZE(1) * DSW_BITS);
7934 chunk %= FBA_SIZE(1) * DSW_BITS;
7935 II_READ_START(ip, bitmap);
7936 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF|NSC_WRBUF, &tmp);
7937 II_READ_END(ip, bitmap, rc, 1);
7938 if (!II_SUCCESS(rc)) {
7939 if (tmp)
7940 (void) nsc_free_buf(tmp);
7941 _ii_error(ip, DSW_BMPOFFLINE);
7942 return (rc);
7943 }
7944 if (DSW_BIT_ISSET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7945 chunk%DSW_BITS) == 0) {
7946 DSW_BIT_SET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7947 chunk%DSW_BITS);
7948 if ((ip->bi_state & DSW_CNTCPYBITS) == 0)
7949 ip->bi_copybits++;
7950
7951 II_NSC_WRITE(ip, bitmap, rc, tmp, fba, 1, 0);
7952 }
7953 (void) nsc_free_buf(tmp);
7954 if (!II_SUCCESS(rc)) {
7955 _ii_error(ip, DSW_BMPOFFLINE);
7956 return (rc);
7957 }
7958
7959 return (0);
7960 }
7961
7962
7963 /*
7964 * _ii_ab_clr_copy_bits
7965 * Records that a chunk has been cleared on the shadow device, this
7966 * function assumes that the bits to clear are all in the same fba,
7967 * as is the case when they were generated by _ii_ab_next_copy_bit().
7968 *
7969 * Returns non-zero if an error is encountered
7970 * Returns 0 if no error
7971 */
7972
7973 static int
_ii_ab_clr_copy_bits(_ii_info_t * ip,chunkid_t chunk,int nchunks)7974 _ii_ab_clr_copy_bits(_ii_info_t *ip, chunkid_t chunk, int nchunks)
7975 {
7976 int rc;
7977 nsc_off_t fba;
7978 nsc_buf_t *tmp = NULL;
7979
7980 if (ip->bi_flags & DSW_BMPOFFLINE)
7981 return (EIO);
7982
7983 fba = ip->bi_copyfba + chunk / (FBA_SIZE(1) * DSW_BITS);
7984 chunk %= FBA_SIZE(1) * DSW_BITS;
7985 II_READ_START(ip, bitmap);
7986 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF|NSC_WRBUF, &tmp);
7987 II_READ_END(ip, bitmap, rc, 1);
7988 if (!II_SUCCESS(rc)) {
7989 if (tmp)
7990 (void) nsc_free_buf(tmp);
7991 _ii_error(ip, DSW_BMPOFFLINE);
7992 return (rc);
7993 }
7994 for (; nchunks-- > 0; chunk++) {
7995 DSW_BIT_CLR(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
7996 chunk%DSW_BITS);
7997 if (ip->bi_copybits > 0)
7998 ip->bi_copybits--;
7999 }
8000
8001 II_NSC_WRITE(ip, bitmap, rc, tmp, fba, 1, 0);
8002 (void) nsc_free_buf(tmp);
8003 if (!II_SUCCESS(rc)) {
8004 _ii_error(ip, DSW_BMPOFFLINE);
8005 return (rc);
8006 }
8007
8008 return (0);
8009 }
8010
8011 /*
8012 * _ii_ab_fill_copy_bmp
8013 * Fills the copy bitmap with 1's.
8014 *
8015 * Returns non-zero if an error is encountered
8016 * Returns 0 if no error
8017 */
8018
8019 static int
_ii_ab_fill_copy_bmp(_ii_info_t * ip)8020 _ii_ab_fill_copy_bmp(_ii_info_t *ip)
8021 {
8022 int rc;
8023 nsc_off_t fba;
8024 nsc_buf_t *tmp;
8025 unsigned char *p;
8026 int i, j;
8027
8028 if (ip->bi_flags & DSW_BMPOFFLINE)
8029 return (EIO);
8030
8031 fba = ip->bi_copyfba;
8032 for (i = DSW_BM_FBA_LEN(ip->bi_size); i-- > 0; fba++) {
8033 tmp = NULL;
8034 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_WRBUF, &tmp);
8035 if (!II_SUCCESS(rc)) {
8036 if (tmp)
8037 (void) nsc_free_buf(tmp);
8038 _ii_error(ip, DSW_BMPOFFLINE);
8039 return (rc);
8040 }
8041 p = (unsigned char *)tmp->sb_vec->sv_addr;
8042 for (j = FBA_SIZE(1); j-- > 0; p++)
8043 *p = (unsigned char)0xff;
8044 II_NSC_WRITE(ip, bitmap, rc, tmp, fba, 1, 0);
8045 if (!II_SUCCESS(rc)) {
8046 _ii_error(ip, DSW_BMPOFFLINE);
8047 (void) nsc_free_buf(tmp);
8048 return (rc);
8049 }
8050 (void) nsc_free_buf(tmp);
8051 }
8052
8053 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8054
8055 return (0);
8056 }
8057
8058 /*
8059 * _ii_ab_load_bmp
8060 * Load bitmap from persistent storage.
8061 */
8062
8063 static int
_ii_ab_load_bmp(_ii_info_t * ip,int flag)8064 _ii_ab_load_bmp(_ii_info_t *ip, int flag)
8065 /* ARGSUSED */
8066 {
8067 if (ip->bi_flags & DSW_BMPOFFLINE)
8068 return (EIO);
8069
8070 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8071
8072 return (0);
8073 }
8074
8075 /*
8076 * _ii_ab_next_copy_bit
8077 * Find next set copy bit.
8078 *
8079 * Returns the next bits set in the copy bitmap, with the corresponding chunks
8080 * locked. Used to avoid having to reread the same bit map block as each bit
8081 * is tested.
8082 */
8083
8084 static chunkid_t
_ii_ab_next_copy_bit(_ii_info_t * ip,chunkid_t startchunk,chunkid_t maxchunk,int wanted,int * got)8085 _ii_ab_next_copy_bit(_ii_info_t *ip, chunkid_t startchunk, chunkid_t maxchunk,
8086 int wanted, int *got)
8087 {
8088 chunkid_t rc;
8089 nsc_off_t fba;
8090 chunkid_t chunk;
8091 int bits_per_fba = FBA_SIZE(1) * DSW_BITS;
8092 int high;
8093 chunkid_t nextchunk;
8094 nsc_buf_t *tmp = NULL;
8095
8096 *got = 0;
8097 again:
8098 if (ip->bi_flags & DSW_BMPOFFLINE)
8099 return (maxchunk + 1);
8100
8101 while (startchunk < maxchunk) {
8102 tmp = NULL;
8103 fba = ip->bi_copyfba + startchunk / bits_per_fba;
8104 chunk = startchunk % bits_per_fba;
8105 II_READ_START(ip, bitmap);
8106 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF, &tmp);
8107 II_READ_END(ip, bitmap, rc, 1);
8108 if (!II_SUCCESS(rc)) {
8109 if (tmp)
8110 (void) nsc_free_buf(tmp);
8111 _ii_error(ip, DSW_BMPOFFLINE);
8112 return (maxchunk + 1);
8113 }
8114 high = startchunk + bits_per_fba - startchunk%bits_per_fba;
8115 if (high > maxchunk)
8116 high = maxchunk;
8117 for (; startchunk < high; chunk++, startchunk++) {
8118 if (DSW_BIT_ISSET(tmp->sb_vec->sv_addr[chunk/DSW_BITS],
8119 chunk%DSW_BITS)) {
8120 /*
8121 * trylock won't sleep so can use while
8122 * holding the buf.
8123 */
8124 if (!_ii_trylock_chunk(ip, startchunk)) {
8125 (void) nsc_free_buf(tmp);
8126 _ii_lock_chunk(ip, startchunk);
8127 if (_ii_ab_tst_copy_bit(ip, startchunk)
8128 != 1) {
8129 /*
8130 * another process copied this
8131 * chunk while we were acquiring
8132 * the chunk lock.
8133 */
8134 _ii_unlock_chunk(ip,
8135 startchunk);
8136 DTRACE_PROBE(
8137 _ii_ab_next_copy_bit_again);
8138 goto again;
8139 }
8140 *got = 1;
8141 DTRACE_PROBE(_ii_ab_next_copy_bit_end);
8142 return (startchunk);
8143 }
8144 *got = 1;
8145 nextchunk = startchunk + 1;
8146 chunk++;
8147 for (; --wanted > 0 && nextchunk < high;
8148 nextchunk++, chunk++) {
8149 if (!DSW_BIT_ISSET(tmp->sb_vec->sv_addr
8150 [chunk/DSW_BITS], chunk%DSW_BITS)) {
8151 break; /* end of bit run */
8152 }
8153 if (_ii_trylock_chunk(ip, nextchunk))
8154 (*got)++;
8155 else
8156 break;
8157 }
8158 (void) nsc_free_buf(tmp);
8159 DTRACE_PROBE(_ii_ab_next_copy_bit);
8160 return (startchunk);
8161 }
8162 }
8163 (void) nsc_free_buf(tmp);
8164 }
8165
8166 return (maxchunk + 1);
8167 }
8168
8169 /*
8170 * _ii_ab_save_bmp
8171 * Save bitmap to persistent storage.
8172 */
8173
8174 static int
_ii_ab_save_bmp(_ii_info_t * ip,int flag)8175 _ii_ab_save_bmp(_ii_info_t *ip, int flag)
8176 /* ARGSUSED */
8177 {
8178 if (ip->bi_flags & DSW_BMPOFFLINE)
8179 return (EIO);
8180
8181 return (0);
8182 }
8183
8184 /*
8185 * _ii_ab_change_bmp
8186 * copy change bitmap to memory
8187 */
8188
8189 static int
_ii_ab_change_bmp(_ii_info_t * ip,unsigned char * ptr)8190 _ii_ab_change_bmp(_ii_info_t *ip, unsigned char *ptr)
8191 /* ARGSUSED */
8192 {
8193 int bm_size;
8194 int i, j, fba;
8195 int rc;
8196 unsigned char *p;
8197 nsc_buf_t *tmp = NULL;
8198
8199 if (ip->bi_flags & DSW_BMPOFFLINE)
8200 return (EIO);
8201 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
8202
8203 rc = _ii_nsc_io(ip, KS_BMP, ip->bi_bmpfd, NSC_RDBUF, ip->bi_shdfba,
8204 ptr, bm_size);
8205 if (!II_SUCCESS(rc)) {
8206 _ii_error(ip, DSW_BMPOFFLINE);
8207 return (rc);
8208 }
8209
8210 fba = ip->bi_copyfba;
8211 for (i = DSW_BM_FBA_LEN(ip->bi_size); i-- > 0; fba++) {
8212 tmp = NULL;
8213 II_READ_START(ip, bitmap);
8214 rc = nsc_alloc_buf(ip->bi_bmpfd, fba, 1, NSC_RDBUF, &tmp);
8215 II_READ_END(ip, bitmap, rc, 1);
8216 if (!II_SUCCESS(rc)) {
8217 if (tmp)
8218 (void) nsc_free_buf(tmp);
8219 _ii_error(ip, DSW_BMPOFFLINE);
8220 return (rc);
8221 }
8222 p = (unsigned char *)tmp->sb_vec->sv_addr;
8223 for (j = FBA_SIZE(1); j-- > 0; p++)
8224 *ptr |= *p;
8225 (void) nsc_free_buf(tmp);
8226 }
8227
8228 return (0);
8229 }
8230
8231 /*
8232 * Count bits set in the bit map.
8233 */
8234 static int
_ii_ab_cnt_bits(_ii_info_t * ip,nsc_off_t bm_offset,nsc_size_t * counter,int bm_size)8235 _ii_ab_cnt_bits(_ii_info_t *ip, nsc_off_t bm_offset, nsc_size_t *counter,
8236 int bm_size)
8237 {
8238 nsc_size_t last_fba;
8239 nsc_buf_t *tmp;
8240 nsc_vec_t *sd_vecp;
8241 nsc_off_t fba_pos;
8242 int buf_fba_len;
8243 int buf_byte_len;
8244 int co_len;
8245 int i;
8246 unsigned int j, k;
8247 unsigned char *cp;
8248 int rc;
8249
8250 *counter = 0;
8251 if (ip->bi_flags & DSW_BMPOFFLINE)
8252 return (EIO);
8253
8254 last_fba = bm_offset + DSW_BM_FBA_LEN(ip->bi_size);
8255
8256 for (fba_pos = bm_offset; fba_pos < last_fba && bm_size > 0;
8257 fba_pos += DSW_CBLK_FBA) {
8258 tmp = NULL;
8259 buf_fba_len = fba_pos + DSW_CBLK_FBA < last_fba ?
8260 DSW_CBLK_FBA : last_fba - fba_pos;
8261 II_READ_START(ip, bitmap);
8262 rc = nsc_alloc_buf(ip->bi_bmpfd, fba_pos, buf_fba_len,
8263 NSC_RDBUF, &tmp);
8264 II_READ_END(ip, bitmap, rc, 1);
8265 if (!II_SUCCESS(rc)) {
8266 if (tmp)
8267 (void) nsc_free_buf(tmp);
8268
8269 _ii_error(ip, DSW_BMPOFFLINE);
8270 return (EIO);
8271 }
8272
8273 /* count each sd_vec's worth of data */
8274 buf_byte_len = FBA_SIZE(buf_fba_len);
8275 for (sd_vecp = tmp->sb_vec;
8276 buf_byte_len > 0 && bm_size > 0;
8277 sd_vecp++) {
8278 co_len = (bm_size > sd_vecp->sv_len) ?
8279 sd_vecp->sv_len : bm_size;
8280 cp = sd_vecp->sv_addr;
8281 for (i = k = 0; i < co_len; i++)
8282 for (j = (unsigned)*cp++; j; j &= j - 1)
8283 k++;
8284 *counter += k;
8285 bm_size -= co_len;
8286 buf_byte_len -= co_len;
8287 }
8288
8289
8290 (void) nsc_free_buf(tmp);
8291 }
8292
8293 return (0);
8294 }
8295
8296 /*
8297 * OR the bitmaps as part of a join operation
8298 */
8299 static int
_ii_ab_join_bmp(_ii_info_t * dest_ip,_ii_info_t * src_ip)8300 _ii_ab_join_bmp(_ii_info_t *dest_ip, _ii_info_t *src_ip)
8301 {
8302 int rc;
8303 nsc_size_t len;
8304 nsc_size_t size;
8305 nsc_buf_t *dest_tmp, *src_tmp;
8306 nsc_off_t src_fba_pos;
8307
8308 if ((src_ip->bi_flags & DSW_BMPOFFLINE) ||
8309 (dest_ip->bi_flags & DSW_BMPOFFLINE))
8310 return (EIO);
8311
8312 size = DSW_BM_FBA_LEN(src_ip->bi_size) + src_ip->bi_shdfba;
8313 for (src_fba_pos = src_ip->bi_shdfba; src_fba_pos < size;
8314 src_fba_pos += DSW_CBLK_FBA) {
8315 src_tmp = NULL;
8316 len = src_fba_pos + DSW_CBLK_FBA < size ?
8317 DSW_CBLK_FBA : size - src_fba_pos;
8318 II_READ_START(src_ip, bitmap);
8319 rc = nsc_alloc_buf(src_ip->bi_bmpfd, src_fba_pos, len,
8320 NSC_RDWRBUF, &src_tmp);
8321 II_READ_END(src_ip, bitmap, rc, len);
8322 if (!II_SUCCESS(rc)) {
8323 if (src_tmp)
8324 (void) nsc_free_buf(src_tmp);
8325
8326 _ii_error(src_ip, DSW_BMPOFFLINE);
8327 return (rc);
8328 }
8329
8330 dest_tmp = NULL;
8331 II_READ_START(dest_ip, bitmap);
8332 rc = nsc_alloc_buf(dest_ip->bi_bmpfd, src_fba_pos, len,
8333 NSC_RDWRBUF, &dest_tmp);
8334 II_READ_END(dest_ip, bitmap, rc, len);
8335 if (!II_SUCCESS(rc)) {
8336 (void) nsc_free_buf(src_tmp);
8337 if (dest_tmp)
8338 (void) nsc_free_buf(dest_tmp);
8339
8340 _ii_error(dest_ip, DSW_BMPOFFLINE);
8341 return (rc);
8342 }
8343 rc = _ii_nsc_or(src_tmp, dest_tmp, src_fba_pos, src_fba_pos,
8344 len);
8345 if (II_SUCCESS(rc)) {
8346 II_NSC_WRITE(dest_ip, bitmap, rc, dest_tmp,
8347 src_fba_pos, len, 0);
8348 }
8349
8350 (void) nsc_free_buf(src_tmp);
8351 (void) nsc_free_buf(dest_tmp);
8352 if (!II_SUCCESS(rc)) {
8353 _ii_error(dest_ip, DSW_BMPOFFLINE);
8354 return (rc);
8355 }
8356 }
8357
8358 dest_ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8359
8360 return (0);
8361
8362 }
8363
8364 static _ii_bmp_ops_t alloc_buf_bmp = {
8365 _ii_ab_co_bmp,
8366 _ii_ab_ci_bmp,
8367 _ii_ab_zerobm,
8368 _ii_ab_copybm,
8369 _ii_ab_orbm,
8370 _ii_ab_tst_shd_bit,
8371 _ii_ab_set_shd_bit,
8372 _ii_ab_tst_copy_bit,
8373 _ii_ab_set_copy_bit,
8374 _ii_ab_clr_copy_bits,
8375 _ii_ab_next_copy_bit,
8376 _ii_ab_fill_copy_bmp,
8377 _ii_ab_load_bmp,
8378 _ii_ab_save_bmp,
8379 _ii_ab_change_bmp,
8380 _ii_ab_cnt_bits,
8381 _ii_ab_join_bmp
8382 };
8383
8384
8385 /*
8386 * Copyout the bit map.
8387 */
8388 static int
_ii_km_co_bmp(_ii_info_t * ip,nsc_off_t bm_offset,unsigned char * user_bm,int user_bm_size)8389 _ii_km_co_bmp(_ii_info_t *ip, nsc_off_t bm_offset, unsigned char *user_bm,
8390 int user_bm_size)
8391 {
8392 int start_offset;
8393 int bm_size;
8394 size_t co_len;
8395 nsc_off_t last_fba;
8396
8397 /* First calculate the size of the shadow and copy bitmaps */
8398 co_len = DSW_BM_FBA_LEN(ip->bi_size);
8399 ASSERT((ip->bi_copyfba - ip->bi_shdfba) == co_len);
8400
8401 /* Are we in the ranges of the various bitmaps/indexes? */
8402 if (bm_offset < ip->bi_shdfba)
8403 return (EIO);
8404 else if (bm_offset < (last_fba = ip->bi_shdfba + co_len))
8405 /*EMPTY*/;
8406 else if (bm_offset < (last_fba = ip->bi_copyfba + co_len))
8407 /*EMPTY*/;
8408 else if ((ip->bi_flags & DSW_TREEMAP) &&
8409 (bm_offset < (last_fba = last_fba + (co_len * 32))))
8410 /*EMPTY*/;
8411 else return (EIO);
8412
8413 if (FBA_LEN(user_bm_size) > last_fba - bm_offset)
8414 return (EIO);
8415
8416 start_offset = FBA_SIZE(bm_offset);
8417 bm_size = FBA_SIZE(last_fba);
8418
8419 co_len = (user_bm_size > bm_size) ? bm_size : user_bm_size;
8420 if (copyout(ip->bi_bitmap + start_offset, user_bm, co_len))
8421 return (EFAULT);
8422
8423 return (0);
8424 }
8425
8426 /*
8427 * Copyin a bit map and or with differences bitmap.
8428 */
8429 static int
_ii_km_ci_bmp(_ii_info_t * ip,nsc_off_t bm_offset,unsigned char * user_bm,int user_bm_size)8430 _ii_km_ci_bmp(_ii_info_t *ip, nsc_off_t bm_offset, unsigned char *user_bm,
8431 int user_bm_size)
8432 {
8433 unsigned char *tmp_buf;
8434 unsigned char *dest;
8435 unsigned char *p;
8436 size_t tmp_size;
8437 int n;
8438 int start_offset;
8439 int bm_size;
8440 size_t ci_len;
8441 int rc = 0;
8442
8443 start_offset = FBA_SIZE(bm_offset);
8444 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
8445
8446 tmp_buf = NULL;
8447 tmp_size = FBA_SIZE(1);
8448
8449 tmp_buf = kmem_alloc(tmp_size, KM_SLEEP);
8450 start_offset = FBA_SIZE(bm_offset);
8451 dest = ip->bi_bitmap + start_offset;
8452 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
8453
8454 ci_len = (user_bm_size > bm_size) ? bm_size : user_bm_size;
8455 while (ci_len > 0) {
8456 n = (tmp_size > ci_len) ? ci_len : tmp_size;
8457 if (copyin(user_bm, tmp_buf, n)) {
8458 rc = EFAULT;
8459 break;
8460 }
8461 user_bm += n;
8462 for (p = tmp_buf; n--> 0; ci_len--)
8463 *dest++ |= *p++;
8464 }
8465 if (tmp_buf)
8466 kmem_free(tmp_buf, tmp_size);
8467
8468 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8469
8470 return (rc);
8471 }
8472
8473 /*
8474 * Completely zero the bit map.
8475 */
8476 static int
_ii_km_zerobm(_ii_info_t * ip)8477 _ii_km_zerobm(_ii_info_t *ip)
8478 {
8479 int start_offset = FBA_SIZE(ip->bi_shdfba);
8480 int len;
8481
8482 len = FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba);
8483 mutex_enter(&ip->bi_bmpmutex);
8484 bzero(ip->bi_bitmap+start_offset, len);
8485 mutex_exit(&ip->bi_bmpmutex);
8486
8487 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8488
8489 return (0);
8490 }
8491
8492
8493 /*
8494 * Copy shadow bitmap to copy bitmap
8495 */
8496 static int
_ii_km_copybm(_ii_info_t * ip)8497 _ii_km_copybm(_ii_info_t *ip)
8498 {
8499 int copy_offset, shd_offset;
8500 int len;
8501
8502 len = FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba);
8503 shd_offset = FBA_SIZE(ip->bi_shdfba);
8504 copy_offset = FBA_SIZE(ip->bi_copyfba);
8505 mutex_enter(&ip->bi_bmpmutex);
8506 bcopy(ip->bi_bitmap+shd_offset, ip->bi_bitmap+copy_offset, len);
8507 mutex_exit(&ip->bi_bmpmutex);
8508
8509 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8510
8511 return (0);
8512 }
8513
8514
8515 /*
8516 * Or the shadow bitmap in to the copy bitmap, clear the
8517 * shadow bitmap.
8518 */
8519 static int
_ii_km_orbm(_ii_info_t * ip)8520 _ii_km_orbm(_ii_info_t *ip)
8521 {
8522 unsigned char *copy, *shd;
8523 int copy_offset, shd_offset;
8524 int len;
8525
8526 len = FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba);
8527 shd_offset = FBA_SIZE(ip->bi_shdfba);
8528 copy_offset = FBA_SIZE(ip->bi_copyfba);
8529 shd = ip->bi_bitmap + shd_offset;
8530 copy = ip->bi_bitmap + copy_offset;
8531
8532 mutex_enter(&ip->bi_bmpmutex);
8533 while (len-- > 0)
8534 *copy++ |= *shd++;
8535 mutex_exit(&ip->bi_bmpmutex);
8536
8537 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8538
8539 return (0);
8540 }
8541
8542 /*
8543 * _ii_km_tst_shd_bit
8544 * Determine if a chunk has been copied to the shadow device
8545 *
8546 * Calling/Exit State:
8547 * Returns 1 if the modified bit has been set for the shadow device,
8548 * otherwise returns 0.
8549 */
8550
8551 static int
_ii_km_tst_shd_bit(_ii_info_t * ip,chunkid_t chunk)8552 _ii_km_tst_shd_bit(_ii_info_t *ip, chunkid_t chunk)
8553 {
8554 unsigned char *bmp;
8555 int bmp_offset;
8556 int rc;
8557
8558 bmp_offset = FBA_SIZE(ip->bi_shdfba);
8559 bmp = ip->bi_bitmap + bmp_offset;
8560
8561 mutex_enter(&ip->bi_bmpmutex);
8562 rc = DSW_BIT_ISSET(bmp[chunk/DSW_BITS], chunk%DSW_BITS);
8563 mutex_exit(&ip->bi_bmpmutex);
8564
8565 return (rc);
8566 }
8567
8568
8569 /*
8570 * _ii_km_set_shd_bit
8571 * Records that a chunk has been copied to the shadow device
8572 */
8573
8574 static int
_ii_km_set_shd_bit(_ii_info_t * ip,chunkid_t chunk)8575 _ii_km_set_shd_bit(_ii_info_t *ip, chunkid_t chunk)
8576 {
8577 unsigned char *bmp;
8578 int bmp_offset;
8579
8580 bmp_offset = FBA_SIZE(ip->bi_shdfba);
8581 bmp = ip->bi_bitmap + bmp_offset;
8582
8583 mutex_enter(&ip->bi_bmpmutex);
8584 if (DSW_BIT_ISSET(bmp[chunk/DSW_BITS], chunk%DSW_BITS) == 0) {
8585 DSW_BIT_SET(bmp[chunk/DSW_BITS], chunk%DSW_BITS);
8586 if ((ip->bi_state & DSW_CNTSHDBITS) == 0)
8587 ip->bi_shdbits++;
8588 }
8589 mutex_exit(&ip->bi_bmpmutex);
8590
8591 return (0);
8592 }
8593
8594 /*
8595 * _ii_km_tst_copy_bit
8596 * Determine if a chunk needs to be copied during updates.
8597 *
8598 * Calling/Exit State:
8599 * Returns 1 if the copy bit for the chunk is set,
8600 * otherwise returns 0
8601 */
8602
8603 static int
_ii_km_tst_copy_bit(_ii_info_t * ip,chunkid_t chunk)8604 _ii_km_tst_copy_bit(_ii_info_t *ip, chunkid_t chunk)
8605 {
8606 unsigned char *bmp;
8607 int bmp_offset;
8608 int rc;
8609
8610 bmp_offset = FBA_SIZE(ip->bi_copyfba);
8611 bmp = ip->bi_bitmap + bmp_offset;
8612
8613 mutex_enter(&ip->bi_bmpmutex);
8614 rc = DSW_BIT_ISSET(bmp[chunk/DSW_BITS], chunk%DSW_BITS);
8615 mutex_exit(&ip->bi_bmpmutex);
8616
8617 return (rc);
8618 }
8619
8620
8621 /*
8622 * _ii_km_set_copy_bit
8623 * Records that a chunk has been copied to the shadow device
8624 */
8625
8626 static int
_ii_km_set_copy_bit(_ii_info_t * ip,chunkid_t chunk)8627 _ii_km_set_copy_bit(_ii_info_t *ip, chunkid_t chunk)
8628 {
8629 unsigned char *bmp;
8630 int bmp_offset;
8631
8632 bmp_offset = FBA_SIZE(ip->bi_copyfba);
8633 bmp = ip->bi_bitmap + bmp_offset;
8634
8635 mutex_enter(&ip->bi_bmpmutex);
8636 if (DSW_BIT_ISSET(bmp[chunk/DSW_BITS], chunk%DSW_BITS) == 0) {
8637 DSW_BIT_SET(bmp[chunk/DSW_BITS], chunk%DSW_BITS);
8638 if ((ip->bi_state & DSW_CNTCPYBITS) == 0)
8639 ip->bi_copybits++;
8640 }
8641 mutex_exit(&ip->bi_bmpmutex);
8642
8643 return (0);
8644 }
8645
8646
8647 /*
8648 * _ii_km_clr_copy_bits
8649 * Records that a chunk has been cleared on the shadow device
8650 */
8651
8652 static int
_ii_km_clr_copy_bits(_ii_info_t * ip,chunkid_t chunk,int nchunks)8653 _ii_km_clr_copy_bits(_ii_info_t *ip, chunkid_t chunk, int nchunks)
8654 {
8655 unsigned char *bmp;
8656 int bmp_offset;
8657
8658 bmp_offset = FBA_SIZE(ip->bi_copyfba);
8659 bmp = ip->bi_bitmap + bmp_offset;
8660
8661 mutex_enter(&ip->bi_bmpmutex);
8662 for (; nchunks-- > 0; chunk++) {
8663 DSW_BIT_CLR(bmp[chunk/DSW_BITS], chunk%DSW_BITS);
8664 if (ip->bi_copybits > 0)
8665 ip->bi_copybits--;
8666 }
8667 mutex_exit(&ip->bi_bmpmutex);
8668
8669 return (0);
8670 }
8671
8672 /*
8673 * _ii_km_fill_copy_bmp
8674 * Fills the copy bitmap with 1's.
8675 */
8676
8677 static int
_ii_km_fill_copy_bmp(_ii_info_t * ip)8678 _ii_km_fill_copy_bmp(_ii_info_t *ip)
8679 {
8680 int len;
8681 unsigned char *bmp;
8682 int bmp_offset;
8683
8684 bmp_offset = FBA_SIZE(ip->bi_copyfba);
8685 bmp = ip->bi_bitmap + bmp_offset;
8686
8687 len = FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba);
8688
8689 mutex_enter(&ip->bi_bmpmutex);
8690 while (len-- > 0)
8691 *bmp++ = (unsigned char)0xff;
8692 mutex_exit(&ip->bi_bmpmutex);
8693
8694 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8695
8696 return (0);
8697 }
8698
8699 /*
8700 * _ii_km_load_bmp
8701 * Load bitmap from persistent storage.
8702 */
8703
8704 static int
_ii_km_load_bmp(_ii_info_t * ip,int flag)8705 _ii_km_load_bmp(_ii_info_t *ip, int flag)
8706 {
8707 nsc_off_t bmp_offset;
8708 nsc_size_t bitmap_size;
8709 int rc;
8710
8711 if (ip->bi_flags & DSW_BMPOFFLINE)
8712 return (EIO);
8713
8714 if (ip->bi_bitmap == NULL) {
8715 bitmap_size = FBA_SIZE(2 * (ip->bi_copyfba - ip->bi_shdfba) +
8716 ip->bi_shdfba);
8717 ip->bi_bitmap = nsc_kmem_zalloc(bitmap_size, KM_SLEEP,
8718 _ii_local_mem);
8719 }
8720 if (flag)
8721 return (0); /* just create an empty bitmap */
8722 bmp_offset = FBA_SIZE(ip->bi_shdfba);
8723 rc = _ii_nsc_io(ip, KS_BMP, ip->bi_bmpfd, NSC_RDBUF, ip->bi_shdfba,
8724 ip->bi_bitmap + bmp_offset,
8725 2 * FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba));
8726 if (!II_SUCCESS(rc))
8727 _ii_error(ip, DSW_BMPOFFLINE);
8728
8729 ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8730
8731 return (rc);
8732 }
8733
8734 /*
8735 * _ii_km_save_bmp
8736 * Save bitmap to persistent storage.
8737 */
8738
8739 static int
_ii_km_save_bmp(_ii_info_t * ip,int flag)8740 _ii_km_save_bmp(_ii_info_t *ip, int flag)
8741 {
8742 int bmp_offset;
8743 int bitmap_size;
8744 int rc;
8745
8746 bmp_offset = FBA_SIZE(ip->bi_shdfba);
8747 if (ip->bi_flags & DSW_BMPOFFLINE)
8748 rc = EIO;
8749 else {
8750 rc = _ii_nsc_io(ip, KS_BMP, ip->bi_bmpfd, NSC_WRBUF,
8751 ip->bi_shdfba, ip->bi_bitmap + bmp_offset,
8752 2 * FBA_SIZE(ip->bi_copyfba - ip->bi_shdfba));
8753 if (!II_SUCCESS(rc))
8754 _ii_error(ip, DSW_BMPOFFLINE);
8755 }
8756
8757 if (flag && ip->bi_bitmap) { /* dispose of bitmap memory */
8758 bitmap_size = FBA_SIZE(2 * (ip->bi_copyfba - ip->bi_shdfba) +
8759 ip->bi_shdfba);
8760 nsc_kmem_free(ip->bi_bitmap, bitmap_size);
8761 ip->bi_bitmap = NULL;
8762 }
8763
8764 return (rc);
8765 }
8766
8767 /*
8768 * _ii_km_next_copy_bit
8769 * Find next set copy bit.
8770 *
8771 * Returns the next bits set in the copy bitmap, with the corresponding chunks
8772 * locked. Used to cut down on the number of times the bmpmutex is acquired.
8773 */
8774
8775 static chunkid_t
_ii_km_next_copy_bit(_ii_info_t * ip,chunkid_t chunk,chunkid_t maxchunk,int want,int * got)8776 _ii_km_next_copy_bit(_ii_info_t *ip, chunkid_t chunk, chunkid_t maxchunk,
8777 int want, int *got)
8778 {
8779 unsigned char *bmp;
8780 int bmp_offset;
8781 int nextchunk;
8782
8783 *got = 0;
8784 bmp_offset = FBA_SIZE(ip->bi_copyfba);
8785 bmp = ip->bi_bitmap + bmp_offset;
8786
8787 mutex_enter(&ip->bi_bmpmutex);
8788 for (; chunk < maxchunk; chunk++) {
8789 if (DSW_BIT_ISSET(bmp[chunk/DSW_BITS], chunk%DSW_BITS)) {
8790 /*
8791 * trylock won't sleep so can use while
8792 * holding bi_bmpmutex.
8793 */
8794 if (!_ii_trylock_chunk(ip, chunk)) {
8795 mutex_exit(&ip->bi_bmpmutex);
8796 _ii_lock_chunk(ip, chunk);
8797 *got = 1;
8798
8799 DTRACE_PROBE(_ii_km_next_copy_bit);
8800
8801 return (chunk);
8802 }
8803 *got = 1;
8804 for (nextchunk = chunk + 1;
8805 *got < want && nextchunk < maxchunk; nextchunk++) {
8806 if (!DSW_BIT_ISSET(bmp[nextchunk/DSW_BITS],
8807 nextchunk%DSW_BITS))
8808 break;
8809 if (_ii_trylock_chunk(ip, nextchunk))
8810 (*got)++;
8811 else
8812 break;
8813 }
8814 mutex_exit(&ip->bi_bmpmutex);
8815
8816 DTRACE_PROBE(_ii_km_next_copy_bit);
8817 return (chunk);
8818 }
8819 }
8820 mutex_exit(&ip->bi_bmpmutex);
8821
8822 return (maxchunk + 1);
8823 }
8824
8825 /*
8826 * _ii_km_change_bmp
8827 * copy change bitmap to memory
8828 */
8829
8830 static int
_ii_km_change_bmp(_ii_info_t * ip,unsigned char * ptr)8831 _ii_km_change_bmp(_ii_info_t *ip, unsigned char *ptr)
8832 /* ARGSUSED */
8833 {
8834 int start_offset;
8835 int bm_size;
8836 unsigned char *q;
8837
8838 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(ip->bi_size));
8839
8840 start_offset = FBA_SIZE(ip->bi_shdfba);
8841 bcopy(ip->bi_bitmap + start_offset, ptr, bm_size);
8842
8843 start_offset = FBA_SIZE(ip->bi_copyfba);
8844 q = ip->bi_bitmap + start_offset;
8845 while (bm_size-- > 0)
8846 *ptr |= *q;
8847
8848 return (0);
8849 }
8850
8851 /*
8852 * Count bits set in the bit map.
8853 */
8854 static int
_ii_km_cnt_bits(_ii_info_t * ip,nsc_off_t bm_offset,nsc_size_t * counter,int bm_size)8855 _ii_km_cnt_bits(_ii_info_t *ip, nsc_off_t bm_offset, nsc_size_t *counter,
8856 int bm_size)
8857 {
8858 int start_offset;
8859 int i;
8860 nsc_size_t j, k;
8861 unsigned char *cp;
8862
8863 start_offset = FBA_SIZE(bm_offset);
8864
8865 cp = ip->bi_bitmap + start_offset;
8866 for (i = k = 0; i < bm_size; i++)
8867 for (j = (unsigned)*cp++; j; j &= j - 1)
8868 k++;
8869 *counter = k;
8870
8871 return (0);
8872 }
8873
8874 /*
8875 * Or the shadow bitmap in to the copy bitmap, clear the
8876 * shadow bitmap.
8877 */
8878 static int
_ii_km_join_bmp(_ii_info_t * dest_ip,_ii_info_t * src_ip)8879 _ii_km_join_bmp(_ii_info_t *dest_ip, _ii_info_t *src_ip)
8880 {
8881 uchar_t *dest, *src;
8882 nsc_size_t bm_size;
8883
8884 dest = dest_ip->bi_bitmap + FBA_SIZE(dest_ip->bi_shdfba);
8885 src = src_ip->bi_bitmap + FBA_SIZE(src_ip->bi_shdfba);
8886 bm_size = FBA_SIZE(DSW_BM_FBA_LEN(dest_ip->bi_size));
8887
8888 while (bm_size-- > 0)
8889 *dest++ |= *src++;
8890
8891 dest_ip->bi_state |= (DSW_CNTSHDBITS|DSW_CNTCPYBITS);
8892
8893 return (0);
8894 }
8895
8896 static _ii_bmp_ops_t kmem_buf_bmp = {
8897 _ii_km_co_bmp,
8898 _ii_km_ci_bmp,
8899 _ii_km_zerobm,
8900 _ii_km_copybm,
8901 _ii_km_orbm,
8902 _ii_km_tst_shd_bit,
8903 _ii_km_set_shd_bit,
8904 _ii_km_tst_copy_bit,
8905 _ii_km_set_copy_bit,
8906 _ii_km_clr_copy_bits,
8907 _ii_km_next_copy_bit,
8908 _ii_km_fill_copy_bmp,
8909 _ii_km_load_bmp,
8910 _ii_km_save_bmp,
8911 _ii_km_change_bmp,
8912 _ii_km_cnt_bits,
8913 _ii_km_join_bmp
8914 };
8915
8916
8917 static int
ii_read_volume(_ii_info_t * ip,int mst_src,nsc_buf_t * srcbuf,nsc_buf_t * dstbuf,chunkid_t chunk_num,nsc_off_t fba,nsc_size_t len)8918 ii_read_volume(_ii_info_t *ip, int mst_src, nsc_buf_t *srcbuf,
8919 nsc_buf_t *dstbuf, chunkid_t chunk_num, nsc_off_t fba, nsc_size_t len)
8920 {
8921 int rc;
8922 nsc_buf_t *tmp;
8923 nsc_off_t mapped_fba;
8924 chunkid_t mapped_chunk;
8925 int overflow;
8926
8927 if (mst_src || (ip->bi_flags&DSW_TREEMAP) == 0) {
8928 /* simple read with optional copy */
8929 if (mst_src) {
8930 II_NSC_READ(ip, master, rc, srcbuf, fba, len, 0);
8931 } else {
8932 II_NSC_READ(ip, shadow, rc, srcbuf, fba, len, 0);
8933 }
8934 if (dstbuf && II_SUCCESS(rc)) {
8935 rc = nsc_copy(srcbuf, dstbuf, fba, fba, len);
8936 }
8937
8938 return (rc);
8939 }
8940 /* read from mapped shadow into final buffer */
8941 mapped_chunk = ii_tsearch(ip, chunk_num);
8942 if (mapped_chunk == II_NULLNODE)
8943 return (EIO);
8944 overflow = II_ISOVERFLOW(mapped_chunk);
8945 if (overflow)
8946 mapped_chunk = II_2OVERFLOW(mapped_chunk);
8947 /* convert chunk number from tsearch into final fba */
8948 mapped_fba = DSW_CHK2FBA(mapped_chunk) + (fba % DSW_SIZE);
8949 tmp = NULL;
8950 if (overflow) {
8951 (void) nsc_reserve(OVRFD(ip), NSC_MULTI);
8952 II_READ_START(ip, overflow);
8953 rc = nsc_alloc_buf(OVRFD(ip), mapped_fba, len, NSC_RDBUF, &tmp);
8954 II_READ_END(ip, overflow, rc, len);
8955 } else {
8956 II_READ_START(ip, shadow);
8957 rc = nsc_alloc_buf(SHDFD(ip), mapped_fba, len, NSC_RDBUF, &tmp);
8958 II_READ_END(ip, shadow, rc, len);
8959 }
8960 if (II_SUCCESS(rc)) {
8961 if (dstbuf == NULL)
8962 dstbuf = srcbuf;
8963 rc = nsc_copy(tmp, dstbuf, mapped_fba, fba, len);
8964 (void) nsc_free_buf(tmp);
8965 }
8966 if (overflow)
8967 nsc_release(OVRFD(ip));
8968
8969 return (rc);
8970 }
8971
8972 /*
8973 * _ii_fill_buf
8974 * Read data from the required device
8975 *
8976 * Calling/Exit State:
8977 * Returns 0 if the data was read successfully, otherwise
8978 * error code.
8979 *
8980 * Description:
8981 * Reads the data from fba_pos for length fba_len from the
8982 * required device. This data may be a mix of data from the master
8983 * device and the shadow device, depending on the state of the
8984 * bitmaps.
8985 */
8986
8987 static int
_ii_fill_buf(ii_fd_t * bfd,nsc_off_t fba_pos,nsc_size_t fba_len,int flag,nsc_buf_t ** handle,nsc_buf_t ** handle2)8988 _ii_fill_buf(ii_fd_t *bfd, nsc_off_t fba_pos, nsc_size_t fba_len, int flag,
8989 nsc_buf_t **handle, nsc_buf_t **handle2)
8990 {
8991 _ii_info_t *ip = bfd->ii_info;
8992 _ii_info_t *xip;
8993 int second_shd = 0;
8994 nsc_off_t temp_fba;
8995 nsc_size_t temp_len;
8996 nsc_size_t bmp_len;
8997 chunkid_t chunk_num;
8998 int rc;
8999 int fill_from_pair;
9000 int rtype = SHDR|BMP;
9001 nsc_buf_t *second_buf = NULL;
9002
9003 if (flag&NSC_RDAHEAD)
9004 return (NSC_DONE);
9005
9006 chunk_num = fba_pos / DSW_SIZE;
9007 temp_fba = fba_pos;
9008 temp_len = fba_len;
9009
9010 /*
9011 * If the master is being updated from a shadow we need to fill from
9012 * the correct shadow volume.
9013 */
9014 if (NSHADOWS(ip) && bfd->ii_shd == 0) {
9015 for (xip = ip->bi_head; xip; xip = xip->bi_sibling) {
9016 if (xip == ip)
9017 continue;
9018 if (xip->bi_flags &DSW_COPYINGS) {
9019 second_shd = 1;
9020 ip = xip;
9021 if ((rc = _ii_rsrv_devs(ip, rtype,
9022 II_INTERNAL)) != 0)
9023 return (EIO);
9024 rc = nsc_alloc_buf(SHDFD(ip), fba_pos, fba_len,
9025 (flag&NSC_RDAHEAD)|NSC_MIXED, &second_buf);
9026 if (!II_SUCCESS(rc)) {
9027 rc = EIO;
9028 goto out;
9029 }
9030 handle2 = &second_buf;
9031 break;
9032 }
9033 }
9034 }
9035
9036 while (temp_len > 0) {
9037 if ((temp_fba + temp_len) > DSW_CHK2FBA(chunk_num + 1)) {
9038 bmp_len = DSW_CHK2FBA(chunk_num + 1) - temp_fba;
9039 temp_len -= bmp_len;
9040 } else {
9041 bmp_len = temp_len;
9042 temp_len = 0;
9043 }
9044
9045 fill_from_pair = 0;
9046
9047 if ((ip->bi_flags & DSW_COPYINGM) == DSW_COPYINGM) {
9048 rc = II_TST_COPY_BIT(ip, chunk_num);
9049 /* Treat a failed bitmap volume as a clear bit */
9050 if (rc > 0) {
9051 /* Copy bit set */
9052 if (bfd->ii_shd) {
9053 if (*handle2)
9054 fill_from_pair = 1;
9055 else {
9056 rc = EIO;
9057 goto out;
9058 }
9059 }
9060 }
9061 }
9062 if ((ip->bi_flags & DSW_COPYINGS) == DSW_COPYINGS) {
9063 rc = II_TST_COPY_BIT(ip, chunk_num);
9064 /* Treat a failed bitmap volume as a clear bit */
9065 if (rc > 0) {
9066 /* Copy bit set */
9067 if (bfd->ii_shd == 0) {
9068 if (*handle2 ||
9069 (ip->bi_flags&DSW_TREEMAP))
9070 fill_from_pair = 1;
9071 else {
9072 rc = EIO;
9073 goto out;
9074 }
9075 }
9076 }
9077 }
9078 if (((ip->bi_flags & DSW_GOLDEN) == 0) && bfd->ii_shd) {
9079 /* Dependent shadow read */
9080
9081 rc = II_TST_SHD_BIT(ip, chunk_num);
9082 if (rc < 0) {
9083 rc = EIO;
9084 goto out;
9085 }
9086 if (rc == 0) {
9087 /* Shadow bit clear */
9088 if (*handle2)
9089 fill_from_pair = 1;
9090 else {
9091 rc = EIO;
9092 goto out;
9093 }
9094 }
9095 }
9096
9097 if (fill_from_pair) {
9098 /* it matters now */
9099 if (ip->bi_flags & (DSW_MSTOFFLINE | DSW_SHDOFFLINE)) {
9100 rc = EIO;
9101 goto out;
9102 }
9103 if (*handle2 == NULL &&
9104 (ip->bi_flags&DSW_TREEMAP) == 0) {
9105 rc = EIO;
9106 goto out;
9107 }
9108 rc = ii_read_volume(ip, bfd->ii_shd,
9109 *handle2, *handle, chunk_num, temp_fba, bmp_len);
9110 if (!II_SUCCESS(rc)) {
9111 _ii_error(ip, DSW_MSTOFFLINE);
9112 _ii_error(ip, DSW_SHDOFFLINE);
9113 goto out;
9114 }
9115 } else {
9116 if (bfd->ii_shd && (ip->bi_flags & DSW_SHDOFFLINE)) {
9117 rc = EIO;
9118 goto out;
9119 }
9120 if ((bfd->ii_shd == 0) &&
9121 (ip->bi_flags & DSW_MSTOFFLINE)) {
9122 rc = EIO;
9123 goto out;
9124 }
9125 rc = ii_read_volume(ip, !(bfd->ii_shd), *handle, NULL,
9126 chunk_num, temp_fba, bmp_len);
9127 if (!II_SUCCESS(rc)) {
9128 if (bfd->ii_shd)
9129 _ii_error(ip, DSW_SHDOFFLINE);
9130 else
9131 _ii_error(ip, DSW_MSTOFFLINE);
9132 goto out;
9133 }
9134 }
9135
9136 temp_fba += bmp_len;
9137 chunk_num++;
9138 }
9139
9140 rc = 0;
9141 out:
9142 if (second_buf)
9143 (void) nsc_free_buf(second_buf);
9144 if (second_shd)
9145 _ii_rlse_devs(ip, rtype);
9146
9147 return (rc);
9148 }
9149
9150
9151 /*
9152 * _ii_shadow_write
9153 * Perform any copy on write required by a write buffer request
9154 *
9155 * Calling/Exit State:
9156 * Returns 0 on success, otherwise error code.
9157 *
9158 */
9159
9160 static int
_ii_shadow_write(ii_fd_t * bfd,nsc_off_t pos,nsc_size_t len)9161 _ii_shadow_write(ii_fd_t *bfd, nsc_off_t pos, nsc_size_t len)
9162 {
9163 _ii_info_t *ip = bfd->ii_info;
9164 chunkid_t chunk_num;
9165 int rc;
9166 int flag;
9167 int hanging;
9168
9169 DTRACE_PROBE2(_ii_shadow_write_start, nsc_off_t, pos, nsc_size_t, len);
9170
9171 /* fail immediately if config DB is unavailable */
9172 if ((ip->bi_flags & DSW_CFGOFFLINE) == DSW_CFGOFFLINE) {
9173 return (EIO);
9174 }
9175
9176 chunk_num = pos / DSW_SIZE;
9177
9178 if (bfd->ii_shd)
9179 flag = 0; /* To shadow */
9180 else
9181 flag = CV_SHD2MST; /* To master */
9182
9183 mutex_enter(&ip->bi_mutex);
9184 ip->bi_shdref++;
9185 mutex_exit(&ip->bi_mutex);
9186 hanging = (ip->bi_flags&DSW_HANGING) != 0;
9187
9188 for (; (chunk_num >= 0) &&
9189 DSW_CHK2FBA(chunk_num) < (pos + len); chunk_num++) {
9190
9191 if (!hanging)
9192 _ii_lock_chunk(ip, chunk_num);
9193 rc = _ii_copy_on_write(ip, flag, chunk_num, 1);
9194
9195 /*
9196 * Set the shadow bit when a small shadow has overflowed so
9197 * that ii_read_volume can return an error if an attempt is
9198 * made to read that chunk.
9199 */
9200 if (!hanging) {
9201 if (rc == 0 ||
9202 (rc == EIO && (ip->bi_flags&DSW_OVERFLOW) != 0))
9203 (void) II_SET_SHD_BIT(ip, chunk_num);
9204 _ii_unlock_chunk(ip, chunk_num);
9205 }
9206 }
9207
9208 mutex_enter(&ip->bi_mutex);
9209 ip->bi_shdref--;
9210 if (ip->bi_state & DSW_CLOSING) {
9211 if (total_ref(ip) == 0) {
9212 cv_signal(&ip->bi_closingcv);
9213 }
9214 }
9215 mutex_exit(&ip->bi_mutex);
9216
9217 /* did the bitmap fail during this process? */
9218 return (ip->bi_flags & DSW_CFGOFFLINE? EIO : 0);
9219 }
9220
9221 /*
9222 * _ii_alloc_buf
9223 * Allocate a buffer of data
9224 *
9225 * Calling/Exit State:
9226 * Returns 0 for success, < 0 for async I/O, > 0 is an error code.
9227 *
9228 * Description:
9229 * For a write buffer, calls dsw_shadow_write to perform any necessary
9230 * copy on write operations, then allocates the real buffers from the
9231 * underlying devices.
9232 * For a read buffer, allocates the real buffers from the underlying
9233 * devices, then calls _ii_fill_buf to fill the required buffer.
9234 * For a buffer that is neither read nor write, just allocate the
9235 * buffers so that a _ii_fill_buf can be done later by _ii_read.
9236 */
9237
9238 static int
_ii_alloc_buf(ii_fd_t * bfd,nsc_off_t pos,nsc_size_t len,int flag,ii_buf_t ** ptr)9239 _ii_alloc_buf(ii_fd_t *bfd, nsc_off_t pos, nsc_size_t len, int flag,
9240 ii_buf_t **ptr)
9241 {
9242 _ii_info_t *ip = bfd->ii_info;
9243 ii_buf_t *h;
9244 int raw = II_RAW(bfd);
9245 int rc = 0;
9246 int ioflag;
9247 int fbuf = 0, fbuf2 = 0, abuf = 0;
9248 int rw_ent = 0;
9249
9250 if (bfd->ii_bmp) {
9251 DTRACE_PROBE(_ii_alloc_buf_end);
9252 /* any I/O to the bitmap device is barred */
9253 return (EIO);
9254 }
9255
9256 if (len == 0) {
9257 DTRACE_PROBE(_ii_alloc_buf_end);
9258 return (EINVAL);
9259 }
9260
9261 /* Bounds checking */
9262 if (pos + len > ip->bi_size) {
9263 if (ii_debug > 1)
9264 cmn_err(CE_NOTE,
9265 "!ii: Attempt to access beyond end of ii volume");
9266 DTRACE_PROBE(_ii_alloc_buf_end);
9267 return (EIO);
9268 }
9269
9270 h = *ptr;
9271 if (h == NULL) {
9272 h = (ii_buf_t *)_ii_alloc_handle(NULL, NULL, NULL, bfd);
9273 if (h == NULL) {
9274 DTRACE_PROBE(_ii_alloc_buf_end);
9275 return (ENOMEM);
9276 }
9277 }
9278
9279 /*
9280 * Temporary nsc_reserve of bitmap and other device.
9281 * This device has already been reserved by the preceding _ii_attach.
9282 * Corresponding nsc_release is in _ii_free_buf.
9283 */
9284
9285 h->ii_rsrv = BMP | (raw ? (bfd->ii_shd ? MSTR : SHDR)
9286 : (bfd->ii_shd ? MST : SHD));
9287
9288 if (!bfd->ii_shd)
9289 ip = ip->bi_master;
9290
9291 rw_enter(&ip->bi_linkrw, RW_READER);
9292 rw_ent = 1;
9293 if (ip->bi_shdfd == NULL || (ip->bi_flags & DSW_SHDEXPORT) ==
9294 DSW_SHDEXPORT)
9295 h->ii_rsrv &= ~(SHD|SHDR);
9296 if ((rc = _ii_rsrv_devs(ip, h->ii_rsrv, II_EXTERNAL)) != 0) {
9297 rw_exit(&ip->bi_linkrw);
9298 rw_ent = 0;
9299 h->ii_rsrv = NULL;
9300 goto error;
9301 }
9302
9303 if (flag & NSC_WRBUF) {
9304 rc = _ii_shadow_write(bfd, pos, len);
9305 if (!II_SUCCESS(rc))
9306 goto error;
9307 }
9308
9309 if (!(flag & NSC_RDAHEAD))
9310 ioflag = flag & ~(NSC_RDBUF);
9311 else
9312 ioflag = flag;
9313
9314 if (bfd->ii_shd) {
9315 /*
9316 * SHADOW
9317 */
9318
9319 if (ip->bi_flags & DSW_SHDEXPORT) {
9320 rc = EIO;
9321 goto error;
9322 }
9323 /*
9324 * The master device buffer has to be allocated first
9325 * so that deadlocks are avoided.
9326 */
9327 DTRACE_PROBE(AllocBufFor_SHADOW);
9328
9329 if ((ip->bi_flags & (DSW_MSTOFFLINE|DSW_SHDIMPORT)) == 0) {
9330 rc = nsc_alloc_buf(MSTFD(ip), pos, len,
9331 (flag&NSC_RDAHEAD)|NSC_MIXED, &h->ii_bufp2);
9332 if (!II_SUCCESS(rc)) {
9333 if (ii_debug > 2)
9334 cmn_err(CE_WARN, "!ii: "
9335 "Join/write-S race detected\n");
9336 if (h->ii_bufp2)
9337 (void) nsc_free_buf(h->ii_bufp2);
9338 h->ii_bufp2 = NULL;
9339 /*
9340 * Carry on as this will not matter if
9341 * _ii_fill_buf is not called, or if
9342 * it is called but doesn't need to read this
9343 * volume.
9344 */
9345 rc = 0;
9346 }
9347 fbuf2 = 1;
9348 }
9349
9350 if (ip->bi_flags & DSW_SHDOFFLINE) {
9351 rc = EIO;
9352 goto error;
9353 }
9354 if ((ip->bi_flags)&DSW_TREEMAP) {
9355 rc = nsc_alloc_abuf(pos, len, 0, &h->ii_abufp);
9356 if (!II_SUCCESS(rc)) {
9357 _ii_error(ip, DSW_SHDOFFLINE);
9358 goto error;
9359 }
9360 abuf = 1;
9361 } else {
9362 II_ALLOC_BUF(ip, shadow, rc, SHDFD(ip), pos, len,
9363 ioflag, &h->ii_bufp); /* do not read yet */
9364 if (!II_SUCCESS(rc)) {
9365 _ii_error(ip, DSW_SHDOFFLINE);
9366 goto error;
9367 }
9368 fbuf = 1;
9369 }
9370 } else {
9371 /*
9372 * MASTER
9373 */
9374
9375 /*
9376 * The master device buffer has to be allocated first
9377 * so that deadlocks are avoided.
9378 */
9379
9380 if (ip->bi_flags & (DSW_MSTOFFLINE|DSW_SHDIMPORT)) {
9381 rc = EIO;
9382 goto error;
9383 }
9384
9385 DTRACE_PROBE(AllocBufFor_MASTER);
9386
9387 II_ALLOC_BUF(ip, master, rc, MSTFD(ip), pos, len, ioflag,
9388 &h->ii_bufp); /* do not read yet */
9389 if (!II_SUCCESS(rc)) {
9390 _ii_error(ip, DSW_MSTOFFLINE);
9391 goto error;
9392 }
9393 fbuf = 1;
9394
9395 /*
9396 * If shadow FD and (dependent set OR copying) and
9397 * not (compact dependent && shadow offline && shadow exported)
9398 */
9399 if ((ip->bi_shdfd) &&
9400 ((ip->bi_flags & DSW_COPYINGP) ||
9401 (!(ip->bi_flags & DSW_GOLDEN))) &&
9402 (!(ip->bi_flags &
9403 (DSW_TREEMAP|DSW_SHDOFFLINE|DSW_SHDEXPORT)))) {
9404 rc = nsc_alloc_buf(SHDFD(ip), pos, len,
9405 (flag&NSC_RDAHEAD)|NSC_MIXED, &h->ii_bufp2);
9406 if (!II_SUCCESS(rc)) {
9407 if (ii_debug > 2)
9408 cmn_err(CE_WARN, "!ii: "
9409 "Join/write-M race detected\n");
9410 if (h->ii_bufp2)
9411 (void) nsc_free_buf(h->ii_bufp2);
9412 h->ii_bufp2 = NULL;
9413 /*
9414 * Carry on as this will not matter if
9415 * _ii_fill_buf is not called, or if
9416 * it is called but doesn't need to read this
9417 * volume.
9418 */
9419 rc = 0;
9420 }
9421 fbuf2 = 1;
9422 }
9423 }
9424
9425 if (flag & NSC_RDBUF)
9426 rc = _ii_fill_buf(bfd, pos, len, flag,
9427 h->ii_abufp ? &h->ii_abufp : &h->ii_bufp, &h->ii_bufp2);
9428
9429 error:
9430 if (II_SUCCESS(rc)) {
9431 h->ii_bufh.sb_vec = h->ii_abufp ? h->ii_abufp->sb_vec :
9432 h->ii_bufp->sb_vec;
9433 h->ii_bufh.sb_error = 0;
9434 h->ii_bufh.sb_flag |= flag;
9435 h->ii_bufh.sb_pos = pos;
9436 h->ii_bufh.sb_len = len;
9437 } else {
9438 h->ii_bufh.sb_error = rc;
9439 if (h->ii_bufp2 && fbuf2) {
9440 (void) nsc_free_buf(h->ii_bufp2);
9441 h->ii_bufp2 = NULL;
9442 }
9443 if (h->ii_bufp && fbuf) {
9444 (void) nsc_free_buf(h->ii_bufp);
9445 h->ii_bufp = NULL;
9446 }
9447 if (h->ii_abufp && abuf) {
9448 (void) nsc_free_buf(h->ii_abufp);
9449 h->ii_abufp = NULL;
9450 }
9451
9452 if (h->ii_rsrv) {
9453 /*
9454 * Release temporary reserve - reserved above.
9455 */
9456 _ii_rlse_devs(ip, h->ii_rsrv);
9457 h->ii_rsrv = NULL;
9458 }
9459 if (rw_ent)
9460 rw_exit(&ip->bi_linkrw);
9461 }
9462
9463 return (rc);
9464 }
9465
9466
9467 /*
9468 * _ii_free_buf
9469 */
9470
9471 static int
_ii_free_buf(ii_buf_t * h)9472 _ii_free_buf(ii_buf_t *h)
9473 {
9474 ii_fd_t *bfd;
9475 int rsrv;
9476 int rc;
9477
9478 if (h->ii_abufp == NULL) {
9479 rc = nsc_free_buf(h->ii_bufp);
9480 } else {
9481 rc = nsc_free_buf(h->ii_abufp);
9482 h->ii_abufp = NULL;
9483 }
9484 if (!II_SUCCESS(rc))
9485 return (rc);
9486 if (h->ii_bufp2) {
9487 rc = nsc_free_buf(h->ii_bufp2);
9488 h->ii_bufp2 = NULL;
9489 if (!II_SUCCESS(rc))
9490 return (rc);
9491 }
9492
9493 bfd = h->ii_fd;
9494 rsrv = h->ii_rsrv;
9495
9496 if ((h->ii_bufh.sb_flag & NSC_HALLOCATED) == 0) {
9497 rc = _ii_free_handle(h, h->ii_fd);
9498 if (!II_SUCCESS(rc))
9499 return (rc);
9500 } else {
9501 h->ii_bufh.sb_flag = NSC_HALLOCATED;
9502 h->ii_bufh.sb_vec = NULL;
9503 h->ii_bufh.sb_error = 0;
9504 h->ii_bufh.sb_pos = 0;
9505 h->ii_bufh.sb_len = 0;
9506 h->ii_rsrv = NULL;
9507 }
9508
9509 /*
9510 * Release temporary reserve - reserved in _ii_alloc_buf.
9511 */
9512
9513 if (rsrv)
9514 _ii_rlse_devs(bfd->ii_info, rsrv);
9515 rw_exit(&bfd->ii_info->bi_linkrw);
9516
9517 return (0);
9518 }
9519
9520
9521 /*
9522 * _ii_open
9523 * Open a device
9524 *
9525 * Calling/Exit State:
9526 * Returns a token to identify the shadow device.
9527 *
9528 * Description:
9529 * Performs the housekeeping operations associated with an upper layer
9530 * of the nsc stack opening a shadowed device.
9531 */
9532
9533 /* ARGSUSED */
9534
9535 static int
_ii_open(char * path,int flag,blind_t * cdp,nsc_iodev_t * iodev)9536 _ii_open(char *path, int flag, blind_t *cdp, nsc_iodev_t *iodev)
9537 {
9538 _ii_info_t *ip;
9539 _ii_overflow_t *op;
9540 ii_fd_t *bfd;
9541 int is_mst = 0;
9542 int is_shd = 0;
9543 int raw = (flag & NSC_CACHE) == 0;
9544
9545 bfd = nsc_kmem_zalloc(sizeof (*bfd), KM_SLEEP, _ii_local_mem);
9546 if (!bfd)
9547 return (ENOMEM);
9548
9549 DTRACE_PROBE1(_ii_open_mutex,
9550 ii_fd_t *, bfd);
9551
9552 mutex_enter(&_ii_info_mutex);
9553
9554 for (ip = _ii_info_top; ip; ip = ip->bi_next) {
9555 if (strcmp(path, ii_pathname(ip->bi_mstfd)) == 0) {
9556 is_mst = 1;
9557 break;
9558 } else if (strcmp(path, ip->bi_keyname) == 0) {
9559 is_shd = 1;
9560 break;
9561 } else if (strcmp(path, ii_pathname(ip->bi_bmpfd)) == 0)
9562 break;
9563 }
9564
9565 if (is_mst)
9566 ip = ip->bi_master;
9567
9568 if (ip && ip->bi_disabled && !(ip->bi_state & DSW_MULTIMST)) {
9569 DTRACE_PROBE(_ii_open_Disabled);
9570 mutex_exit(&_ii_info_mutex);
9571 return (EINTR);
9572 }
9573
9574 if (!ip) {
9575 /* maybe it's an overflow */
9576 mutex_exit(&_ii_info_mutex);
9577 mutex_enter(&_ii_overflow_mutex);
9578 for (op = _ii_overflow_top; op; op = op->ii_next) {
9579 if (strcmp(path, op->ii_volname) == 0)
9580 break;
9581 }
9582 mutex_exit(&_ii_overflow_mutex);
9583
9584 if (!op) {
9585 nsc_kmem_free(bfd, sizeof (*bfd));
9586 DTRACE_PROBE(_ii_open_end_EINVAL);
9587 return (EINVAL);
9588 }
9589 bfd->ii_ovr = 1;
9590 bfd->ii_oflags = flag;
9591 bfd->ii_optr = op;
9592 *cdp = (blind_t)bfd;
9593
9594 DTRACE_PROBE(_ii_open_end_overflow);
9595 return (0);
9596 }
9597 mutex_enter(&ip->bi_mutex);
9598 ip->bi_ioctl++;
9599 mutex_exit(&_ii_info_mutex);
9600
9601 if (is_mst) {
9602 if (raw) {
9603 ip->bi_mstr_iodev = NULL; /* set in attach */
9604 ip->bi_mstrref++;
9605 } else {
9606 ip->bi_mst_iodev = NULL; /* set in attach */
9607 ip->bi_mstref++;
9608 }
9609 ip->bi_master->bi_iifd = bfd;
9610 } else if (is_shd) {
9611 if (raw) {
9612 ip->bi_shdr_iodev = NULL; /* set in attach */
9613 ip->bi_shdrref++;
9614 } else {
9615 ip->bi_shd_iodev = NULL; /* set in attach */
9616 ip->bi_shdref++;
9617 }
9618 bfd->ii_shd = 1;
9619 } else {
9620 ip->bi_bmpref++;
9621 ip->bi_bmp_iodev = NULL; /* set in attach */
9622 bfd->ii_bmp = 1;
9623 }
9624
9625 _ii_ioctl_done(ip);
9626 mutex_exit(&ip->bi_mutex);
9627
9628 bfd->ii_info = ip;
9629 bfd->ii_oflags = flag;
9630
9631 *cdp = (blind_t)bfd;
9632
9633 return (0);
9634 }
9635
9636 static int
_ii_openc(char * path,int flag,blind_t * cdp,nsc_iodev_t * iodev)9637 _ii_openc(char *path, int flag, blind_t *cdp, nsc_iodev_t *iodev)
9638 {
9639 return (_ii_open(path, NSC_CACHE|flag, cdp, iodev));
9640 }
9641
9642 static int
_ii_openr(char * path,int flag,blind_t * cdp,nsc_iodev_t * iodev)9643 _ii_openr(char *path, int flag, blind_t *cdp, nsc_iodev_t *iodev)
9644 {
9645 return (_ii_open(path, NSC_DEVICE|flag, cdp, iodev));
9646 }
9647
9648
9649 /*
9650 * _ii_close
9651 * Close a device
9652 *
9653 * Calling/Exit State:
9654 * Always succeeds - returns 0
9655 *
9656 * Description:
9657 * Performs the housekeeping operations associated with an upper layer
9658 * of the nsc stack closing a shadowed device.
9659 */
9660
9661 static int
_ii_close(bfd)9662 _ii_close(bfd)
9663 ii_fd_t *bfd;
9664 {
9665 _ii_info_t *ip = bfd->ii_info;
9666 _ii_info_dev_t *dip;
9667 int raw;
9668
9669 if (!ip) {
9670 ASSERT(bfd->ii_ovr);
9671 return (0);
9672 }
9673
9674 raw = II_RAW(bfd);
9675
9676 mutex_enter(&ip->bi_mutex);
9677
9678 if (bfd->ii_shd && raw) {
9679 dip = &ip->bi_shdrdev;
9680 } else if (bfd->ii_shd) {
9681 dip = &ip->bi_shddev;
9682 } else if (bfd->ii_bmp) {
9683 dip = &ip->bi_bmpdev;
9684 } else if (raw) {
9685 dip = ip->bi_mstrdev;
9686 } else {
9687 dip = ip->bi_mstdev;
9688 }
9689
9690 if (dip) {
9691 dip->bi_ref--;
9692 if (dip->bi_ref == 0)
9693 dip->bi_iodev = NULL;
9694 }
9695
9696 if (ip->bi_state & DSW_CLOSING) {
9697 if (total_ref(ip) == 0) {
9698 cv_signal(&ip->bi_closingcv);
9699 }
9700 } else if ((ip->bi_flags & DSW_HANGING) &&
9701 (ip->bi_head->bi_state & DSW_CLOSING))
9702 cv_signal(&ip->bi_head->bi_closingcv);
9703
9704 if (!(bfd->ii_shd || bfd->ii_bmp)) /* is master device */
9705 ip->bi_master->bi_iifd = NULL;
9706 mutex_exit(&ip->bi_mutex);
9707
9708 nsc_kmem_free(bfd, sizeof (*bfd));
9709
9710 return (0);
9711 }
9712
9713 /*
9714 * _ii_alloc_handle
9715 * Allocate a handle
9716 *
9717 */
9718
9719 static nsc_buf_t *
_ii_alloc_handle(void (* d_cb)(),void (* r_cb)(),void (* w_cb)(),ii_fd_t * bfd)9720 _ii_alloc_handle(void (*d_cb)(), void (*r_cb)(), void (*w_cb)(), ii_fd_t *bfd)
9721 {
9722 ii_buf_t *h;
9723
9724 if (REMOTE_VOL(bfd->ii_shd, bfd->ii_info))
9725 return (NULL);
9726
9727 h = kmem_alloc(sizeof (*h), KM_SLEEP);
9728 if (!h)
9729 return (NULL);
9730
9731 h->ii_abufp = NULL;
9732 h->ii_bufp = nsc_alloc_handle(II_FD(bfd), d_cb, r_cb, w_cb);
9733 if (!h->ii_bufp) {
9734 kmem_free(h, sizeof (*h));
9735 return (NULL);
9736 }
9737 h->ii_bufp2 = NULL;
9738 h->ii_bufh.sb_flag = NSC_HALLOCATED;
9739 h->ii_fd = bfd;
9740 h->ii_rsrv = NULL;
9741
9742 return ((nsc_buf_t *)h);
9743 }
9744
9745
9746 /*
9747 * _ii_free_handle
9748 * Free a handle
9749 *
9750 */
9751
9752 static int /*ARGSUSED*/
_ii_free_handle(ii_buf_t * h,ii_fd_t * bfd)9753 _ii_free_handle(ii_buf_t *h, ii_fd_t *bfd)
9754 {
9755 int rc;
9756
9757 if (h->ii_abufp)
9758 (void) nsc_free_buf(h->ii_abufp);
9759 rc = nsc_free_handle(h->ii_bufp);
9760 if (!II_SUCCESS(rc)) {
9761 return (rc);
9762 }
9763
9764 kmem_free(h, sizeof (ii_buf_t));
9765
9766 return (0);
9767 }
9768
9769
9770 /*
9771 * _ii_attach
9772 * Attach
9773 *
9774 * Calling/Exit State:
9775 * Returns 0 for success, errno on failure.
9776 *
9777 * Description:
9778 */
9779
9780 static int
_ii_attach(ii_fd_t * bfd,nsc_iodev_t * iodev)9781 _ii_attach(ii_fd_t *bfd, nsc_iodev_t *iodev)
9782 {
9783 _ii_info_t *ip;
9784 int dev;
9785 int raw;
9786 int rc;
9787 _ii_info_dev_t *infop;
9788
9789 raw = II_RAW(bfd);
9790
9791 DTRACE_PROBE2(_ii_attach_info,
9792 char *, bfd->ii_shd? "shadow" : "master",
9793 int, raw);
9794
9795 if (bfd->ii_ovr)
9796 return (EINVAL);
9797
9798 ip = bfd->ii_info;
9799 if (ip == NULL)
9800 return (EINVAL);
9801
9802 mutex_enter(&ip->bi_mutex);
9803 if (bfd->ii_bmp) {
9804 infop = &ip->bi_bmpdev;
9805 } else if (bfd->ii_shd) {
9806 if (raw) {
9807 infop = &ip->bi_shdrdev;
9808 } else {
9809 infop = &ip->bi_shddev;
9810 }
9811 } else if (!bfd->ii_ovr) {
9812 if (raw) {
9813 infop = ip->bi_mstrdev;
9814 } else {
9815 infop = ip->bi_mstdev;
9816 }
9817 }
9818
9819 if (iodev) {
9820 infop->bi_iodev = iodev;
9821 nsc_set_owner(infop->bi_fd, infop->bi_iodev);
9822 }
9823 mutex_exit(&ip->bi_mutex);
9824
9825 if (bfd->ii_bmp)
9826 return (EINVAL);
9827
9828 if (raw)
9829 dev = bfd->ii_shd ? SHDR : MSTR;
9830 else
9831 dev = bfd->ii_shd ? SHD : MST;
9832
9833 rc = _ii_rsrv_devs(ip, dev, II_EXTERNAL);
9834
9835 return (rc);
9836 }
9837
9838
9839 /*
9840 * _ii_detach
9841 * Detach
9842 *
9843 * Calling/Exit State:
9844 * Returns 0 for success, always succeeds
9845 *
9846 * Description:
9847 */
9848
9849 static int
_ii_detach(bfd)9850 _ii_detach(bfd)
9851 ii_fd_t *bfd;
9852 {
9853 int dev;
9854 int raw;
9855
9856 raw = II_RAW(bfd);
9857
9858 DTRACE_PROBE2(_ii_detach_info,
9859 char *, bfd->ii_shd? "shadow" : "master",
9860 int, raw);
9861
9862 if (bfd->ii_bmp)
9863 return (0);
9864
9865 ASSERT(bfd->ii_info);
9866 dev = bfd->ii_shd ? (raw ? SHDR : SHD) : (raw ? MSTR : MST);
9867 _ii_rlse_devs(bfd->ii_info, dev);
9868
9869 return (0);
9870 }
9871
9872 /*
9873 * _ii_get_pinned
9874 *
9875 */
9876
9877 static int
_ii_get_pinned(ii_fd_t * bfd)9878 _ii_get_pinned(ii_fd_t *bfd)
9879 {
9880 int rc;
9881
9882 if (REMOTE_VOL(bfd->ii_shd, bfd->ii_info))
9883 return (EIO);
9884
9885 rc = nsc_get_pinned(II_FD(bfd));
9886
9887 return (rc);
9888 }
9889
9890 /*
9891 * _ii_discard_pinned
9892 *
9893 */
9894
9895 static int
_ii_discard_pinned(ii_fd_t * bfd,nsc_off_t pos,nsc_size_t len)9896 _ii_discard_pinned(ii_fd_t *bfd, nsc_off_t pos, nsc_size_t len)
9897 {
9898 int rc;
9899
9900 if (REMOTE_VOL(bfd->ii_shd, bfd->ii_info))
9901 return (EIO);
9902 rc = nsc_discard_pinned(II_FD(bfd), pos, len);
9903
9904 return (rc);
9905 }
9906
9907 /*
9908 * _ii_partsize
9909 *
9910 */
9911
9912 static int
_ii_partsize(ii_fd_t * bfd,nsc_size_t * ptr)9913 _ii_partsize(ii_fd_t *bfd, nsc_size_t *ptr)
9914 {
9915 /* Always return saved size */
9916 *ptr = bfd->ii_info->bi_size;
9917 return (0);
9918 }
9919
9920 /*
9921 * _ii_maxfbas
9922 *
9923 */
9924
9925 static int
_ii_maxfbas(ii_fd_t * bfd,int flag,nsc_size_t * ptr)9926 _ii_maxfbas(ii_fd_t *bfd, int flag, nsc_size_t *ptr)
9927 {
9928 int rc;
9929 int rs;
9930 int dev;
9931 _ii_info_t *ip;
9932
9933 ip = bfd->ii_info;
9934 if (REMOTE_VOL(bfd->ii_shd, ip))
9935 return (EIO);
9936
9937 dev = ((ip->bi_flags)&DSW_SHDIMPORT) ? SHDR : MSTR;
9938
9939 DTRACE_PROBE1(_ii_maxfbas_info,
9940 char *, dev == SHDR? "shadow" : "master");
9941
9942 rs = _ii_rsrv_devs(ip, dev, II_INTERNAL);
9943 rc = nsc_maxfbas((dev == MSTR) ? MSTFD(ip) : SHDFD(ip), flag, ptr);
9944
9945 if (rs == 0)
9946 _ii_rlse_devs(ip, dev);
9947
9948 return (rc);
9949 }
9950
9951 /*
9952 * ii_get_group_list
9953 */
9954 _ii_info_t **
ii_get_group_list(char * group,int * count)9955 ii_get_group_list(char *group, int *count)
9956 {
9957 int i;
9958 int nip;
9959 uint64_t hash;
9960 _ii_info_t **ipa;
9961 _ii_lsthead_t *head;
9962 _ii_lstinfo_t *np;
9963
9964 hash = nsc_strhash(group);
9965
9966 for (head = _ii_group_top; head; head = head->lst_next) {
9967 if (hash == head->lst_hash && strncmp(head->lst_name,
9968 group, DSW_NAMELEN) == 0)
9969 break;
9970 }
9971
9972 if (!head) {
9973 return (NULL);
9974 }
9975
9976 /* Count entries */
9977 for (nip = 0, np = head->lst_start; np; np = np->lst_next)
9978 ++nip;
9979
9980 ASSERT(nip > 0);
9981
9982 ipa = kmem_zalloc(sizeof (_ii_info_t *) * nip, KM_SLEEP);
9983
9984 np = head->lst_start;
9985
9986 for (i = 0; i < nip; i++) {
9987 ASSERT(np != 0);
9988
9989 ipa[i] = np->lst_ip;
9990 np = np->lst_next;
9991 }
9992
9993 *count = nip;
9994 return (ipa);
9995 }
9996
9997 /*
9998 * _ii_pinned
9999 *
10000 */
10001
10002 static void
_ii_pinned(_ii_info_dev_t * dip,nsc_off_t pos,nsc_size_t len)10003 _ii_pinned(_ii_info_dev_t *dip, nsc_off_t pos, nsc_size_t len)
10004 {
10005 DTRACE_PROBE3(_ii_pinned_start, nsc_iodev_t, dip->bi_iodev,
10006 nsc_off_t, pos, nsc_size_t, len);
10007
10008 nsc_pinned_data(dip->bi_iodev, pos, len);
10009
10010 }
10011
10012 /*
10013 * _ii_unpinned
10014 *
10015 */
10016
10017 static void
_ii_unpinned(_ii_info_dev_t * dip,nsc_off_t pos,nsc_size_t len)10018 _ii_unpinned(_ii_info_dev_t *dip, nsc_off_t pos, nsc_size_t len)
10019 {
10020 nsc_unpinned_data(dip->bi_iodev, pos, len);
10021
10022 }
10023
10024
10025 /*
10026 * _ii_read
10027 */
10028
10029 static int
_ii_read(ii_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)10030 _ii_read(ii_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
10031 {
10032 int rc;
10033 void *sb_vec;
10034 nsc_vec_t **src;
10035
10036 if (REMOTE_VOL(h->ii_fd->ii_shd, h->ii_fd->ii_info))
10037 rc = EIO;
10038 else {
10039 src = h->ii_abufp? &h->ii_abufp->sb_vec : &h->ii_bufp->sb_vec;
10040 sb_vec = *src;
10041 *src = h->ii_bufh.sb_vec;
10042 rc = _ii_fill_buf(h->ii_fd, pos, len, flag,
10043 h->ii_abufp ? &h->ii_abufp : &h->ii_bufp, &h->ii_bufp2);
10044 *src = sb_vec;
10045 }
10046 if (!II_SUCCESS(rc))
10047 h->ii_bufh.sb_error = rc;
10048
10049 return (rc);
10050 }
10051
10052
10053 /*
10054 * _ii_write
10055 */
10056
10057 static int
_ii_write(ii_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)10058 _ii_write(ii_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
10059 {
10060 int rc;
10061 ii_fd_t *bfd = h->ii_fd;
10062 _ii_info_t *ip = bfd->ii_info;
10063 chunkid_t chunk_num;
10064 nsc_size_t copy_len;
10065 nsc_off_t mapped_fba;
10066 chunkid_t mapped_chunk;
10067 int overflow;
10068 nsc_buf_t *tmp;
10069 void *sb_vec;
10070
10071 if (REMOTE_VOL(h->ii_fd->ii_shd, h->ii_fd->ii_info))
10072 rc = EIO;
10073 else if ((ip->bi_flags&DSW_TREEMAP) == 0 || !bfd->ii_shd) {
10074 sb_vec = h->ii_bufp->sb_vec;
10075 h->ii_bufp->sb_vec = h->ii_bufh.sb_vec;
10076 if (bfd->ii_shd) {
10077 II_NSC_WRITE(ip, shadow, rc, h->ii_bufp, pos, len,
10078 flag);
10079 } else {
10080 II_NSC_WRITE(ip, master, rc, h->ii_bufp, pos, len,
10081 flag);
10082 }
10083 h->ii_bufp->sb_vec = sb_vec;
10084 } else {
10085 /* write of mapped shadow buffer */
10086 rc = 0;
10087 chunk_num = pos / DSW_SIZE;
10088 while (len > 0 && II_SUCCESS(rc)) {
10089 /*
10090 * don't need to test bitmaps as allocating the
10091 * write buffer will c-o-write the chunk.
10092 */
10093 mapped_chunk = ii_tsearch(ip, chunk_num);
10094 if (mapped_chunk == II_NULLNODE) {
10095 rc = EIO;
10096 break;
10097 }
10098 overflow = II_ISOVERFLOW(mapped_chunk);
10099 if (overflow)
10100 mapped_chunk = II_2OVERFLOW(mapped_chunk);
10101 mapped_fba = DSW_CHK2FBA(mapped_chunk) +
10102 (pos % DSW_SIZE);
10103 copy_len = DSW_SIZE - (pos % DSW_SIZE);
10104 if (copy_len > len)
10105 copy_len = len;
10106 tmp = NULL;
10107 if (overflow) {
10108 (void) nsc_reserve(OVRFD(ip), NSC_MULTI);
10109 rc = nsc_alloc_buf(OVRFD(ip), mapped_fba,
10110 copy_len, NSC_WRBUF, &tmp);
10111 } else
10112 rc = nsc_alloc_buf(SHDFD(ip), mapped_fba,
10113 copy_len, NSC_WRBUF, &tmp);
10114 sb_vec = h->ii_abufp->sb_vec;
10115 h->ii_abufp->sb_vec = h->ii_bufh.sb_vec;
10116 if (II_SUCCESS(rc)) {
10117 rc = nsc_copy(h->ii_abufp, tmp, pos,
10118 mapped_fba, copy_len);
10119 }
10120 if (overflow) {
10121 II_NSC_WRITE(ip, overflow, rc, tmp, mapped_fba,
10122 copy_len, flag);
10123 } else {
10124 II_NSC_WRITE(ip, shadow, rc, tmp, mapped_fba,
10125 copy_len, flag);
10126 }
10127 h->ii_abufp->sb_vec = sb_vec;
10128 (void) nsc_free_buf(tmp);
10129 if (overflow)
10130 nsc_release(OVRFD(ip));
10131 /* move on to next chunk */
10132 pos += copy_len;
10133 len -= copy_len;
10134 chunk_num++;
10135 }
10136 }
10137 if (!II_SUCCESS(rc))
10138 h->ii_bufh.sb_error = rc;
10139
10140 return (rc);
10141 }
10142
10143
10144 /*
10145 * _ii_zero
10146 */
10147
10148 static int
_ii_zero(ii_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)10149 _ii_zero(ii_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
10150 {
10151 int rc;
10152 void *sb_vec;
10153
10154 sb_vec = h->ii_bufp->sb_vec;
10155 h->ii_bufp->sb_vec = h->ii_bufh.sb_vec;
10156 rc = nsc_zero(h->ii_bufp, pos, len, flag);
10157 h->ii_bufp->sb_vec = sb_vec;
10158 if (!II_SUCCESS(rc))
10159 h->ii_bufh.sb_error = rc;
10160
10161 return (rc);
10162 }
10163
10164
10165 /*
10166 * _ii_uncommit
10167 */
10168
10169 static int
_ii_uncommit(ii_buf_t * h,nsc_off_t pos,nsc_size_t len,int flag)10170 _ii_uncommit(ii_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
10171 {
10172 int rc;
10173 void *sb_vec;
10174
10175 sb_vec = h->ii_bufp->sb_vec;
10176 h->ii_bufp->sb_vec = h->ii_bufh.sb_vec;
10177 rc = nsc_uncommit(h->ii_bufp, pos, len, flag);
10178 h->ii_bufp->sb_vec = sb_vec;
10179 if (!II_SUCCESS(rc))
10180 h->ii_bufh.sb_error = rc;
10181
10182 return (rc);
10183 }
10184
10185
10186 /*
10187 * _ii_trksize
10188 */
10189
10190 static int
_ii_trksize(ii_fd_t * bfd,int trksize)10191 _ii_trksize(ii_fd_t *bfd, int trksize)
10192 {
10193 int rc;
10194
10195 rc = nsc_set_trksize(II_FD(bfd), trksize);
10196
10197 return (rc);
10198 }
10199
10200 /*
10201 * _ii_register_path
10202 */
10203
10204 static nsc_path_t *
_ii_register_path(char * path,int type,nsc_io_t * io)10205 _ii_register_path(char *path, int type, nsc_io_t *io)
10206 {
10207 nsc_path_t *tok;
10208
10209 tok = nsc_register_path(path, type, io);
10210
10211 return (tok);
10212 }
10213
10214 /*
10215 * _ii_unregister_path
10216 */
10217 /*ARGSUSED*/
10218 static int
_ii_unregister_path(nsc_path_t * sp,int flag,char * type)10219 _ii_unregister_path(nsc_path_t *sp, int flag, char *type)
10220 {
10221 int rc;
10222
10223 rc = nsc_unregister_path(sp, flag);
10224
10225 return (rc);
10226 }
10227
10228 int
_ii_ll_add(_ii_info_t * ip,kmutex_t * mutex,_ii_lsthead_t ** lst,char * name,char ** key)10229 _ii_ll_add(_ii_info_t *ip, kmutex_t *mutex, _ii_lsthead_t **lst, char *name,
10230 char **key)
10231 {
10232 _ii_lsthead_t **head;
10233 _ii_lstinfo_t *node;
10234 uint64_t hash;
10235
10236 ASSERT(key && !*key);
10237 ASSERT(ip && mutex && lst && name);
10238
10239 node = kmem_zalloc(sizeof (_ii_lstinfo_t), KM_SLEEP);
10240 if (!node) {
10241 cmn_err(CE_WARN, "!ii: _ii_ll_add: ENOMEM");
10242 DTRACE_PROBE(_ii_ll_add_end_ENOMEM);
10243 return (ENOMEM);
10244 }
10245 node->lst_ip = ip;
10246
10247 /* find out where we should insert it */
10248 hash = nsc_strhash(name);
10249
10250 mutex_enter(mutex);
10251 for (head = lst; *head; head = &((*head)->lst_next)) {
10252 if (((*head)->lst_hash == hash) &&
10253 strncmp(name, (*head)->lst_name, DSW_NAMELEN) == 0) {
10254 node->lst_next = (*head)->lst_start;
10255 (*head)->lst_start = node;
10256 break;
10257 }
10258 }
10259
10260 if (!*head) {
10261 /* create a new entry */
10262 *head = kmem_zalloc(sizeof (_ii_lsthead_t), KM_SLEEP);
10263 if (!*head) {
10264 /* bother */
10265 cmn_err(CE_WARN, "!ii: _ii_ll_add: ENOMEM");
10266 kmem_free(node, sizeof (_ii_lstinfo_t));
10267 DTRACE_PROBE(_ii_ll_add_end_2);
10268 return (ENOMEM);
10269 }
10270 (*head)->lst_hash = hash;
10271 (void) strncpy((*head)->lst_name, name, DSW_NAMELEN);
10272 (*head)->lst_start = node;
10273 }
10274 mutex_exit(mutex);
10275
10276 *key = (*head)->lst_name;
10277
10278 return (0);
10279 }
10280
10281 int
_ii_ll_remove(_ii_info_t * ip,kmutex_t * mutex,_ii_lsthead_t ** lst,char ** key)10282 _ii_ll_remove(_ii_info_t *ip, kmutex_t *mutex, _ii_lsthead_t **lst, char **key)
10283 {
10284 _ii_lsthead_t **head, *oldhead = 0;
10285 _ii_lstinfo_t **node, *oldnode = 0;
10286 uint64_t hash;
10287 int found;
10288
10289 ASSERT(key && *key);
10290 ASSERT(ip && lst);
10291
10292 hash = nsc_strhash(*key);
10293
10294 mutex_enter(mutex);
10295 for (head = lst; *head; head = &((*head)->lst_next)) {
10296 if (((*head)->lst_hash == hash) &&
10297 strncmp(*key, (*head)->lst_name, DSW_NAMELEN) == 0)
10298 break;
10299 }
10300 if (!*head) {
10301 /* no such link (!) */
10302 mutex_exit(mutex);
10303 return (0);
10304 }
10305
10306 found = 0;
10307 for (node = &(*head)->lst_start; *node; node = &((*node)->lst_next)) {
10308 if (ip == (*node)->lst_ip) {
10309 oldnode = *node;
10310 *node = (*node)->lst_next;
10311 kmem_free(oldnode, sizeof (_ii_lstinfo_t));
10312 found = 1;
10313 break;
10314 }
10315 }
10316
10317 ASSERT(found);
10318
10319 if (!found) {
10320 mutex_exit(mutex);
10321 return (0);
10322 }
10323
10324 /* did we just delete the last set in this resource group? */
10325 if (!(*head)->lst_start) {
10326 oldhead = *head;
10327 *head = (*head)->lst_next;
10328 kmem_free(oldhead, sizeof (_ii_lsthead_t));
10329 }
10330 mutex_exit(mutex);
10331
10332 *key = NULL;
10333
10334 return (0);
10335 }
10336
10337 static nsc_def_t _ii_fd_def[] = {
10338 "Pinned", (uintptr_t)_ii_pinned, 0,
10339 "Unpinned", (uintptr_t)_ii_unpinned, 0,
10340 0, 0, 0
10341 };
10342
10343
10344 static nsc_def_t _ii_io_def[] = {
10345 "Open", (uintptr_t)_ii_openc, 0,
10346 "Close", (uintptr_t)_ii_close, 0,
10347 "Attach", (uintptr_t)_ii_attach, 0,
10348 "Detach", (uintptr_t)_ii_detach, 0,
10349 "AllocHandle", (uintptr_t)_ii_alloc_handle, 0,
10350 "FreeHandle", (uintptr_t)_ii_free_handle, 0,
10351 "AllocBuf", (uintptr_t)_ii_alloc_buf, 0,
10352 "FreeBuf", (uintptr_t)_ii_free_buf, 0,
10353 "GetPinned", (uintptr_t)_ii_get_pinned, 0,
10354 "Discard", (uintptr_t)_ii_discard_pinned, 0,
10355 "PartSize", (uintptr_t)_ii_partsize, 0,
10356 "MaxFbas", (uintptr_t)_ii_maxfbas, 0,
10357 "Read", (uintptr_t)_ii_read, 0,
10358 "Write", (uintptr_t)_ii_write, 0,
10359 "Zero", (uintptr_t)_ii_zero, 0,
10360 "Uncommit", (uintptr_t)_ii_uncommit, 0,
10361 "TrackSize", (uintptr_t)_ii_trksize, 0,
10362 "Provide", 0, 0,
10363 0, 0, 0
10364 };
10365
10366 static nsc_def_t _ii_ior_def[] = {
10367 "Open", (uintptr_t)_ii_openr, 0,
10368 "Close", (uintptr_t)_ii_close, 0,
10369 "Attach", (uintptr_t)_ii_attach, 0,
10370 "Detach", (uintptr_t)_ii_detach, 0,
10371 "AllocHandle", (uintptr_t)_ii_alloc_handle, 0,
10372 "FreeHandle", (uintptr_t)_ii_free_handle, 0,
10373 "AllocBuf", (uintptr_t)_ii_alloc_buf, 0,
10374 "FreeBuf", (uintptr_t)_ii_free_buf, 0,
10375 "GetPinned", (uintptr_t)_ii_get_pinned, 0,
10376 "Discard", (uintptr_t)_ii_discard_pinned, 0,
10377 "PartSize", (uintptr_t)_ii_partsize, 0,
10378 "MaxFbas", (uintptr_t)_ii_maxfbas, 0,
10379 "Read", (uintptr_t)_ii_read, 0,
10380 "Write", (uintptr_t)_ii_write, 0,
10381 "Zero", (uintptr_t)_ii_zero, 0,
10382 "Uncommit", (uintptr_t)_ii_uncommit, 0,
10383 "TrackSize", (uintptr_t)_ii_trksize, 0,
10384 "Provide", 0, 0,
10385 0, 0, 0
10386 };
10387