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