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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
28 #include <sys/param.h>
29 #include <sys/systm.h>
34 #include <sys/t_lock.h>
39 #include <sys/cmn_err.h>
40 #include <sys/sysmacros.h>
41 #include <sys/types.h>
42 #include <sys/mkdev.h>
45 #include <sys/lvm/md_trans.h>
46 #include <sys/modctl.h>
48 #include <sys/sunddi.h>
49 #include <sys/debug.h>
50 #include <sys/filio.h>
51 #include <sys/lvm/md_notify.h>
52 #include <sys/callb.h>
55 #include <sys/sysevent/eventdefs.h>
56 #include <sys/sysevent/svm.h>
59 extern unit_t md_nunits
;
60 extern set_t md_nsets
;
61 extern md_set_t md_set
[];
62 extern md_ops_t trans_md_ops
;
63 extern md_krwlock_t md_unit_array_rw
;
64 extern uint_t mt_debug
;
66 extern major_t md_major
;
69 trans_getun(minor_t mnum
, md_error_t
*mde
, int flags
, IOLOCK
*lock
)
73 set_t setno
= MD_MIN2SET(mnum
);
75 if ((setno
>= md_nsets
) || (MD_MIN2UNIT(mnum
) >= md_nunits
)) {
76 (void) mdmderror(mde
, MDE_INVAL_UNIT
, mnum
);
80 if (! (flags
& STALE_OK
)) {
81 if (md_get_setstatus(setno
) & MD_SET_STALE
) {
82 (void) mdmddberror(mde
, MDE_DB_STALE
, mnum
, setno
);
90 (void) mdmderror(mde
, MDE_UNIT_ALREADY_SETUP
, mnum
);
93 return ((mt_unit_t
*)1);
97 (void) mdmderror(mde
, MDE_UNIT_NOT_SETUP
, mnum
);
101 if (flags
& ARRAY_WRITER
)
102 md_array_writer(lock
);
103 else if (flags
& ARRAY_READER
)
104 md_array_reader(lock
);
106 if (!(flags
& NO_LOCK
)) {
108 (void) md_ioctl_writerlock(lock
, ui
);
110 (void) md_ioctl_readerlock(lock
, ui
);
112 un
= (mt_unit_t
*)MD_UNIT(mnum
);
114 if (un
->c
.un_type
!= MD_METATRANS
) {
115 (void) mdmderror(mde
, MDE_NOT_MT
, mnum
);
125 * THESE ROUTINES ARE ONLY USED WHEN ASSERTS ARE ENABLED
128 extern int (*mdv_strategy_tstpnt
)(buf_t
*, int, void*);
131 * return the global stats struct
134 trans_get_transstats(void *d
, int mode
)
136 md_i_get_t
*migp
= d
;
138 mdclrerror(&migp
->mde
);
140 if (migp
->size
== 0) {
141 migp
->size
= sizeof (struct transstats
);
145 if (migp
->size
< sizeof (struct transstats
))
148 if (ddi_copyout(&transstats
, (caddr_t
)(uintptr_t)migp
->mdp
,
149 sizeof (struct transstats
), mode
))
162 trans_test_trygetblk(void *d
, int mode
, IOLOCK
*lock
)
168 struct buf
*trygetblk();
170 md_i_get_t
*migp
= d
;
172 mdclrerror(&migp
->mde
);
175 un
= trans_getun(migp
->id
, &migp
->mde
,
183 * test 1 -- don't find nonexistant buf
186 if (bp
= trygetblk(dev
, 0))
190 * test 2 - don't find stale buf
193 if ((bp
= getblk(dev
, 0, DEV_BSIZE
)) == NULL
)
195 bp
->b_flags
|= (B_STALE
|B_DONE
);
197 if (bp
= trygetblk(dev
, 0))
201 * test 3 -- don't find busy buf
204 if ((bp
= getblk(dev
, 0, DEV_BSIZE
)) == NULL
)
206 if (trygetblk(dev
, 0))
208 bp
->b_flags
|= B_STALE
;
212 * test 4 -- don't find not-done buf
215 if ((bp
= getblk(dev
, 0, DEV_BSIZE
)) == NULL
)
218 if (bp
= trygetblk(dev
, 0))
222 * test 5 -- find an idle buf
225 if ((bp
= bread(dev
, 0, DEV_BSIZE
)) == NULL
)
228 if ((bp
= trygetblk(dev
, 0)) == NULL
)
230 bp
->b_flags
|= B_STALE
;
234 test
= 0; /* no test failed */
237 bp
->b_flags
|= B_STALE
;
249 trans_trypage(struct vnode
*vp
, uint_t off
)
256 if ((pp
= page_lookup_nowait(vp
, off
, SE_EXCL
)) == NULL
)
261 if (!page_io_trylock(pp
)) {
270 trans_test_trypage(void *d
, int mode
, IOLOCK
*lock
)
278 extern struct vnode
*common_specvp(struct vnode
*);
279 extern void pvn_io_done(struct page
*);
281 md_i_get_t
*migp
= d
;
283 mdclrerror(&migp
->mde
);
286 un
= trans_getun(migp
->id
, &migp
->mde
,
292 devvp
= makespecvp(dev
, VBLK
);
293 cvp
= common_specvp(devvp
);
296 * get rid of the devices pages
298 (void) VOP_PUTPAGE(cvp
, (offset_t
)0, (uint_t
)0, B_INVAL
, CRED(), NULL
);
301 * test 1 -- don't find nonexistant page
304 if (pp
= trans_trypage(cvp
, 0))
308 * test 2 -- don't find busy page
311 if ((pp
= page_create(cvp
, 0, 1, PG_WAIT
)) == NULL
)
313 if (trans_trypage(cvp
, 0))
319 * test 3 - find an idle page
322 if ((pp
= page_create(cvp
, 0, 1, PG_WAIT
)) == NULL
)
325 if ((pp
= trans_trypage(cvp
, 0)) == NULL
)
330 test
= 0; /* no test failed */
335 * get rid of the file's pages
337 (void) VOP_PUTPAGE(cvp
, (offset_t
)0, (uint_t
)0, B_INVAL
, CRED(), NULL
);
349 #define NTSDTHREADS (3)
358 static uint_t keys
[NKEYS
];
359 static struct tothread tta
[NTSDTHREADS
];
360 static int allocatorvalue
;
361 static int okdestructoralloc
;
364 trans_test_stepwait(struct tothread
*tp
, int step
)
367 * wait for other thread
369 mutex_enter(&tp
->lock
);
370 while (tp
->step
< step
)
371 cv_wait(&tp
->cv
, &tp
->lock
);
372 mutex_exit(&tp
->lock
);
376 trans_test_step(struct tothread
*tp
, int step
)
379 * wakeup other threads
381 mutex_enter(&tp
->lock
);
383 cv_broadcast(&tp
->cv
);
384 mutex_exit(&tp
->lock
);
388 trans_test_destructor(void *voidp
)
391 struct tothread
*tp
= voidp
;
394 * check that threads clean up *all* TSD at exit
396 mutex_enter(&tp
->lock
);
398 mutex_exit(&tp
->lock
);
400 trans_test_step(tp
, 3);
404 trans_test_destructor_alloc(void *voidp
)
408 okdestructoralloc
= 0;
410 if (*value
== allocatorvalue
)
411 okdestructoralloc
= 1;
412 md_trans_free((caddr_t
)value
, sizeof (value
));
417 trans_test_allocator(void)
421 value
= (int *)md_trans_zalloc(sizeof (value
));
422 *value
= allocatorvalue
;
423 return ((void *)value
);
427 * thread used to test TSD destroy functionality
430 trans_test_thread(struct tothread
*tp
)
436 * Register cpr callback
438 CALLB_CPR_INIT(&cprinfo
, &tp
->lock
, callb_generic_cpr
,
439 "trans_test_thread");
444 for (i
= NKEYS
- 1; i
>= 0; --i
)
445 if (tsd_set(keys
[i
], tp
)) {
450 * tell parent that we have TSD
452 trans_test_step(tp
, 1);
455 * wait for parent to destroy some of our TSD
457 trans_test_stepwait(tp
, 2);
460 * make sure that the appropriate TSD was destroyed
462 if ((tsd_get(keys
[0]) != NULL
) ||
463 (tsd_get(keys
[NKEYS
-1]) != NULL
) ||
464 (tsd_get(keys
[NKEYS
>>1]) != NULL
)) {
468 for (i
= 0; i
< NKEYS
; ++i
)
469 if (tsd_get(keys
[i
]) != tp
)
470 if (i
!= 0 && i
!= NKEYS
- 1 && i
!= NKEYS
>> 1) {
478 mutex_enter(&tp
->lock
);
479 CALLB_CPR_EXIT(&cprinfo
);
483 * error -- make sure the parent will wake up (error code in tp)
485 trans_test_step(tp
, 3);
490 mutex_enter(&tp
->lock
);
491 CALLB_CPR_EXIT(&cprinfo
);
496 trans_test_threadcreate(struct tothread
*tp
)
499 * initialize the per thread struct and make a thread
501 bzero((caddr_t
)tp
, sizeof (struct tothread
));
503 mutex_init(&tp
->lock
, NULL
, MUTEX_DEFAULT
, NULL
);
504 cv_init(&tp
->cv
, NULL
, CV_DEFAULT
, NULL
);
506 (void) thread_create(NULL
, 0, trans_test_thread
, tp
, 0, &p0
,
507 TS_RUN
, minclsyspri
);
510 * driver for TSD tests -- *NOT REENTRANT*
514 trans_test_tsd(void *d
, int mode
)
517 uint_t rekeys
[NKEYS
];
522 md_i_get_t
*migp
= d
;
524 mdclrerror(&migp
->mde
);
528 * destroy old keys, if any
530 for (i
= 0; i
< NKEYS
; ++i
)
531 tsd_destroy(&keys
[i
]);
533 * test 1 -- simple create and destroy keys tests
537 for (i
= 0; i
< NKEYS
; ++i
) {
538 tsd_create(&keys
[i
], NULL
);
540 /* get with no set should return NULL */
541 if (tsd_get(keys
[i
]) != NULL
) {
546 /* destroyed key should be 0 */
548 tsd_destroy(&keys
[i
]);
554 /* destroy the key twice */
556 tsd_destroy(&keys
[i
]);
558 /* destroyed key should be 0 */
564 /* getting a destroyed key should return NULL */
565 if (tsd_get(keys
[i
]) != NULL
) {
569 /* recreate the key */
570 tsd_create(&keys
[i
], NULL
);
572 /* should be the same key as before */
573 if (key
!= keys
[i
]) {
578 /* initial value should be NULL */
579 if (tsd_get(keys
[i
]) != NULL
) {
585 tsd_destroy(&keys
[i
]);
589 * test 2 -- recreate keys
593 for (i
= 0; i
< NKEYS
; ++i
)
594 tsd_create(&keys
[i
], NULL
);
595 for (i
= 0; i
< NKEYS
; ++i
) {
596 /* make sure the keys were created */
602 /* make sure that recreating key doesn't change it */
604 tsd_create(&rekeys
[i
], NULL
);
605 if (rekeys
[i
] != keys
[i
]) {
610 for (i
= 0; i
< NKEYS
; ++i
)
611 tsd_destroy(&keys
[i
]);
614 * test 3 -- check processing for unset and destroyed keys
619 /* getting a 0 key returns NULL */
620 if (tsd_get(0) != NULL
) {
625 /* setting a 0 key returns error */
626 if (tsd_set(0, NULL
) != EINVAL
) {
630 tsd_create(&key
, NULL
);
632 /* setting a created key returns no error */
633 if (tsd_set(key
, NULL
) == EINVAL
) {
639 /* setting a destroyed key returns error */
640 if (tsd_set(key
, NULL
) != EINVAL
) {
646 * test 4 -- make sure that set and get work
651 for (i
= 0; i
< NKEYS
; ++i
) {
652 tsd_create(&keys
[i
], NULL
);
655 (void) tsd_set(keys
[i
], &key
);
658 if (tsd_get(keys
[i
]) != &key
) {
663 /* set the value to NULL */
664 (void) tsd_set(keys
[i
], NULL
);
667 if (tsd_get(keys
[i
]) != NULL
) {
673 for (i
= 0; i
< NKEYS
; ++i
)
674 tsd_destroy(&keys
[i
]);
677 * test 5 -- destroying keys w/multiple threads
682 /* create the keys */
683 for (i
= 0; i
< NKEYS
; ++i
)
684 tsd_create(&keys
[i
], trans_test_destructor
);
686 /* create some threads */
687 for (i
= 0; i
< NTSDTHREADS
; ++i
)
688 trans_test_threadcreate(&tta
[i
]);
690 /* wait for the threads to assign TSD */
691 for (i
= 0; i
< NTSDTHREADS
; ++i
)
692 trans_test_stepwait(&tta
[i
], 1);
694 /* destroy some of the keys */
695 tsd_destroy(&keys
[0]);
696 tsd_destroy(&keys
[NKEYS
- 1]);
697 tsd_destroy(&keys
[NKEYS
>> 1]);
698 tsd_destroy(&keys
[NKEYS
>> 1]);
700 /* wakeup the threads -- they check that the destroy took */
701 for (i
= 0; i
< NTSDTHREADS
; ++i
)
702 trans_test_step(&tta
[i
], 2);
704 /* wait for the threads to exit (also checks for TSD cleanup) */
705 for (i
= 0; i
< NTSDTHREADS
; ++i
)
706 trans_test_stepwait(&tta
[i
], 3);
708 /* destroy the rest of the keys */
709 for (i
= 0; i
< NKEYS
; ++i
)
710 tsd_destroy(&keys
[i
]);
712 /* check for error */
713 for (i
= 0; i
< NTSDTHREADS
; ++i
) {
715 error
= tta
[i
].error
;
716 mutex_destroy(&tta
[i
].lock
);
717 cv_destroy(&tta
[i
].cv
);
721 * test 6 -- test getcreate
726 /* make sure the keys are destroyed */
727 for (i
= 0; i
< NKEYS
; ++i
)
728 tsd_destroy(&keys
[i
]);
731 for (i
= 0; i
< NKEYS
; ++i
) {
733 if (*(int *)tsd_getcreate(&keys
[i
], trans_test_destructor_alloc
,
734 trans_test_allocator
) != allocatorvalue
) {
739 for (i
= 0; i
< NKEYS
; ++i
) {
741 if (*(int *)tsd_get(keys
[i
]) != allocatorvalue
) {
746 /* make sure destructor gets called when we destroy the keys */
747 for (i
= 0; i
< NKEYS
; ++i
) {
749 okdestructoralloc
= 0;
750 tsd_destroy(&keys
[i
]);
751 if (okdestructoralloc
== 0) {
758 /* make sure the keys are destroyed */
759 for (i
= 0; i
< NKEYS
; ++i
)
760 tsd_destroy(&keys
[i
]);
762 /* return test # and error code (if any) */
768 * Error Injection Structures, Data, and Functions:
770 * Error injection is used to test the Harpy error recovery system. The
771 * MD_IOC_INJECTERRORS ioctl is used to start or continue error injection on a
772 * unit, and MD_IOC_STOPERRORS turns it off. An mt_error structure is
773 * associated with every trans device for which we are injecting errors. When
774 * MD_IOC_INJECTERRORS is issued, mdv_strategy_tstpnt is set to point to
775 * trans_error_injector(), so that it gets called for every MDD I/O operation.
777 * The trans unit can be in one of three states:
779 * count down - Each I/O causes er_count_down to be decremented.
780 * When er_count_down reaches 0, an error is injected,
781 * the block number is remembered. Without makeing
782 * special provisions, the log area would receive a
783 * small percentage of the injected errors. Thus,
784 * trans_check_error() will be written, so that every
785 * other error is injected on the log.
787 * suspend - No errors are generated and the counters are not
788 * modified. This is so that fsck/mkfs can do their thing
789 * (we're not testing them) and so that the test script can
790 * set up another test. The transition back to the count
791 * down state occurs when MD_IOC_INJECTERRORS is invoked
801 typedef struct mt_error
{
802 struct mt_error
*er_next
; /* next error unit in list. */
804 mt_unit_t
*er_unitp
; /* unit to force errors on. */
805 size_t er_count_down
; /* i/o transactions until error. */
806 size_t er_increment
; /* increment for reset_count. */
807 size_t er_reset_count
; /* used to reset er_count_down */
808 size_t er_total_errors
; /* count generated errors. */
809 /* Following fields describe error we are injecting. */
810 dev_t er_bad_unit
; /* Unit associated with block in */
812 off_t er_bad_block
; /* Block in error. */
815 #define ERROR_INCREMENT (1)
816 #define INITIAL_COUNT (1)
818 static int default_increment
= ERROR_INCREMENT
;
819 static kmutex_t error_mutex
; /* protects error_list */
820 static mt_error_t error_list_head
;
821 static int initial_count
= INITIAL_COUNT
;
822 static int (*tstpnt_save
)(buf_t
*, int, void*) = NULL
;
825 find_by_mtunit(mt_unit_t
*un
, mt_error_t
**pred_errp
)
827 mt_error_t
*errp
= (mt_error_t
*)NULL
;
829 ASSERT(mutex_owned(&error_mutex
) != 0);
830 *pred_errp
= &error_list_head
;
831 while ((errp
= (*pred_errp
)->er_next
) != (mt_error_t
*)NULL
) {
832 if (errp
->er_unitp
== un
)
840 find_by_dev(md_dev64_t dev
)
842 mt_error_t
*errp
= &error_list_head
;
844 ASSERT(mutex_owned(&error_mutex
) != 0);
845 while ((errp
= errp
->er_next
) != (mt_error_t
*)NULL
) {
846 if ((errp
->er_unitp
->un_m_dev
== dev
) ||
847 (errp
->er_unitp
->un_l_dev
== dev
))
854 trans_check_error(buf_t
*bp
, mt_error_t
*errp
)
857 md_dev64_t target
= md_expldev(bp
->b_edev
);
859 ASSERT(mutex_owned(&error_mutex
) != 0);
860 switch (errp
->er_state
) {
862 errp
->er_count_down
--;
863 if (errp
->er_count_down
== 0) {
865 * Every other error that we inject should be on
866 * the log device. Errors will be injected on the
867 * log device when errp->er_total_errors is even
868 * and on the master device when it is odd. If
869 * this I/O is not for the appropriate device, we
870 * will set errp->er_count_down to 1, so that we
871 * can try again later.
873 if ((((errp
->er_total_errors
% 2) == 0) &&
874 (errp
->er_unitp
->un_l_dev
== target
)) ||
875 (((errp
->er_total_errors
% 2) != 0) &&
876 (errp
->er_unitp
->un_m_dev
== target
))) {
877 /* simulate an error */
878 bp
->b_flags
|= B_ERROR
;
880 /* remember the error. */
881 errp
->er_total_errors
++;
882 errp
->er_bad_unit
= bp
->b_edev
;
883 errp
->er_bad_block
= bp
->b_blkno
;
884 /* reset counters. */
885 errp
->er_count_down
= errp
->er_reset_count
;
886 errp
->er_reset_count
+= errp
->er_increment
;
889 /* Try again next time. */
890 errp
->er_count_down
= 1;
896 /* No errors while suspended. */
899 case mte_watch_block
:
900 if ((bp
->b_edev
== errp
->er_bad_unit
) &&
901 (bp
->b_blkno
== errp
->er_bad_block
)) {
902 bp
->b_flags
|= B_ERROR
;
912 trans_error_injector(buf_t
*bp
, int flag
, void* private)
914 mt_error_t
*errp
= (mt_error_t
*)NULL
;
915 int (*tstpnt
)(buf_t
*, int, void*) = NULL
;
917 md_dev64_t target
= md_expldev(bp
->b_edev
);
921 mutex_enter(&error_mutex
);
922 errp
= find_by_dev(target
);
923 if (errp
!= (mt_error_t
*)NULL
) {
925 if (target
== un
->un_m_dev
) {
926 /* Target is our master device. */
927 rv
= trans_check_error(bp
, errp
);
929 if (target
== un
->un_l_dev
) {
931 * Target is our log device. Unfortunately, the same
932 * device may also be used for the MDD database.
933 * Therefore, we need to make sure that the I/O is for
934 * the range of blocks designated as our log.
936 if ((bp
->b_blkno
>= un
->un_l_pwsblk
) &&
937 ((bp
->b_blkno
+ btodb(bp
->b_bcount
)) <=
938 (un
->un_l_sblk
+ un
->un_l_tblks
))) {
939 rv
= trans_check_error(bp
, errp
);
943 tstpnt
= tstpnt_save
;
944 mutex_exit(&error_mutex
);
947 trv
= (*tstpnt
)(bp
, flag
, private);
950 * If we are producing an error (rv != 0) we need to make sure that
951 * biodone gets called. If the tstpnt returned non-zero,
952 * we'll assume that it called biodone.
954 if ((rv
!= 0) && (trv
== 0)) {
957 rv
= ((rv
== 0) && (trv
== 0)) ? 0 : 1;
962 * Prepare to inject errors on the master and log devices associated with the
963 * unit specified in migp. The first time that trans_inject_errors() is called
964 * for a unit, an mt_error_t structure is allocated and initialized for the
965 * unit. Subsequent calls for the unit will just insure that the unit is in the
968 * If an mt_error structure is allocated and it is the first one to be put in
969 * the list, mdv_strategy_tstpnt (which is referenced in md_call_strategy()) is
970 * set to trans_error_injector so that it will be called to see if an I/O
971 * request should be treated as an error.
976 trans_inject_errors(void *d
, int mode
, IOLOCK
*lock
)
979 mt_error_t
*do_not_care
;
983 md_i_get_t
*migp
= d
;
985 mdclrerror(&migp
->mde
);
987 un
= trans_getun(migp
->id
, &migp
->mde
,
993 * If there is already a an error structure for the unit make sure that
994 * it is in count down mode.
997 mutex_enter(&error_mutex
);
998 errp
= find_by_mtunit(un
, &do_not_care
);
999 if (errp
!= (mt_error_t
*)NULL
) {
1000 errp
->er_state
= mte_count_down
;
1004 * Initialize error structure.
1007 errp
= (mt_error_t
*)md_trans_zalloc(sizeof (mt_error_t
));
1008 errp
->er_state
= mte_count_down
;
1009 errp
->er_unitp
= un
;
1010 errp
->er_count_down
= initial_count
;
1011 errp
->er_increment
= default_increment
;
1012 errp
->er_reset_count
= initial_count
;
1013 errp
->er_total_errors
= 0;
1014 errp
->er_bad_unit
= 0;
1015 errp
->er_bad_block
= 0;
1017 /* Insert it into the list. */
1019 errp
->er_next
= error_list_head
.er_next
;
1020 error_list_head
.er_next
= errp
;
1023 * Set up md_call_strategy to call our error injector.
1026 if (mdv_strategy_tstpnt
!= trans_error_injector
) {
1027 tstpnt_save
= mdv_strategy_tstpnt
;
1028 mdv_strategy_tstpnt
= trans_error_injector
;
1031 mutex_exit(&error_mutex
);
1037 trans_stop_errors(void *d
, int mode
, IOLOCK
*lock
)
1039 mt_error_t
*errp
= (mt_error_t
*)NULL
;
1040 mt_error_t
*pred_errp
;
1044 md_i_get_t
*migp
= d
;
1046 mdclrerror(&migp
->mde
);
1048 un
= trans_getun(migp
->id
, &migp
->mde
,
1053 mutex_enter(&error_mutex
);
1054 errp
= find_by_mtunit(un
, &pred_errp
);
1055 if (errp
!= (mt_error_t
*)NULL
) {
1056 /* Remove from list. */
1057 pred_errp
->er_next
= errp
->er_next
;
1058 if ((error_list_head
.er_next
== (mt_error_t
*)NULL
) &&
1059 (mdv_strategy_tstpnt
== trans_error_injector
)) {
1060 mdv_strategy_tstpnt
= tstpnt_save
;
1063 /* unit not set up for errors. */
1066 mutex_exit(&error_mutex
);
1070 if (errp
!= (mt_error_t
*)NULL
) {
1071 md_trans_free((void *)errp
, sizeof (*errp
));
1079 mutex_init(&error_mutex
, NULL
, MUTEX_DRIVER
, (void *)NULL
);
1086 mutex_destroy(&error_mutex
);
1091 * END OF DEBUG ROUTINES
1095 * BEGIN RELEASE DEBUG
1096 * The following routines remain in the released product for testability
1100 * ufs error injection remains in the released product
1104 trans_ufserror(void *d
, int mode
, IOLOCK
*lock
)
1108 md_i_get_t
*migp
= d
;
1110 mdclrerror(&migp
->mde
);
1112 un
= trans_getun(migp
->id
, &migp
->mde
,
1114 if (un
== NULL
|| un
->un_ut
== NULL
)
1120 * shadow test remains in the released product
1123 trans_set_shadow(void *d
, int mode
, IOLOCK
*lock
)
1125 dev32_t device
; /* shadow device */
1128 md_i_get_t
*migp
= d
;
1130 mdclrerror(&migp
->mde
);
1132 un
= trans_getun(migp
->id
, &migp
->mde
,
1137 if ((un
->un_debug
& MT_SHADOW
) == 0)
1140 /* Get shadow device. User always passes down 32 bit devt */
1142 if (ddi_copyin((caddr_t
)(uintptr_t)migp
->mdp
,
1143 &device
, sizeof (device
), mode
)) {
1147 /* Save shadow device designator. */
1148 un
->un_s_dev
= md_expldev((md_dev64_t
)device
);
1157 trans_get(void *d
, int mode
, IOLOCK
*lock
)
1162 md_i_get_t
*migp
= d
;
1164 mdclrerror(&migp
->mde
);
1166 un
= trans_getun(migp
->id
, &migp
->mde
,
1171 if (migp
->size
== 0) {
1172 migp
->size
= un
->c
.un_size
;
1176 if (migp
->size
< un
->c
.un_size
)
1185 * refresh log fields in case log was metattach'ed
1187 un
->un_l_head
= (daddr32_t
)btodb(ul
->un_head_lof
);
1188 un
->un_l_sblk
= un
->un_l_head
;
1189 un
->un_l_pwsblk
= ul
->un_pwsblk
;
1190 un
->un_l_maxtransfer
= (uint_t
)btodb(ul
->un_maxtransfer
);
1191 un
->un_l_nblks
= ul
->un_nblks
;
1192 un
->un_l_tblks
= ul
->un_tblks
;
1193 un
->un_l_tail
= (daddr32_t
)btodb(ul
->un_tail_lof
);
1194 un
->un_l_resv
= ul
->un_resv
;
1195 un
->un_l_maxresv
= ul
->un_maxresv
;
1196 un
->un_l_error
= ul
->un_error
;
1197 un
->un_l_timestamp
= ul
->un_timestamp
;
1200 * check for log dev dynconcat; can only pick up extra space when the
1201 * tail physically follows the head in the circular log
1203 if (un
->un_l_head
<= un
->un_l_tail
)
1204 if (ul
->un_status
& LDL_METADEVICE
) {
1205 struct mdc_unit
*c
= MD_UNIT(md_getminor(ul
->un_dev
));
1207 if (c
->un_total_blocks
> un
->un_l_tblks
) {
1208 un
->un_l_tblks
= c
->un_total_blocks
;
1209 un
->un_l_nblks
= un
->un_l_tblks
- un
->un_l_sblk
;
1210 if (un
->un_l_nblks
> btodb(LDL_MAXLOGSIZE
))
1211 un
->un_l_nblks
= btodb(LDL_MAXLOGSIZE
);
1212 un
->un_l_maxresv
= (uint_t
)(un
->un_l_nblks
*
1219 if (ddi_copyout(un
, (void *)(uintptr_t)migp
->mdp
, un
->c
.un_size
, mode
))
1225 trans_replace(replace_params_t
*params
)
1227 minor_t mnum
= params
->mnum
;
1234 mdclrerror(¶ms
->mde
);
1236 ui
= MDI_UNIT(mnum
);
1237 un
= md_unit_writerlock(ui
);
1239 if (MD_STATUS(un
) & MD_UN_RESYNC_ACTIVE
) {
1240 return (mdmderror(¶ms
->mde
, MDE_RESYNC_ACTIVE
, mnum
));
1243 cmp_dev
= params
->old_dev
;
1244 mdev
= un
->un_m_dev
;
1245 ldev
= un
->un_l_dev
;
1246 if (cmp_dev
== mdev
) {
1247 un
->un_m_key
= params
->new_key
;
1248 un
->un_m_dev
= params
->new_dev
;
1249 } else if (cmp_dev
== ldev
) {
1250 un
->un_l_key
= params
->new_key
;
1251 un
->un_l_dev
= params
->new_dev
;
1254 trans_commit(un
, 1);
1255 md_unit_writerexit(ui
);
1261 trans_grow(void *d
, int mode
, IOLOCK
*lock
)
1265 md_grow_params_t
*mgp
= d
;
1267 mdclrerror(&mgp
->mde
);
1269 un
= trans_getun(mgp
->mnum
, &mgp
->mde
,
1275 * check for master dev dynconcat
1277 if (md_getmajor(un
->un_m_dev
) == md_major
) {
1280 c
= MD_UNIT(md_getminor(un
->un_m_dev
));
1281 if (c
->un_total_blocks
> MD_MAX_BLKS_FOR_SMALL_DEVS
) {
1282 un
->c
.un_total_blocks
= MD_MAX_BLKS_FOR_SMALL_DEVS
;
1284 un
->c
.un_total_blocks
= c
->un_total_blocks
;
1286 md_nblocks_set(MD_SID(un
), un
->c
.un_total_blocks
);
1294 trans_detach_ioctl(void *d
, int mode
, IOLOCK
*lock
)
1299 md_i_get_t
*migp
= d
;
1301 mdclrerror(&migp
->mde
);
1303 /* acquire both md_unit_array_rw, and unit_reader lock */
1304 un
= trans_getun(migp
->id
, &migp
->mde
,
1310 * simply too much work to make debug modes w/out a log
1318 error
= trans_detach(un
, migp
->size
);
1324 trans_get_log(void *d
, int mode
, IOLOCK
*lock
)
1329 md_i_get_t
*migp
= d
;
1331 mdclrerror(&migp
->mde
);
1333 un
= trans_getun(migp
->id
, &migp
->mde
, RD_LOCK
, lock
);
1340 if (migp
->size
== 0) {
1341 migp
->size
= ML_UNIT_ONDSZ
;
1345 if (migp
->size
< ML_UNIT_ONDSZ
)
1348 if (ddi_copyout(ul
, (void *)(uintptr_t)migp
->mdp
, ML_UNIT_ONDSZ
,
1355 trans_getdevs(void *d
, int mode
, IOLOCK
*lock
)
1360 md_dev64_t unit_dev
;
1362 md_getdevs_params_t
*mgdp
= d
;
1364 mdclrerror(&mgdp
->mde
);
1366 un
= trans_getun(mgdp
->mnum
, &mgdp
->mde
, RD_LOCK
, lock
);
1370 ndev
= (un
->un_flags
& (TRANS_DETACHED
| TRANS_ATTACHING
)) ? 1 : 2;
1372 if (mgdp
->cnt
== 0) {
1380 udevs
= (md_dev64_t
*)(uintptr_t)mgdp
->devs
;
1381 unit_dev
= un
->un_m_dev
;
1383 if (md_getmajor(unit_dev
) != md_major
) {
1384 if ((unit_dev
= md_xlate_mini_2_targ(unit_dev
)) == NODEV64
)
1389 if (ddi_copyout(&unit_dev
, (caddr_t
)&udevs
[0],
1390 sizeof (*udevs
), mode
) != 0)
1393 unit_dev
= un
->un_l_dev
;
1394 if (md_getmajor(unit_dev
) != md_major
) {
1395 if ((unit_dev
= md_xlate_mini_2_targ(unit_dev
)) == NODEV64
)
1400 if (ddi_copyout(&unit_dev
, (caddr_t
)&udevs
[1],
1401 sizeof (*udevs
), mode
) != 0)
1408 trans_reset_ioctl(md_i_reset_t
*mirp
, IOLOCK
*lock
)
1410 minor_t mnum
= mirp
->mnum
;
1414 mdclrerror(&mirp
->mde
);
1416 un
= trans_getun(mnum
, &mirp
->mde
, NO_LOCK
, lock
);
1421 /* This prevents new opens */
1422 rw_enter(&md_unit_array_rw
.lock
, RW_WRITER
);
1424 if (MD_HAS_PARENT(MD_PARENT(un
))) {
1425 rw_exit(&md_unit_array_rw
.lock
);
1426 return (mdmderror(&mirp
->mde
, MDE_IN_USE
, mnum
));
1429 if (md_unit_isopen(MDI_UNIT(mnum
))) {
1430 rw_exit(&md_unit_array_rw
.lock
);
1431 return (mdmderror(&mirp
->mde
, MDE_IS_OPEN
, mnum
));
1436 error
= trans_detach(un
, mirp
->force
);
1439 * reset (aka remove; aka delete) the trans device
1442 error
= trans_reset(un
, mnum
, 1, mirp
->force
);
1444 rw_exit(&md_unit_array_rw
.lock
);
1449 trans_get_geom(mt_unit_t
*un
, struct dk_geom
*geomp
)
1451 md_get_geom((md_unit_t
*)un
, geomp
);
1457 trans_get_vtoc(mt_unit_t
*un
, struct vtoc
*vtocp
)
1459 md_get_vtoc((md_unit_t
*)un
, vtocp
);
1465 trans_get_extvtoc(mt_unit_t
*un
, struct extvtoc
*vtocp
)
1467 md_get_extvtoc((md_unit_t
*)un
, vtocp
);
1473 trans_islog(mt_unit_t
*un
)
1475 if (un
->un_l_unit
== NULL
)
1486 return (md_set_vtoc((md_unit_t
*)un
, vtocp
));
1490 trans_set_extvtoc(mt_unit_t
*un
, struct extvtoc
*vtocp
)
1492 return (md_set_extvtoc((md_unit_t
*)un
, vtocp
));
1498 struct dk_map
*dkmapp
1501 md_get_cgapart((md_unit_t
*)un
, dkmapp
);
1506 trans_admin_ioctl(int cmd
, void *data
, int mode
, IOLOCK
*lockp
)
1512 /* We can only handle 32-bit clients for internal commands */
1513 if ((mode
& DATAMODEL_MASK
) != DATAMODEL_ILP32
) {
1521 if (! (mode
& FREAD
))
1524 sz
= sizeof (md_i_get_t
);
1526 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1529 if (ddi_copyin(data
, d
, sz
, mode
)) {
1534 err
= trans_get(d
, mode
, lockp
);
1540 if (! (mode
& FREAD
))
1543 sz
= sizeof (md_i_get_t
);
1545 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1548 if (ddi_copyin(data
, d
, sz
, mode
)) {
1553 err
= trans_get_log(d
, mode
, lockp
);
1561 if (! (mode
& FWRITE
))
1564 if ((d
= p
= md_trans_zalloc((sz
= sizeof (*p
)))) == NULL
)
1567 if (ddi_copyin(data
, d
, sz
, mode
)) {
1572 err
= trans_reset_ioctl(p
, lockp
);
1578 if (! (mode
& FWRITE
))
1581 sz
= sizeof (md_grow_params_t
);
1583 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1586 if (ddi_copyin(data
, d
, sz
, mode
)) {
1591 err
= trans_grow(d
, mode
, lockp
);
1595 case MD_IOC_TRANS_DETACH
:
1597 if (! (mode
& FWRITE
))
1600 sz
= sizeof (md_i_get_t
);
1602 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1605 if (ddi_copyin(data
, d
, sz
, mode
)) {
1610 err
= trans_detach_ioctl(d
, mode
, lockp
);
1616 replace_params_t
*p
;
1618 if (! (mode
& FWRITE
))
1621 if ((d
= p
= kmem_alloc((sz
= sizeof (*p
)), KM_SLEEP
)) == NULL
)
1624 if (ddi_copyin(data
, d
, sz
, mode
)) {
1629 err
= trans_replace(p
);
1634 case MD_IOCGET_DEVS
:
1636 if (! (mode
& FREAD
))
1639 sz
= sizeof (md_getdevs_params_t
);
1641 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1644 if (ddi_copyin(data
, d
, sz
, mode
)) {
1649 err
= trans_getdevs(d
, mode
, lockp
);
1659 case MD_IOCGET_TRANSSTATS
:
1661 if (! (mode
& FREAD
))
1664 sz
= sizeof (md_i_get_t
);
1666 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1669 if (ddi_copyin(data
, d
, sz
, mode
)) {
1674 err
= trans_get_transstats(d
, mode
);
1682 if (! (mode
& FWRITE
))
1685 sz
= sizeof (md_i_get_t
);
1687 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1690 if (ddi_copyin(data
, d
, sz
, mode
)) {
1697 mdclrerror(&mdigp
->mde
);
1698 mt_debug
= mdigp
->size
;
1704 if (! (mode
& FWRITE
))
1708 sz
= sizeof (md_i_get_t
);
1710 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1713 if (ddi_copyin(data
, d
, sz
, mode
)) {
1718 err
= trans_test_tsd(d
, mode
);
1722 case MD_IOC_TRYGETBLK
:
1724 if (! (mode
& FWRITE
))
1728 sz
= sizeof (md_i_get_t
);
1730 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1733 if (ddi_copyin(data
, d
, sz
, mode
)) {
1738 err
= trans_test_trygetblk(d
, mode
, lockp
);
1742 case MD_IOC_TRYPAGE
:
1744 if (! (mode
& FWRITE
))
1748 sz
= sizeof (md_i_get_t
);
1750 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1753 if (ddi_copyin(data
, d
, sz
, mode
)) {
1758 err
= trans_test_trypage(d
, mode
, lockp
);
1763 case MD_IOC_INJECTERRORS
:
1765 if (! (mode
& FWRITE
))
1769 sz
= sizeof (md_i_get_t
);
1771 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1774 if (ddi_copyin(data
, d
, sz
, mode
)) {
1779 err
= trans_inject_errors(d
, mode
, lockp
);
1783 case MD_IOC_STOPERRORS
:
1785 if (! (mode
& FWRITE
))
1789 sz
= sizeof (md_i_get_t
);
1791 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1794 if (ddi_copyin(data
, d
, sz
, mode
)) {
1799 err
= trans_stop_errors(d
, mode
, lockp
);
1803 case MD_IOC_ISDEBUG
:
1808 case MD_IOC_ISDEBUG
:
1809 case MD_IOCGET_TRANSSTATS
:
1810 case MD_IOC_STOPERRORS
:
1812 case MD_IOC_TRYGETBLK
:
1813 case MD_IOC_TRYPAGE
:
1817 * error injection behaves like MD_IOC_UFSERROR in released product
1819 case MD_IOC_INJECTERRORS
:
1821 if (! (mode
& FWRITE
))
1825 sz
= sizeof (md_i_get_t
);
1827 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1830 if (ddi_copyin(data
, d
, sz
, mode
)) {
1835 err
= trans_ufserror(d
, mode
, lockp
);
1840 * only the shadow test is allowed in the released product
1846 if (! (mode
& FWRITE
))
1849 sz
= sizeof (md_i_get_t
);
1851 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1854 if (ddi_copyin(data
, d
, sz
, mode
)) {
1861 mdclrerror(&mdigp
->mde
);
1862 mt_debug
= mdigp
->size
& MT_SHADOW
;
1866 #endif /* ! DEBUG */
1869 * BEGIN RELEASE DEBUG
1870 * The following routines remain in the released product for testability
1873 case MD_IOC_UFSERROR
:
1875 if (! (mode
& FWRITE
))
1878 sz
= sizeof (md_i_get_t
);
1880 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1883 if (ddi_copyin(data
, d
, sz
, mode
)) {
1888 err
= trans_ufserror(d
, mode
, lockp
);
1892 case MD_IOC_SETSHADOW
:
1894 if (! (mode
& FWRITE
))
1897 sz
= sizeof (md_i_get_t
);
1899 if ((d
= md_trans_zalloc(sz
)) == NULL
)
1902 if (ddi_copyin(data
, d
, sz
, mode
)) {
1907 err
= trans_set_shadow(d
, mode
, lockp
);
1921 * copyout and free any args
1925 if (ddi_copyout(d
, data
, sz
, mode
) != 0) {
1929 md_trans_free(d
, sz
);
1935 md_trans_ioctl(dev_t dev
, int cmd
, void *data
, int mode
, IOLOCK
*lockp
)
1937 minor_t mnum
= getminor(dev
);
1939 md_error_t mde
= mdnullerror
;
1942 /* handle admin ioctls */
1943 if (mnum
== MD_ADM_MINOR
)
1944 return (trans_admin_ioctl(cmd
, data
, mode
, lockp
));
1947 if ((MD_MIN2SET(mnum
) >= md_nsets
) ||
1948 (MD_MIN2UNIT(mnum
) >= md_nunits
) ||
1949 ((un
= trans_getun(mnum
, &mde
, RD_LOCK
, lockp
)) == NULL
))
1952 /* dispatch ioctl */
1959 if (! (mode
& FREAD
))
1962 if ((p
= md_trans_zalloc(sizeof (*p
))) == NULL
)
1966 if (ddi_copyout((caddr_t
)p
, data
, sizeof (*p
), mode
) != 0)
1969 md_trans_free(p
, sizeof (*p
));
1977 if (! (mode
& FREAD
))
1980 if ((p
= md_trans_zalloc(sizeof (*p
))) == NULL
)
1983 if ((err
= trans_get_geom(un
, p
)) == 0) {
1984 if (ddi_copyout((caddr_t
)p
, data
, sizeof (*p
),
1989 md_trans_free(p
, sizeof (*p
));
1997 if (! (mode
& FREAD
))
2000 vtoc
= kmem_zalloc(sizeof (*vtoc
), KM_SLEEP
);
2001 if ((err
= trans_get_vtoc(un
, vtoc
)) != 0) {
2002 kmem_free(vtoc
, sizeof (*vtoc
));
2006 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_NATIVE
) {
2007 if (ddi_copyout(vtoc
, data
, sizeof (*vtoc
), mode
))
2012 struct vtoc32
*vtoc32
;
2014 vtoc32
= kmem_zalloc(sizeof (*vtoc32
), KM_SLEEP
);
2016 vtoctovtoc32((*vtoc
), (*vtoc32
));
2017 if (ddi_copyout(vtoc32
, data
, sizeof (*vtoc32
), mode
))
2019 kmem_free(vtoc32
, sizeof (*vtoc32
));
2021 #endif /* _SYSCALL32 */
2023 kmem_free(vtoc
, sizeof (*vtoc
));
2031 if (! (mode
& FWRITE
))
2034 vtoc
= kmem_zalloc(sizeof (*vtoc
), KM_SLEEP
);
2035 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_NATIVE
) {
2036 if (ddi_copyin(data
, vtoc
, sizeof (*vtoc
), mode
)) {
2042 struct vtoc32
*vtoc32
;
2044 vtoc32
= kmem_zalloc(sizeof (*vtoc32
), KM_SLEEP
);
2046 if (ddi_copyin(data
, vtoc32
, sizeof (*vtoc32
), mode
)) {
2049 vtoc32tovtoc((*vtoc32
), (*vtoc
));
2051 kmem_free(vtoc32
, sizeof (*vtoc32
));
2053 #endif /* _SYSCALL32 */
2056 err
= trans_set_vtoc(un
, vtoc
);
2058 kmem_free(vtoc
, sizeof (*vtoc
));
2065 struct extvtoc
*extvtoc
;
2067 if (! (mode
& FREAD
))
2070 extvtoc
= kmem_zalloc(sizeof (*extvtoc
), KM_SLEEP
);
2071 if ((err
= trans_get_extvtoc(un
, extvtoc
)) != 0) {
2075 if (ddi_copyout(extvtoc
, data
, sizeof (*extvtoc
), mode
))
2078 kmem_free(extvtoc
, sizeof (*extvtoc
));
2084 struct extvtoc
*extvtoc
;
2086 if (! (mode
& FWRITE
))
2089 extvtoc
= kmem_zalloc(sizeof (*extvtoc
), KM_SLEEP
);
2090 if (ddi_copyin(data
, extvtoc
, sizeof (*extvtoc
), mode
)) {
2095 err
= trans_set_extvtoc(un
, extvtoc
);
2097 kmem_free(extvtoc
, sizeof (*extvtoc
));
2105 if ((err
= trans_get_cgapart(un
, &dmp
)) != 0) {
2109 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_NATIVE
) {
2110 if (ddi_copyout((caddr_t
)&dmp
, data
, sizeof (dmp
),
2116 struct dk_map32 dmp32
;
2118 dmp32
.dkl_cylno
= dmp
.dkl_cylno
;
2119 dmp32
.dkl_nblk
= dmp
.dkl_nblk
;
2121 if (ddi_copyout((caddr_t
)&dmp32
, data
, sizeof (dmp32
),
2125 #endif /* _SYSCALL32 */
2131 * _FIOISLOG, _FIOISLOGOK, _FIOLOGRESET are used by fsck/mkfs
2132 * after opening the device. fsck/mkfs use these ioctls for
2136 return (trans_islog(un
));
2144 * rename named service entry points and support functions
2147 /* rename/exchange role swap functions */
2151 * This role swap function is identical for all unit types,
2152 * so keep it here. It's also the best example because it
2153 * touches all the modified portions of the relevant
2154 * in-common structures.
2157 trans_rename_update_self(
2158 md_rendelta_t
*delta
,
2161 minor_t from_min
, to_min
;
2166 ASSERT(rtxnp
->op
== MDRNOP_RENAME
);
2170 ASSERT(rtxnp
->rec_idx
>= 0);
2171 ASSERT(rtxnp
->recids
);
2172 ASSERT(delta
->old_role
== MDRR_SELF
);
2173 ASSERT(delta
->new_role
== MDRR_SELF
);
2175 from_min
= rtxnp
->from
.mnum
;
2176 to_min
= rtxnp
->to
.mnum
;
2177 un
= (mt_unit_t
*)delta
->unp
;
2180 * self id changes in our own unit struct
2181 * both mechanisms for identifying the trans must be reset.
2184 MD_SID(delta
->unp
) = to_min
;
2185 un
->un_dev
= makedevice(md_major
, to_min
);
2188 * clear old array pointers to unit in-core and unit
2191 MDI_VOIDUNIT(from_min
) = NULL
;
2192 MD_VOIDUNIT(from_min
) = NULL
;
2195 * and point the new slots at the unit in-core and unit structs
2198 MDI_VOIDUNIT(to_min
) = delta
->uip
;
2199 MD_VOIDUNIT(to_min
) = delta
->unp
;
2204 md_kstat_destroy_ui(delta
->uip
);
2205 md_kstat_init_ui(to_min
, delta
->uip
);
2208 * the unit in-core reference to the get next link's id changes
2211 delta
->uip
->ui_link
.ln_id
= to_min
;
2214 * name space addition of new key was done from user-level
2215 * remove the old name's key here
2218 sv
.setno
= MD_MIN2SET(from_min
);
2219 sv
.key
= rtxnp
->from
.key
;
2221 md_rem_names(&sv
, 1);
2225 * and store the record id (from the unit struct) into recids
2226 * for later commitment by md_rename()
2229 md_store_recid(&rtxnp
->rec_idx
, rtxnp
->recids
, delta
->unp
);
2234 * rename/exchange of our child or grandchild
2237 trans_renexch_update_kids(
2238 md_rendelta_t
*delta
,
2242 minor_t from_min
, to_min
, log_min
, master_min
;
2246 ASSERT((rtxnp
->op
== MDRNOP_RENAME
) || (rtxnp
->op
== MDRNOP_EXCHANGE
));
2248 ASSERT(rtxnp
->recids
);
2249 ASSERT(rtxnp
->rec_idx
>= 0);
2250 ASSERT(delta
->old_role
== MDRR_PARENT
);
2251 ASSERT(delta
->new_role
== MDRR_PARENT
);
2253 un
= (mt_unit_t
*)delta
->unp
;
2254 from_min
= rtxnp
->from
.mnum
;
2255 to_min
= rtxnp
->to
.mnum
;
2256 log_min
= md_getminor(un
->un_l_dev
);
2257 master_min
= md_getminor(un
->un_m_dev
);
2260 * since our role isn't changing (parent->parent)
2261 * one of our children must be changing; which one is it?
2262 * find the child being modified, and update
2266 /* both devices must be metadevices in order to be updated */
2267 ASSERT(md_getmajor(un
->un_m_dev
) == md_major
);
2268 ASSERT(!(un
->un_l_unit
&& (md_getmajor(un
->un_l_dev
) != md_major
)));
2270 if ((md_getmajor(un
->un_m_dev
) == md_major
) &&
2271 (master_min
== from_min
)) {
2273 ASSERT(!(un
->un_l_unit
&& (log_min
== from_min
)));
2275 un
->un_m_dev
= makedevice(md_major
, to_min
);
2276 un
->un_m_key
= rtxnp
->to
.key
;
2278 } else if ((md_getmajor(un
->un_m_dev
) == md_major
) &&
2279 un
->un_l_unit
&& (log_min
== from_min
)) {
2281 ASSERT(master_min
!= from_min
);
2283 un
->un_l_dev
= makedevice(md_major
, to_min
);
2284 un
->un_l_key
= rtxnp
->to
.key
;
2288 panic("trans_renexch_update_kids: not a metadevice");
2292 md_store_recid(&rtxnp
->rec_idx
, rtxnp
->recids
, delta
->unp
);
2296 * MDRNM_SELF_UPDATE_FROM (exchange down) [self->child]
2299 trans_exchange_self_update_from_down(
2300 md_rendelta_t
*delta
,
2304 minor_t from_min
, to_min
, master_min
, log_min
;
2311 ASSERT(MDRNOP_EXCHANGE
== rtxnp
->op
);
2312 ASSERT(rtxnp
->from
.uip
);
2313 ASSERT(rtxnp
->rec_idx
>= 0);
2314 ASSERT(rtxnp
->recids
);
2315 ASSERT(delta
->old_role
== MDRR_SELF
);
2316 ASSERT(delta
->new_role
== MDRR_CHILD
);
2317 ASSERT(md_getminor(delta
->dev
) == rtxnp
->from
.mnum
);
2319 un
= (mt_unit_t
*)delta
->unp
;
2322 * if we're exchanging a trans, it had better be a metadevice
2324 ASSERT(md_getmajor(un
->un_m_dev
) == md_major
);
2326 to_min
= rtxnp
->to
.mnum
;
2327 from_min
= rtxnp
->from
.mnum
;
2328 master_min
= md_getminor(un
->un_m_dev
);
2329 log_min
= md_getminor(un
->un_l_dev
);
2332 * both mechanisms for identifying a trans must be updated
2335 MD_SID(delta
->unp
) = to_min
;
2336 un
->un_dev
= makedevice(md_major
, to_min
);
2339 * parent identifier need not change
2343 * point the set array pointers at the "new" unit and unit in-cores
2344 * Note: the other half of this transfer is done in the "update to"
2345 * rename/exchange named service.
2348 MDI_VOIDUNIT(to_min
) = delta
->uip
;
2349 MD_VOIDUNIT(to_min
) = delta
->unp
;
2355 delta
->uip
->ui_kstat
= rtxnp
->to
.kstatp
;
2358 * the unit in-core reference to the get next link's id changes
2361 delta
->uip
->ui_link
.ln_id
= to_min
;
2364 * which one of our children is changing?
2366 * Note that the check routines forbid changing the log (for now)
2367 * because there's no lockfs-like trans-ufs "freeze and remount"
2368 * or "freeze and bobbit the log."
2371 /* both devices must be metadevices in order to be updated */
2372 ASSERT(md_getmajor(un
->un_m_dev
) == md_major
);
2373 ASSERT(!(un
->un_l_unit
&& (md_getmajor(un
->un_l_dev
) != md_major
)));
2375 if ((md_getmajor(un
->un_m_dev
) == md_major
) &&
2376 (master_min
== to_min
)) {
2378 /* master and log can't both be changed */
2379 ASSERT(!(un
->un_l_unit
&& (log_min
== to_min
)));
2381 un
->un_m_dev
= makedevice(md_major
, from_min
);
2382 sv
.key
= un
->un_m_key
;
2383 un
->un_m_key
= rtxnp
->from
.key
;
2385 } else if ((md_getmajor(un
->un_m_dev
) == md_major
) &&
2386 un
->un_l_unit
&& (log_min
== to_min
)) {
2388 /* master and log can't both be changed */
2389 ASSERT(!(master_min
== to_min
));
2391 un
->un_l_dev
= makedevice(md_major
, from_min
);
2392 sv
.key
= un
->un_l_key
;
2393 un
->un_l_key
= rtxnp
->from
.key
;
2397 panic("trans_exchange_self_update_from_down: not a metadevice");
2402 * the new master must exist in the name space
2404 ASSERT(rtxnp
->from
.key
!= MD_KEYWILD
);
2405 ASSERT(rtxnp
->from
.key
!= MD_KEYBAD
);
2408 * delete the key for the changed child from the namespace
2411 sv
.setno
= MD_MIN2SET(from_min
);
2412 md_rem_names(&sv
, 1);
2415 * and store the record id (from the unit struct) into recids
2418 md_store_recid(&rtxnp
->rec_idx
, rtxnp
->recids
, delta
->unp
);
2422 * MDRNM_PARENT_UPDATE_TO (exchange down) [parent->self]
2425 trans_exchange_parent_update_to(
2426 md_rendelta_t
*delta
,
2430 minor_t from_min
, to_min
, master_min
, log_min
;
2437 ASSERT(MDRNOP_EXCHANGE
== rtxnp
->op
);
2438 ASSERT(rtxnp
->from
.uip
);
2439 ASSERT(rtxnp
->rec_idx
>= 0);
2440 ASSERT(rtxnp
->recids
);
2441 ASSERT(delta
->old_role
== MDRR_PARENT
);
2442 ASSERT(delta
->new_role
== MDRR_SELF
);
2443 ASSERT(md_getminor(delta
->dev
) == rtxnp
->to
.mnum
);
2445 un
= (mt_unit_t
*)delta
->unp
;
2447 ASSERT(md_getmajor(un
->un_m_dev
) == md_major
);
2449 to_min
= rtxnp
->to
.mnum
;
2450 from_min
= rtxnp
->from
.mnum
;
2451 master_min
= md_getminor(un
->un_m_dev
);
2452 log_min
= md_getminor(un
->un_l_dev
);
2455 * both mechanisms for identifying a trans must be updated
2458 MD_SID(delta
->unp
) = from_min
;
2459 un
->un_dev
= makedevice(md_major
, from_min
);
2462 * parent identifier need not change
2466 * point the set array pointers at the "new" unit and unit in-cores
2467 * Note: the other half of this transfer is done in the "update to"
2468 * rename/exchange named service.
2471 MDI_VOIDUNIT(from_min
) = delta
->uip
;
2472 MD_VOIDUNIT(from_min
) = delta
->unp
;
2478 delta
->uip
->ui_kstat
= rtxnp
->from
.kstatp
;
2481 * the unit in-core reference to the get next link's id changes
2484 delta
->uip
->ui_link
.ln_id
= from_min
;
2487 * which one of our children is changing?
2490 /* both devices must be metadevices in order to be updated */
2491 ASSERT(md_getmajor(un
->un_m_dev
) == md_major
);
2492 ASSERT(!(un
->un_l_unit
&& (md_getmajor(un
->un_l_dev
) != md_major
)));
2494 if ((md_getmajor(un
->un_m_dev
) == md_major
) &&
2495 (master_min
== from_min
)) {
2497 /* can't be changing log and master */
2498 ASSERT(!(un
->un_l_unit
&& (log_min
== to_min
)));
2500 un
->un_m_dev
= makedevice(md_major
, to_min
);
2501 sv
.key
= un
->un_m_key
;
2502 un
->un_m_key
= rtxnp
->to
.key
;
2504 } else if (un
->un_l_unit
&&
2505 ((md_getmajor(un
->un_l_dev
) == md_major
) && log_min
== to_min
)) {
2507 /* can't be changing log and master */
2508 ASSERT(master_min
!= from_min
);
2510 un
->un_l_dev
= makedevice(md_major
, to_min
);
2511 sv
.key
= un
->un_l_key
;
2512 un
->un_l_key
= rtxnp
->to
.key
;
2516 panic("trans_exchange_parent_update_to: not a metadevice");
2521 * delete the key for the changed child from the namespace
2524 sv
.setno
= MD_MIN2SET(from_min
);
2525 md_rem_names(&sv
, 1);
2528 * and store the record id (from the unit struct) into recids
2531 md_store_recid(&rtxnp
->rec_idx
, rtxnp
->recids
, delta
->unp
);
2535 * MDRNM_LIST_URKIDS: named svc entry point
2536 * all all delta entries appropriate for our children onto the
2537 * deltalist pointd to by dlpp
2540 trans_rename_listkids(
2541 md_rendelta_t
**dlpp
,
2544 minor_t from_min
, to_min
, master_min
, log_min
;
2546 md_rendelta_t
*new, *p
;
2551 ASSERT((rtxnp
->op
== MDRNOP_EXCHANGE
) || (rtxnp
->op
== MDRNOP_RENAME
));
2553 from_min
= rtxnp
->from
.mnum
;
2554 to_min
= rtxnp
->to
.mnum
;
2557 if (!MDI_UNIT(from_min
) || !(from_un
= MD_UNIT(from_min
))) {
2558 (void) mdmderror(&rtxnp
->mde
, MDE_UNIT_NOT_SETUP
, from_min
);
2562 for (p
= *dlpp
; p
&& p
->next
!= NULL
; p
= p
->next
) {
2566 if (md_getmajor(from_un
->un_m_dev
) == md_major
) {
2568 master_min
= md_getminor(from_un
->un_m_dev
);
2570 p
= new = md_build_rendelta(MDRR_CHILD
,
2571 to_min
== master_min
? MDRR_SELF
: MDRR_CHILD
,
2572 from_un
->un_m_dev
, p
, MD_UNIT(master_min
),
2573 MDI_UNIT(master_min
), &rtxnp
->mde
);
2576 if (mdisok(&rtxnp
->mde
)) {
2577 (void) mdsyserror(&rtxnp
->mde
, ENOMEM
);
2584 if (from_un
->un_l_unit
&&
2585 (md_getmajor(from_un
->un_l_dev
) == md_major
)) {
2587 log_min
= md_getminor(from_un
->un_l_dev
);
2589 new = md_build_rendelta(MDRR_CHILD
,
2590 to_min
== log_min
? MDRR_SELF
: MDRR_CHILD
,
2591 from_un
->un_l_dev
, p
, MD_UNIT(log_min
),
2592 MDI_UNIT(log_min
), &rtxnp
->mde
);
2594 if (mdisok(&rtxnp
->mde
)) {
2595 (void) mdsyserror(&rtxnp
->mde
, ENOMEM
);
2602 return (n_children
);
2606 * support routine for MDRNM_CHECK
2609 trans_may_renexch_self(
2618 ASSERT((rtxnp
->op
== MDRNOP_RENAME
) || (rtxnp
->op
== MDRNOP_EXCHANGE
));
2620 from_min
= rtxnp
->from
.mnum
;
2621 to_min
= rtxnp
->to
.mnum
;
2624 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_CONFIG_ERROR
,
2629 ASSERT(MD_CAPAB(un
) & MD_CAN_META_CHILD
);
2631 if (!(MD_CAPAB(un
) & MD_CAN_META_CHILD
)) {
2632 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_SOURCE_BAD
, from_min
);
2636 if (MD_PARENT(un
) == MD_MULTI_PARENT
) {
2637 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_SOURCE_BAD
, from_min
);
2641 switch (rtxnp
->op
) {
2642 case MDRNOP_EXCHANGE
:
2644 * may only swap with our child (master) if it is a metadevice
2646 if (md_getmajor(un
->un_m_dev
) != md_major
) {
2647 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_TARGET_BAD
,
2652 if (un
->un_l_unit
&&
2653 (md_getmajor(un
->un_l_dev
) != md_major
)) {
2655 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_TARGET_BAD
,
2660 if (md_getminor(un
->un_m_dev
) != to_min
) {
2661 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_TARGET_BAD
,
2672 (void) mdmderror(&rtxnp
->mde
, MDE_RENAME_CONFIG_ERROR
,
2677 return (0); /* ok */
2681 * Named service entry point: MDRNM_CHECK
2685 md_rendelta_t
*delta
,
2695 ASSERT((rtxnp
->op
== MDRNOP_RENAME
) || (rtxnp
->op
== MDRNOP_EXCHANGE
));
2697 if (!delta
|| !rtxnp
|| !delta
->unp
|| !delta
->uip
) {
2698 (void) mdsyserror(&rtxnp
->mde
, EINVAL
);
2702 un
= (mt_unit_t
*)delta
->unp
;
2704 if (rtxnp
->revision
== MD_RENAME_VERSION_OFFLINE
) {
2706 * trans' may not be open, if it is being modified in the exchange
2707 * or rename; trans-UFS hasn't been verified to handle the change
2708 * out from underneath it.
2710 if ((md_unit_isopen(delta
->uip
)) &&
2711 ((md_getminor(delta
->dev
) == rtxnp
->from
.mnum
) ||
2712 (md_getminor(delta
->dev
) == rtxnp
->to
.mnum
))) {
2713 (void) mdmderror(&rtxnp
->mde
,
2714 MDE_RENAME_BUSY
, rtxnp
->from
.mnum
);
2720 * can't rename or exchange with a log attached
2723 if (un
->un_l_unit
) {
2724 (void) mdmderror(&rtxnp
->mde
,
2725 MDE_RENAME_BUSY
, rtxnp
->from
.mnum
);
2729 switch (delta
->old_role
) {
2732 * self does additional checks
2734 err
= trans_may_renexch_self((mt_unit_t
*)delta
->unp
,
2743 * top_is_trans is only used to check for online
2744 * rename/exchange when MD_RENAME_VERSION == OFFLINE
2745 * since trans holds the sub-devices open
2747 rtxnp
->stat
.trans_in_stack
= TRUE
;
2756 /* end of rename/exchange */