xref: /onnv-gate/usr/src/uts/common/fs/ufs/ufs_panic.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/param.h>
31*0Sstevel@tonic-gate #include <sys/systm.h>
32*0Sstevel@tonic-gate #include <sys/errno.h>
33*0Sstevel@tonic-gate #include <sys/mode.h>
34*0Sstevel@tonic-gate #include <sys/sysmacros.h>
35*0Sstevel@tonic-gate #include <sys/cmn_err.h>
36*0Sstevel@tonic-gate #include <sys/varargs.h>
37*0Sstevel@tonic-gate #include <sys/time.h>
38*0Sstevel@tonic-gate #include <sys/buf.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/t_lock.h>
41*0Sstevel@tonic-gate #include <sys/poll.h>
42*0Sstevel@tonic-gate #include <sys/debug.h>
43*0Sstevel@tonic-gate #include <sys/cred.h>
44*0Sstevel@tonic-gate #include <sys/lockfs.h>
45*0Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
46*0Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
47*0Sstevel@tonic-gate #include <sys/fs/ufs_panic.h>
48*0Sstevel@tonic-gate #include <sys/fs/ufs_lockfs.h>
49*0Sstevel@tonic-gate #include <sys/fs/ufs_trans.h>
50*0Sstevel@tonic-gate #include <sys/fs/ufs_mount.h>
51*0Sstevel@tonic-gate #include <sys/fs/ufs_prot.h>
52*0Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
53*0Sstevel@tonic-gate #include <sys/pathname.h>
54*0Sstevel@tonic-gate #include <sys/utsname.h>
55*0Sstevel@tonic-gate #include <sys/conf.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate /* handy */
58*0Sstevel@tonic-gate #define	abs(x)		((x) < 0? -(x): (x))
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #if defined(DEBUG)
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate #define	DBGLVL_NONE	0x00000000
63*0Sstevel@tonic-gate #define	DBGLVL_MAJOR	0x00000100
64*0Sstevel@tonic-gate #define	DBGLVL_MINOR	0x00000200
65*0Sstevel@tonic-gate #define	DBGLVL_MINUTE	0x00000400
66*0Sstevel@tonic-gate #define	DBGLVL_TRIVIA	0x00000800
67*0Sstevel@tonic-gate #define	DBGLVL_HIDEOUS	0x00001000
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate #define	DBGFLG_NONE		0x00000000
70*0Sstevel@tonic-gate #define	DBGFLG_NOPANIC		0x00000001
71*0Sstevel@tonic-gate #define	DBGFLG_LVLONLY		0x00000002
72*0Sstevel@tonic-gate #define	DBGFLG_FIXWOULDPANIC	0x00000004
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #define	DBGFLG_FLAGMASK		0x0000000F
75*0Sstevel@tonic-gate #define	DBGFLG_LEVELMASK	~DBGFLG_FLAGMASK
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define	DEBUG_FLAGS	(ufs_fix_failure_dbg & DBGFLG_FLAGMASK)
78*0Sstevel@tonic-gate #define	DEBUG_LEVEL	(ufs_fix_failure_dbg & DBGFLG_LEVELMASK)
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate unsigned int ufs_fix_failure_dbg =	DBGLVL_NONE | DBGFLG_NONE;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate #define	DCALL(dbg_level, call)						\
83*0Sstevel@tonic-gate 	{								\
84*0Sstevel@tonic-gate 		if (DEBUG_LEVEL != DBGLVL_NONE) {			\
85*0Sstevel@tonic-gate 			if (DEBUG_FLAGS & DBGFLG_LVLONLY) {		\
86*0Sstevel@tonic-gate 				if (DEBUG_LEVEL & dbg_level) {		\
87*0Sstevel@tonic-gate 					call;				\
88*0Sstevel@tonic-gate 				}					\
89*0Sstevel@tonic-gate 			} else {					\
90*0Sstevel@tonic-gate 				if (dbg_level <= DEBUG_LEVEL) {		\
91*0Sstevel@tonic-gate 					call;				\
92*0Sstevel@tonic-gate 				}					\
93*0Sstevel@tonic-gate 			}						\
94*0Sstevel@tonic-gate 		}							\
95*0Sstevel@tonic-gate 	}
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate #define	DPRINTF(dbg_level, msg)		DCALL(dbg_level, printf msg)
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate #define	MAJOR(msg)			DPRINTF(DBGLVL_MAJOR, msg)
100*0Sstevel@tonic-gate #define	MINOR(msg)			DPRINTF(DBGLVL_MINOR, msg)
101*0Sstevel@tonic-gate #define	MINUTE(msg)			DPRINTF(DBGLVL_MINUTE, msg)
102*0Sstevel@tonic-gate #define	TRIVIA(msg)			DPRINTF(DBGLVL_TRIVIA, msg)
103*0Sstevel@tonic-gate #define	HIDEOUS(msg)			DPRINTF(DBGLVL_HIDEOUS, msg)
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate #else	/* !DEBUG */
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate #define	DCALL(ignored_dbg_level, ignored_routine)
108*0Sstevel@tonic-gate #define	MAJOR(ignored)
109*0Sstevel@tonic-gate #define	MINOR(ignored)
110*0Sstevel@tonic-gate #define	MINUTE(ignored)
111*0Sstevel@tonic-gate #define	TRIVIA(ignored)
112*0Sstevel@tonic-gate #define	HIDEOUS(ignored)
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate #endif /* DEBUG */
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate #define	NULLSTR(str)	(!(str) || *(str) == '\0'? "<null>" : (str))
117*0Sstevel@tonic-gate #define	NULSTRING	""
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /* somewhat arbitrary limits, in seconds */
120*0Sstevel@tonic-gate /* all probably ought to be different, but these are convenient for debugging */
121*0Sstevel@tonic-gate const time_t	UF_TOO_LONG		= 128;	/* max. wait for fsck start */
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate /* all of these are in units of seconds used for retry period while ... */
124*0Sstevel@tonic-gate const time_t	UF_FIXSTART_PERIOD	= 16;	/* awaiting fsck start */
125*0Sstevel@tonic-gate const time_t	UF_FIXPOLL_PERIOD	= 256;	/* awaiting fsck finish */
126*0Sstevel@tonic-gate const time_t	UF_SHORT_ERROR_PERIOD	= 4;	/* after (lockfs) error */
127*0Sstevel@tonic-gate const time_t	UF_LONG_ERROR_PERIOD	= 512;	/* after (lockfs) error */
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate #define	NO_ERROR		0
130*0Sstevel@tonic-gate #define	LOCKFS_OLOCK		LOCKFS_MAXLOCK+1
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate const ulong_t	GB			= 1024 * 1024 * 1024;
133*0Sstevel@tonic-gate const ulong_t	SecondsPerGig		= 1024;	/* ~17 minutes (overestimate) */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate /*
136*0Sstevel@tonic-gate  * per filesystem flags
137*0Sstevel@tonic-gate  */
138*0Sstevel@tonic-gate const int	UFSFX_PANIC		= (UFSMNT_ONERROR_PANIC >> 4);
139*0Sstevel@tonic-gate const int	UFSFX_LCKONLY		= (UFSMNT_ONERROR_LOCK >> 4);
140*0Sstevel@tonic-gate const int	UFSFX_LCKUMOUNT		= (UFSMNT_ONERROR_UMOUNT >> 4);
141*0Sstevel@tonic-gate const int	UFSFX_DEFAULT		= (UFSMNT_ONERROR_DEFAULT >> 4);
142*0Sstevel@tonic-gate const int	UFSFX_REPAIR_START	= 0x10000000;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate /* return protocols */
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate typedef enum triage_return_code {
147*0Sstevel@tonic-gate 	TRIAGE_DEAD = -1,
148*0Sstevel@tonic-gate 	TRIAGE_NO_SPIRIT,
149*0Sstevel@tonic-gate 	TRIAGE_ATTEND_TO
150*0Sstevel@tonic-gate } triage_t;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate typedef enum statefunc_return_code {
153*0Sstevel@tonic-gate 	SFRC_SUCCESS = 1,
154*0Sstevel@tonic-gate 	SFRC_FAIL = 0
155*0Sstevel@tonic-gate } sfrc_t;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate /* external references */
158*0Sstevel@tonic-gate /* in ufs_thread.c */
159*0Sstevel@tonic-gate extern int	ufs_thread_run(struct ufs_q *, callb_cpr_t *cprinfop);
160*0Sstevel@tonic-gate extern int	ufs_checkaccton(vnode_t *);		/* in ufs_lockfs.c */
161*0Sstevel@tonic-gate extern int	ufs_checkswapon(vnode_t *);		/* in ufs_lockfs.c */
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate extern struct pollhead		ufs_pollhd;		/* in ufs_vnops.c */
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate /* globals */
166*0Sstevel@tonic-gate struct	ufs_q	 ufs_fix;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*
169*0Sstevel@tonic-gate  * patchable constants:
170*0Sstevel@tonic-gate  *   These are set in ufsfx_init() [called at modload]
171*0Sstevel@tonic-gate  */
172*0Sstevel@tonic-gate struct ufs_failure_tunable {
173*0Sstevel@tonic-gate 	long	 uft_too_long;		/* limit repair startup time */
174*0Sstevel@tonic-gate 	long	 uft_fixstart_period;	/* pre-repair start period */
175*0Sstevel@tonic-gate 	long	 uft_fixpoll_period;	/* post-fsck start period */
176*0Sstevel@tonic-gate 	long	 uft_short_err_period;	/* post-error short period */
177*0Sstevel@tonic-gate 	long	 uft_long_err_period;	/* post-error long period */
178*0Sstevel@tonic-gate } ufsfx_tune;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /* internal statistics of events */
181*0Sstevel@tonic-gate struct uf_statistics {
182*0Sstevel@tonic-gate 	ulong_t		ufst_lock_violations;
183*0Sstevel@tonic-gate 	ulong_t		ufst_current_races;
184*0Sstevel@tonic-gate 	ulong_t		ufst_unmount_failures;
185*0Sstevel@tonic-gate 	ulong_t		ufst_num_fixed;
186*0Sstevel@tonic-gate 	ulong_t		ufst_num_failed;
187*0Sstevel@tonic-gate 	ulong_t		ufst_cpu_waste;
188*0Sstevel@tonic-gate 	time_t		ufst_last_start_tm;
189*0Sstevel@tonic-gate 	kmutex_t	ufst_mutex;
190*0Sstevel@tonic-gate } uf_stats;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate typedef enum state_action {
193*0Sstevel@tonic-gate 	UFA_ERROR = -1,		/* internal error */
194*0Sstevel@tonic-gate 	UFA_FOUND,		/* found uf in state */
195*0Sstevel@tonic-gate 	UFA_SET			/* change uf to state */
196*0Sstevel@tonic-gate } ufsa_t;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate /* state definition */
199*0Sstevel@tonic-gate typedef struct uf_state_desc {
200*0Sstevel@tonic-gate 	int	  ud_v;					/* value */
201*0Sstevel@tonic-gate 	char	 *ud_name;				/* name */
202*0Sstevel@tonic-gate 	sfrc_t	(*ud_sfp)(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
203*0Sstevel@tonic-gate 							/* per-state actions */
204*0Sstevel@tonic-gate 	ufs_failure_states_t	  ud_prev;		/* valid prev. states */
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	struct uf_state_desc_attr {
207*0Sstevel@tonic-gate 		unsigned	terminal:1;	/* no action req. if found */
208*0Sstevel@tonic-gate 		unsigned	at_fail:1;	/* state set by thread */
209*0Sstevel@tonic-gate 						/* encountering the error */
210*0Sstevel@tonic-gate 		unsigned	unused;
211*0Sstevel@tonic-gate 	} ud_attr;
212*0Sstevel@tonic-gate } ufsd_t;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /*
215*0Sstevel@tonic-gate  * forward references
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /* thread to watch for failures */
219*0Sstevel@tonic-gate static void	ufsfx_thread_fix_failures(void *);
220*0Sstevel@tonic-gate static int 	ufsfx_do_failure_q(void);
221*0Sstevel@tonic-gate static void	ufsfx_kill_fix_failure_thread(void *);
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate /* routines called when failure occurs */
224*0Sstevel@tonic-gate static int		 ufs_fault_v(vnode_t *, char *, va_list)
225*0Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
226*0Sstevel@tonic-gate static ufs_failure_t	*init_failure(vnode_t *, char *, va_list)
227*0Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
228*0Sstevel@tonic-gate static void		 queue_failure(ufs_failure_t *);
229*0Sstevel@tonic-gate /*PRINTFLIKE2*/
230*0Sstevel@tonic-gate static void		 real_panic(ufs_failure_t *, const char *, ...)
231*0Sstevel@tonic-gate 	__KPRINTFLIKE(2);
232*0Sstevel@tonic-gate static void		 real_panic_v(ufs_failure_t *, const char *, va_list)
233*0Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
234*0Sstevel@tonic-gate static triage_t		 triage(vnode_t *);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate /* routines called when failure record is acted upon */
237*0Sstevel@tonic-gate static sfrc_t	set_state(ufs_failure_t *, ufs_failure_states_t);
238*0Sstevel@tonic-gate static int	state_trans_valid(ufs_failure_states_t, ufs_failure_states_t);
239*0Sstevel@tonic-gate static int	terminal_state(ufs_failure_states_t);
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /* routines called when states entered/found */
242*0Sstevel@tonic-gate static sfrc_t	sf_minimum(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
243*0Sstevel@tonic-gate static sfrc_t	sf_undef(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
244*0Sstevel@tonic-gate static sfrc_t	sf_init(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
245*0Sstevel@tonic-gate static sfrc_t	sf_queue(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
246*0Sstevel@tonic-gate static sfrc_t	sf_found_queue(ufs_failure_t *);
247*0Sstevel@tonic-gate static sfrc_t	sf_nonterm_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
248*0Sstevel@tonic-gate static sfrc_t	sf_term_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
249*0Sstevel@tonic-gate static sfrc_t	sf_panic(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
250*0Sstevel@tonic-gate static sfrc_t	sf_set_trylck(ufs_failure_t *);
251*0Sstevel@tonic-gate static sfrc_t	sf_set_locked(ufs_failure_t *);
252*0Sstevel@tonic-gate static sfrc_t	sf_found_trylck(ufs_failure_t *);
253*0Sstevel@tonic-gate static sfrc_t	sf_found_lock_fix_cmn(ufs_failure_t *, ufs_failure_states_t);
254*0Sstevel@tonic-gate static sfrc_t	sf_found_umount(ufs_failure_t *);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate /* support routines, called by sf_nonterm_cmn and sf_term_cmn */
257*0Sstevel@tonic-gate static time_t 	trylock_time_exceeded(ufs_failure_t *);
258*0Sstevel@tonic-gate static void 	pester_msg(ufs_failure_t *, int);
259*0Sstevel@tonic-gate static int 	get_lockfs_status(ufs_failure_t *, struct lockfs *);
260*0Sstevel@tonic-gate static void 	alloc_lockfs_comment(ufs_failure_t *, struct lockfs *);
261*0Sstevel@tonic-gate static int 	set_lockfs(ufs_failure_t *, struct lockfs *);
262*0Sstevel@tonic-gate static int 	lockfs_failure(ufs_failure_t *);
263*0Sstevel@tonic-gate static int 	lockfs_success(ufs_failure_t *);
264*0Sstevel@tonic-gate static int	fsck_active(ufs_failure_t *);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate /* low-level support routines */
267*0Sstevel@tonic-gate static ufsd_t	*get_state_desc(ufs_failure_states_t);
268*0Sstevel@tonic-gate static char	*fs_name(ufs_failure_t *);
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate #if defined(DEBUG)
271*0Sstevel@tonic-gate static char	*state_name(ufs_failure_states_t);
272*0Sstevel@tonic-gate static char	*lock_name(struct lockfs *);
273*0Sstevel@tonic-gate static char	*err_name(int);
274*0Sstevel@tonic-gate static char	*act_name(ufsa_t);
275*0Sstevel@tonic-gate static void	 dump_uf_list(char *msg);
276*0Sstevel@tonic-gate static void	 dump_uf(ufs_failure_t *, int i);
277*0Sstevel@tonic-gate #endif /* DEBUG */
278*0Sstevel@tonic-gate /*
279*0Sstevel@tonic-gate  *
280*0Sstevel@tonic-gate  * State Transitions:
281*0Sstevel@tonic-gate  *
282*0Sstevel@tonic-gate  * normally:
283*0Sstevel@tonic-gate  * if flagged to be locked but not unmounted:	(UFSMNT_ONERROR_LOCK)
284*0Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> FIXING -> FIXED
285*0Sstevel@tonic-gate  *
286*0Sstevel@tonic-gate  * The only difference between these two is that the fsck must be started
287*0Sstevel@tonic-gate  * manually.
288*0Sstevel@tonic-gate  *
289*0Sstevel@tonic-gate  * if flagged to be unmounted:			(UFSMNT_ONERROR_UMOUNT)
290*0Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> UMOUNT -> NOTFIX
291*0Sstevel@tonic-gate  *
292*0Sstevel@tonic-gate  * if flagged to panic:				(UFSMNT_ONERROR_PANIC)
293*0Sstevel@tonic-gate  *	UNDEF -> INIT -> PANIC
294*0Sstevel@tonic-gate  *
295*0Sstevel@tonic-gate  * if a secondary panic on a file system which has an active failure
296*0Sstevel@tonic-gate  * record:
297*0Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> REPLICA
298*0Sstevel@tonic-gate  *
299*0Sstevel@tonic-gate  * UNDEF, INIT, QUEUE all are set in the context of the failing thread.
300*0Sstevel@tonic-gate  * All other states (except possibly PANIC) are set in by the monitor
301*0Sstevel@tonic-gate  * (lock) thread.
302*0Sstevel@tonic-gate  *
303*0Sstevel@tonic-gate  */
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate ufsd_t	state_desc[] =
306*0Sstevel@tonic-gate {
307*0Sstevel@tonic-gate 	{ UF_ILLEGAL,	"in an unknown state",	sf_minimum,	UF_ILLEGAL,
308*0Sstevel@tonic-gate 								{ 0, 1, 0 } },
309*0Sstevel@tonic-gate 	{ UF_UNDEF,	"undefined",		sf_undef,	UF_UNDEF,
310*0Sstevel@tonic-gate 								{ 0, 1, 0 } },
311*0Sstevel@tonic-gate 	{ UF_INIT,	"being initialized",	sf_init,	UF_UNDEF,
312*0Sstevel@tonic-gate 								{ 0, 1, 0 } },
313*0Sstevel@tonic-gate 	{ UF_QUEUE,	"queued",		sf_queue,	UF_INIT,
314*0Sstevel@tonic-gate 								{ 0, 1, 0 } },
315*0Sstevel@tonic-gate 	{ UF_TRYLCK,	"trying to be locked",	sf_nonterm_cmn,
316*0Sstevel@tonic-gate 						UF_QUEUE,	{ 0, 0, 0 } },
317*0Sstevel@tonic-gate 	{ UF_LOCKED,	"locked",		sf_nonterm_cmn,
318*0Sstevel@tonic-gate 					UF_TRYLCK | UF_FIXING,	{ 0, 0, 0 } },
319*0Sstevel@tonic-gate 	{ UF_UMOUNT,	"being unmounted",	sf_nonterm_cmn,
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate #if defined(DEBUG)
322*0Sstevel@tonic-gate 					UF_PANIC |
323*0Sstevel@tonic-gate #endif /* DEBUG */
324*0Sstevel@tonic-gate 					UF_TRYLCK | UF_LOCKED, 	{ 0, 0, 0 } },
325*0Sstevel@tonic-gate 	{ UF_FIXING,	"being fixed",		sf_nonterm_cmn,
326*0Sstevel@tonic-gate 						UF_LOCKED,	{ 0, 0, 0 } },
327*0Sstevel@tonic-gate 	{ UF_FIXED,	"fixed",		sf_term_cmn,
328*0Sstevel@tonic-gate 						UF_FIXING,	{ 1, 0, 0 } },
329*0Sstevel@tonic-gate 	{ UF_NOTFIX,	"not fixed",		sf_term_cmn,
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate #if defined(DEBUG)
332*0Sstevel@tonic-gate 							UF_PANIC |
333*0Sstevel@tonic-gate #endif /* DEBUG */
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	    UF_QUEUE | UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING,
336*0Sstevel@tonic-gate 								{ 1, 0, 0 } },
337*0Sstevel@tonic-gate 	{ UF_REPLICA,	"a replica",		sf_term_cmn,
338*0Sstevel@tonic-gate 						UF_QUEUE,	{ 1, 0, 0 } },
339*0Sstevel@tonic-gate 	{ UF_PANIC,	"panicking",		sf_panic,
340*0Sstevel@tonic-gate 		/* XXX make this narrower */	UF_ALLSTATES,	{ 0, 0, 0 } },
341*0Sstevel@tonic-gate 	{ UF_UNDEF,	NULL,			((sfrc_t (*)()) NULL),
342*0Sstevel@tonic-gate 						UF_UNDEF, 	{ 0, 0, 0 } }
343*0Sstevel@tonic-gate };
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate /* unified collection */
346*0Sstevel@tonic-gate struct ufsfx_info {
347*0Sstevel@tonic-gate 	struct uf_statistics		*ufi_statp;
348*0Sstevel@tonic-gate 	struct ufs_failure_tunable	*ufi_tunep;
349*0Sstevel@tonic-gate 	ufsd_t				*ufi_statetab;
350*0Sstevel@tonic-gate } uffsinfo;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate #if defined(DEBUG)
353*0Sstevel@tonic-gate struct action_description {
354*0Sstevel@tonic-gate 	ufsa_t	 ad_v;
355*0Sstevel@tonic-gate 	char	*ad_name;
356*0Sstevel@tonic-gate };
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate #define	EUNK		(-1)
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate struct error_description {
361*0Sstevel@tonic-gate 	int	 ed_errno;
362*0Sstevel@tonic-gate 	char	*ed_name;
363*0Sstevel@tonic-gate } err_desc[] =
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	{ EUNK,		"<unexpected errno?>"	},
366*0Sstevel@tonic-gate 	{ EINVAL,	"EINVAL"		},
367*0Sstevel@tonic-gate 	{ EACCES,	"EACCES"		},
368*0Sstevel@tonic-gate 	{ EPERM,	"EPERM"			},
369*0Sstevel@tonic-gate 	{ EIO,		"EIO"			},
370*0Sstevel@tonic-gate 	{ EDEADLK,	"EDEADLK"		},
371*0Sstevel@tonic-gate 	{ EBUSY,	"EBUSY"			},
372*0Sstevel@tonic-gate 	{ EAGAIN,	"EAGAIN"		},
373*0Sstevel@tonic-gate 	{ ERESTART,	"ERESTART"		},
374*0Sstevel@tonic-gate 	{ ETIMEDOUT,	"ETIMEDOUT"		},
375*0Sstevel@tonic-gate 	{ NO_ERROR,	"Ok"			},
376*0Sstevel@tonic-gate 	{ EUNK,		NULL 			}
377*0Sstevel@tonic-gate };
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate struct action_description act_desc[] =
380*0Sstevel@tonic-gate {
381*0Sstevel@tonic-gate 	{ UFA_ERROR,	"<unexpected action?>"	},
382*0Sstevel@tonic-gate 	{ UFA_FOUND,	"\"found\""	},
383*0Sstevel@tonic-gate 	{ UFA_SET,	"\"set\""	},
384*0Sstevel@tonic-gate 	{ UFA_ERROR,	NULL			},
385*0Sstevel@tonic-gate };
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate #define	LOCKFS_BADLOCK	(-1)
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate struct lock_description {
390*0Sstevel@tonic-gate 	int	 ld_type;
391*0Sstevel@tonic-gate 	char	*ld_name;
392*0Sstevel@tonic-gate } lock_desc[] =
393*0Sstevel@tonic-gate {
394*0Sstevel@tonic-gate 	{ LOCKFS_BADLOCK,	"<unexpected lock?>"	},
395*0Sstevel@tonic-gate 	{ LOCKFS_ULOCK,		"Unlock"		},
396*0Sstevel@tonic-gate 	{ LOCKFS_ELOCK,		"Error Lock"		},
397*0Sstevel@tonic-gate 	{ LOCKFS_HLOCK,		"Hard Lock"		},
398*0Sstevel@tonic-gate 	{ LOCKFS_OLOCK,		"Old Lock"		},
399*0Sstevel@tonic-gate 	{ LOCKFS_BADLOCK,	NULL			}
400*0Sstevel@tonic-gate };
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate #endif /* DEBUG */
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate /*
405*0Sstevel@tonic-gate  * ufs_fault, ufs_fault_v
406*0Sstevel@tonic-gate  *
407*0Sstevel@tonic-gate  *  called instead of cmn_err(CE_PANIC, ...) by ufs routines
408*0Sstevel@tonic-gate  *  when a failure is detected to put the file system into an
409*0Sstevel@tonic-gate  *  error state (if possible) or to devolve to a panic otherwise
410*0Sstevel@tonic-gate  *
411*0Sstevel@tonic-gate  * vnode is some vnode in this file system, used to find the way
412*0Sstevel@tonic-gate  * to ufsvfs, vfsp etc.  Since a panic can be called from many
413*0Sstevel@tonic-gate  * levels, the vnode is the most convenient hook to pass through.
414*0Sstevel@tonic-gate  *
415*0Sstevel@tonic-gate  */
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate /*PRINTFLIKE2*/
418*0Sstevel@tonic-gate int
419*0Sstevel@tonic-gate ufs_fault(vnode_t *vp, char *fmt, ...)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	va_list	adx;
422*0Sstevel@tonic-gate 	int	error;
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	MINOR(("[ufs_fault"));
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	va_start(adx, fmt);
427*0Sstevel@tonic-gate 	error = ufs_fault_v(vp, fmt, adx);
428*0Sstevel@tonic-gate 	va_end(adx);
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	MINOR((": %s (%d)]\n", err_name(error), error));
431*0Sstevel@tonic-gate 	return (error);
432*0Sstevel@tonic-gate }
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate const char *nullfmt = "<null format?>";
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate static int
437*0Sstevel@tonic-gate ufs_fault_v(vnode_t *vp, char *fmt, va_list adx)
438*0Sstevel@tonic-gate {
439*0Sstevel@tonic-gate 	ufs_failure_t		*new = NULL;
440*0Sstevel@tonic-gate 	ufsvfs_t		*ufsvfsp;
441*0Sstevel@tonic-gate 	triage_t		 fix;
442*0Sstevel@tonic-gate 	int			 err = ERESTART;
443*0Sstevel@tonic-gate 	int			need_vfslock;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	MINOR(("[ufs_fault_v"));
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if (fmt == NULL)
448*0Sstevel@tonic-gate 		fmt = (char *)nullfmt;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	fix = triage(vp);
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	if (vp) {
453*0Sstevel@tonic-gate 		ufsvfsp = (struct ufsvfs *)vp->v_vfsp->vfs_data;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 		/*
456*0Sstevel@tonic-gate 		 * Something bad has happened. That is why we are here.
457*0Sstevel@tonic-gate 		 *
458*0Sstevel@tonic-gate 		 * In order for the bad thing to be recorded in the superblock
459*0Sstevel@tonic-gate 		 * we need to write to the superblock directly.
460*0Sstevel@tonic-gate 		 * In the case that logging is enabled the logging code
461*0Sstevel@tonic-gate 		 * would normally intercept our write as a delta to the log,
462*0Sstevel@tonic-gate 		 * thus we mark the filesystem FSBAD in any case.
463*0Sstevel@tonic-gate 		 */
464*0Sstevel@tonic-gate 		need_vfslock = !MUTEX_HELD(&ufsvfsp->vfs_lock);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 		if (need_vfslock) {
467*0Sstevel@tonic-gate 			mutex_enter(&ufsvfsp->vfs_lock);
468*0Sstevel@tonic-gate 		}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 		ufsvfsp->vfs_fs->fs_clean = FSBAD;
471*0Sstevel@tonic-gate 		ASSERT(SEMA_HELD(&ufsvfsp->vfs_bufp->b_sem));
472*0Sstevel@tonic-gate 		ufsvfsp->vfs_bufp->b_flags &= ~(B_ASYNC | B_READ |
473*0Sstevel@tonic-gate 				B_DONE | B_ERROR | B_DELWRI);
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		(void) bdev_strategy(ufsvfsp->vfs_bufp);
476*0Sstevel@tonic-gate 		(void) biowait(ufsvfsp->vfs_bufp);
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 		if (need_vfslock) {
479*0Sstevel@tonic-gate 			mutex_exit(&ufsvfsp->vfs_lock);
480*0Sstevel@tonic-gate 		}
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	switch (fix) {
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	default:
486*0Sstevel@tonic-gate 	case TRIAGE_DEAD:
487*0Sstevel@tonic-gate 	case TRIAGE_NO_SPIRIT:
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 		real_panic_v(new, fmt, adx);
490*0Sstevel@tonic-gate 		/* LINTED: warning: logical expression always true: op "||" */
491*0Sstevel@tonic-gate 		ASSERT(DEBUG);
492*0Sstevel@tonic-gate 		err = EAGAIN;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate #if defined(DEBUG)
495*0Sstevel@tonic-gate 		if (!(DEBUG_FLAGS & DBGFLG_FIXWOULDPANIC)) {
496*0Sstevel@tonic-gate 			break;
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 		/* FALLTHROUGH */
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate #else
501*0Sstevel@tonic-gate 		break;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate #endif /* DEBUG */
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	case TRIAGE_ATTEND_TO:
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 		/* q thread not running yet? */
508*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
509*0Sstevel@tonic-gate 		if (!ufs_fix.uq_threadp) {
510*0Sstevel@tonic-gate 			mutex_exit(&ufs_fix.uq_mutex);
511*0Sstevel@tonic-gate 			ufs_thread_start(&ufs_fix, ufsfx_thread_fix_failures,
512*0Sstevel@tonic-gate 								    NULL);
513*0Sstevel@tonic-gate 			ufs_fix.uq_threadp->t_flag |= T_DONTBLOCK;
514*0Sstevel@tonic-gate 			mutex_enter(&ufs_fix.uq_mutex);
515*0Sstevel@tonic-gate 		} else {
516*0Sstevel@tonic-gate 			MINOR((": fix failure thread already running "));
517*0Sstevel@tonic-gate 		}
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 		if (ufs_fix.uq_threadp && ufs_fix.uq_threadp == curthread) {
520*0Sstevel@tonic-gate 			mutex_exit(&ufs_fix.uq_mutex);
521*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "ufs_fault_v: recursive ufs_fault");
522*0Sstevel@tonic-gate 		} else {
523*0Sstevel@tonic-gate 			mutex_exit(&ufs_fix.uq_mutex);
524*0Sstevel@tonic-gate 		}
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 		new = init_failure(vp, fmt, adx);
527*0Sstevel@tonic-gate 		if (new != NULL) {
528*0Sstevel@tonic-gate 			queue_failure(new);
529*0Sstevel@tonic-gate 			break;
530*0Sstevel@tonic-gate 		}
531*0Sstevel@tonic-gate 		real_panic_v(new, fmt, adx);
532*0Sstevel@tonic-gate 		break;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	}
535*0Sstevel@tonic-gate 	MINOR(("] "));
536*0Sstevel@tonic-gate 	return (err);
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate /*
540*0Sstevel@tonic-gate  * triage()
541*0Sstevel@tonic-gate  *
542*0Sstevel@tonic-gate  *  Attempt to fix iff:
543*0Sstevel@tonic-gate  *    - the system is not already panicking
544*0Sstevel@tonic-gate  *    - this file system isn't explicitly marked not to be fixed
545*0Sstevel@tonic-gate  *    - we can connect to the user-level daemon
546*0Sstevel@tonic-gate  * These conditions are detectable later, but if we can determine
547*0Sstevel@tonic-gate  * them in the failing threads context the core dump may be more
548*0Sstevel@tonic-gate  * useful.
549*0Sstevel@tonic-gate  *
550*0Sstevel@tonic-gate  */
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate static triage_t
553*0Sstevel@tonic-gate triage(vnode_t *vp)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	struct inode	 *ip;
556*0Sstevel@tonic-gate 	int		  need_unlock_vfs;
557*0Sstevel@tonic-gate 	int		  fs_flags;
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	MINUTE(("[triage"));
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	if (panicstr) {
562*0Sstevel@tonic-gate 		MINUTE((
563*0Sstevel@tonic-gate 		": already panicking: \"%s\" => TRIAGE_DEAD]\n", panicstr));
564*0Sstevel@tonic-gate 		return (TRIAGE_DEAD);
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs) {
568*0Sstevel@tonic-gate 		MINUTE((
569*0Sstevel@tonic-gate 	": vp, ip or ufsvfs is NULL; can't determine fs => TRIAGE_DEAD]\n"));
570*0Sstevel@tonic-gate 		return (TRIAGE_DEAD);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	/* use tryenter and continue no matter what since we're panicky */
574*0Sstevel@tonic-gate 	need_unlock_vfs = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
575*0Sstevel@tonic-gate 	if (need_unlock_vfs)
576*0Sstevel@tonic-gate 		need_unlock_vfs = mutex_tryenter(&ip->i_ufsvfs->vfs_lock);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	fs_flags = ip->i_ufsvfs->vfs_fsfx.fx_flags;
579*0Sstevel@tonic-gate 	if (need_unlock_vfs)
580*0Sstevel@tonic-gate 		mutex_exit(&ip->i_ufsvfs->vfs_lock);
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	if (fs_flags & UFSFX_PANIC) {
583*0Sstevel@tonic-gate 		MINUTE((
584*0Sstevel@tonic-gate 		": filesystem marked \"panic\" => TRIAGE_NO_SPIRIT]\n"));
585*0Sstevel@tonic-gate 		return (TRIAGE_NO_SPIRIT);
586*0Sstevel@tonic-gate 	}
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	if (ufs_checkaccton(vp) != 0) {
589*0Sstevel@tonic-gate 		MINUTE((
590*0Sstevel@tonic-gate 		": filesystem would deadlock (accounting) => TRIAGE_DEAD]\n"));
591*0Sstevel@tonic-gate 		return (TRIAGE_DEAD);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	if (ufs_checkswapon(vp) != 0) {
595*0Sstevel@tonic-gate 		MINUTE((
596*0Sstevel@tonic-gate 		": filesystem would deadlock (swapping) => TRIAGE_DEAD]\n"));
597*0Sstevel@tonic-gate 		return (TRIAGE_DEAD);
598*0Sstevel@tonic-gate 	}
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 	MINUTE((": return TRIAGE_ATTEND_TO] "));
601*0Sstevel@tonic-gate 	return (TRIAGE_ATTEND_TO);
602*0Sstevel@tonic-gate }
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate /*
605*0Sstevel@tonic-gate  * init failure
606*0Sstevel@tonic-gate  *
607*0Sstevel@tonic-gate  * This routine allocates a failure struct and initializes
608*0Sstevel@tonic-gate  * it's member elements.
609*0Sstevel@tonic-gate  * Space is allocated for copies of dynamic identifying fs structures
610*0Sstevel@tonic-gate  * passed in.  Without a much more segmented kernel architecture
611*0Sstevel@tonic-gate  * this is as protected as we can make it (for now.)
612*0Sstevel@tonic-gate  */
613*0Sstevel@tonic-gate static ufs_failure_t *
614*0Sstevel@tonic-gate init_failure(vnode_t *vp, char *fmt, va_list adx)
615*0Sstevel@tonic-gate {
616*0Sstevel@tonic-gate 	ufs_failure_t	*new;
617*0Sstevel@tonic-gate 	struct inode	*ip;
618*0Sstevel@tonic-gate 	int		 initialization_worked = 0;
619*0Sstevel@tonic-gate 	int		 need_vfs_unlock;
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	MINOR(("[init_failure"));
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	new = kmem_zalloc(sizeof (ufs_failure_t), KM_NOSLEEP);
624*0Sstevel@tonic-gate 	if (!new) {
625*0Sstevel@tonic-gate 		MINOR((": kmem_zalloc failed]\n"));
626*0Sstevel@tonic-gate 		return (NULL);
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	/*
630*0Sstevel@tonic-gate 	 * enough information to make a fix attempt possible?
631*0Sstevel@tonic-gate 	 */
632*0Sstevel@tonic-gate 	if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs || !vp->v_vfsp ||
633*0Sstevel@tonic-gate 	    !ip->i_ufsvfs->vfs_bufp || !ITOF(ip) || !fmt)
634*0Sstevel@tonic-gate 		goto errout;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	if (vp->v_type != VREG && vp->v_type != VDIR &&
637*0Sstevel@tonic-gate 	    vp->v_type != VBLK && vp->v_type != VCHR &&
638*0Sstevel@tonic-gate 	    vp->v_type != VLNK && vp->v_type != VFIFO &&
639*0Sstevel@tonic-gate 	    vp->v_type != VSOCK)
640*0Sstevel@tonic-gate 		goto errout;
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	if (ip->i_ufsvfs->vfs_root->v_type != VREG &&
643*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VDIR &&
644*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VBLK &&
645*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VCHR &&
646*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VLNK &&
647*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VFIFO &&
648*0Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VSOCK)
649*0Sstevel@tonic-gate 		goto errout;
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	if ((ITOF(ip)->fs_magic != FS_MAGIC) &&
652*0Sstevel@tonic-gate 	    (ITOF(ip)->fs_magic != MTB_UFS_MAGIC))
653*0Sstevel@tonic-gate 		goto errout;
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	/* intialize values */
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	(void) vsnprintf(new->uf_panic_str, LOCKFS_MAXCOMMENTLEN - 1, fmt, adx);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	new->uf_ufsvfsp = ip->i_ufsvfs;
660*0Sstevel@tonic-gate 	new->uf_vfsp    = ip->i_vfs;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	mutex_init(&new->uf_mutex, NULL, MUTEX_DEFAULT, NULL);
663*0Sstevel@tonic-gate 	need_vfs_unlock = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	if (need_vfs_unlock) {
666*0Sstevel@tonic-gate 		if (!mutex_tryenter(&ip->i_ufsvfs->vfs_lock)) {
667*0Sstevel@tonic-gate 			/*
668*0Sstevel@tonic-gate 			 * not much alternative here, but we're panicking
669*0Sstevel@tonic-gate 			 * already, it couldn't be worse - so just
670*0Sstevel@tonic-gate 			 * proceed optimistically and take note.
671*0Sstevel@tonic-gate 			 */
672*0Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
673*0Sstevel@tonic-gate 			uf_stats.ufst_lock_violations++;
674*0Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
675*0Sstevel@tonic-gate 			MINOR((": couldn't get vfs lock"))
676*0Sstevel@tonic-gate 			need_vfs_unlock = 0;
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	if (mutex_tryenter(&new->uf_mutex)) {
681*0Sstevel@tonic-gate 		initialization_worked = set_state(new, UF_INIT);
682*0Sstevel@tonic-gate 		mutex_exit(&new->uf_mutex);
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	if (need_vfs_unlock)
686*0Sstevel@tonic-gate 		mutex_exit(&ip->i_ufsvfs->vfs_lock);
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	if (initialization_worked) {
689*0Sstevel@tonic-gate 		MINOR(("] "));
690*0Sstevel@tonic-gate 		return (new);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 	/* FALLTHROUGH */
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate errout:
695*0Sstevel@tonic-gate 	if (new)
696*0Sstevel@tonic-gate 		kmem_free(new, sizeof (ufs_failure_t));
697*0Sstevel@tonic-gate 	MINOR((": failed]\n"));
698*0Sstevel@tonic-gate 	return (NULL);
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate static void
702*0Sstevel@tonic-gate queue_failure(ufs_failure_t *new)
703*0Sstevel@tonic-gate {
704*0Sstevel@tonic-gate 	MINOR(("[queue_failure"));
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	mutex_enter(&ufs_fix.uq_mutex);
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	if (ufs_fix.uq_ufhead)
709*0Sstevel@tonic-gate 		insque(new, &ufs_fix.uq_ufhead);
710*0Sstevel@tonic-gate 	else
711*0Sstevel@tonic-gate 		ufs_fix.uq_ufhead = new;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (mutex_tryenter(&new->uf_mutex)) {
714*0Sstevel@tonic-gate 		(void) set_state(new, UF_QUEUE);
715*0Sstevel@tonic-gate 		mutex_exit(&new->uf_mutex);
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	mutex_enter(&uf_stats.ufst_mutex);		/* force wakeup */
719*0Sstevel@tonic-gate 	ufs_fix.uq_ne = ufs_fix.uq_lowat = uf_stats.ufst_num_failed;
720*0Sstevel@tonic-gate 	mutex_exit(&uf_stats.ufst_mutex);
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	cv_broadcast(&ufs_fix.uq_cv);
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	DCALL(DBGLVL_MAJOR, cmn_err(CE_WARN, new->uf_panic_str?
725*0Sstevel@tonic-gate 					new->uf_panic_str:
726*0Sstevel@tonic-gate 					"queue_failure: NULL panic str?"));
727*0Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	MINOR(("] "));
730*0Sstevel@tonic-gate }
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate /*PRINTFLIKE2*/
733*0Sstevel@tonic-gate static void
734*0Sstevel@tonic-gate real_panic(ufs_failure_t *f, const char *fmt, ...)
735*0Sstevel@tonic-gate {
736*0Sstevel@tonic-gate 	va_list	adx;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	MINUTE(("[real_panic "));
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	va_start(adx, fmt);
741*0Sstevel@tonic-gate 	real_panic_v(f, fmt, adx);
742*0Sstevel@tonic-gate 	va_end(adx);
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	MINUTE((": return?!]\n"));
745*0Sstevel@tonic-gate }
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate static void
748*0Sstevel@tonic-gate real_panic_v(ufs_failure_t *f, const char *fmt, va_list adx)
749*0Sstevel@tonic-gate {
750*0Sstevel@tonic-gate 	int seriousness = CE_PANIC;
751*0Sstevel@tonic-gate 	int need_unlock;
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	MINUTE(("[real_panic_v "));
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	if (f && f->uf_ufsvfsp)
756*0Sstevel@tonic-gate 		TRANS_SETERROR(f->uf_ufsvfsp);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate #if defined(DEBUG)
759*0Sstevel@tonic-gate 	if (DEBUG_FLAGS & DBGFLG_NOPANIC) {
760*0Sstevel@tonic-gate 		seriousness = CE_WARN;
761*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "real_panic: EWOULDPANIC\n");
762*0Sstevel@tonic-gate 	}
763*0Sstevel@tonic-gate #endif /* DEBUG */
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	delay(hz >> 1);			/* allow previous warnings to get out */
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	if (!f && fmt)
768*0Sstevel@tonic-gate 		vcmn_err(seriousness, fmt, adx);
769*0Sstevel@tonic-gate 	else
770*0Sstevel@tonic-gate 		cmn_err(seriousness, f && f->uf_panic_str? f->uf_panic_str:
771*0Sstevel@tonic-gate 		    "real_panic: <unknown panic?>");
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	if (f) {
774*0Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
775*0Sstevel@tonic-gate 		if (need_unlock) {
776*0Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
777*0Sstevel@tonic-gate 		}
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		f->uf_retry = -1;
780*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 		if (need_unlock) {
783*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
784*0Sstevel@tonic-gate 		}
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 	MINUTE((": return?!]\n"));
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate  * initializes ufs panic structs, locks, etc
791*0Sstevel@tonic-gate  */
792*0Sstevel@tonic-gate void
793*0Sstevel@tonic-gate ufsfx_init(void)
794*0Sstevel@tonic-gate {
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_init"));
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 	/* patchable; unchanged while running, so no lock is needed */
799*0Sstevel@tonic-gate 	ufsfx_tune.uft_too_long		= UF_TOO_LONG;
800*0Sstevel@tonic-gate 	ufsfx_tune.uft_fixstart_period	= UF_FIXSTART_PERIOD;
801*0Sstevel@tonic-gate 	ufsfx_tune.uft_fixpoll_period	= UF_FIXPOLL_PERIOD;
802*0Sstevel@tonic-gate 	ufsfx_tune.uft_short_err_period	= UF_SHORT_ERROR_PERIOD;
803*0Sstevel@tonic-gate 	ufsfx_tune.uft_long_err_period	= UF_LONG_ERROR_PERIOD;
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 	uffsinfo.ufi_statp	= &uf_stats;
806*0Sstevel@tonic-gate 	uffsinfo.ufi_tunep	= &ufsfx_tune;
807*0Sstevel@tonic-gate 	uffsinfo.ufi_statetab	= &state_desc[0];
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	mutex_init(&uf_stats.ufst_mutex, NULL, MUTEX_DEFAULT, NULL);
810*0Sstevel@tonic-gate 	ufs_thread_init(&ufs_fix, /* maxne */ 1);
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	MINUTE(("] "));
813*0Sstevel@tonic-gate }
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate /*
816*0Sstevel@tonic-gate  * initializes per-ufs values
817*0Sstevel@tonic-gate  * returns 0 (ok) or errno
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate int
820*0Sstevel@tonic-gate ufsfx_mount(struct ufsvfs *ufsvfsp, int flags)
821*0Sstevel@tonic-gate {
822*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_mount (%d)", flags));
823*0Sstevel@tonic-gate 	/* don't check/need vfs_lock because it's still being initialized */
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	ufsvfsp->vfs_fsfx.fx_flags = (flags & UFSMNT_ONERROR_FLGMASK) >> 4;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	MINUTE((": %s: fx_flags:%ld,",
828*0Sstevel@tonic-gate 		ufsvfsp->vfs_fs->fs_fsmnt, ufsvfsp->vfs_fsfx.fx_flags));
829*0Sstevel@tonic-gate 	/*
830*0Sstevel@tonic-gate 	 *	onerror={panic ^ lock only ^ unmount}
831*0Sstevel@tonic-gate 	 */
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_PANIC) {
834*0Sstevel@tonic-gate 		MINUTE((" PANIC"));
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	} else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKONLY) {
837*0Sstevel@tonic-gate 		MINUTE((" LCKONLY"));
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	} else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKUMOUNT) {
840*0Sstevel@tonic-gate 		MINUTE((" LCKUMOUNT"));
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	} else {
843*0Sstevel@tonic-gate 		ufsvfsp->vfs_fsfx.fx_flags = UFSFX_DEFAULT;
844*0Sstevel@tonic-gate 		ASSERT(ufsvfsp->vfs_fsfx.fx_flags &
845*0Sstevel@tonic-gate 						(UFSMNT_ONERROR_FLGMASK >> 4));
846*0Sstevel@tonic-gate 		MINUTE((" DEFAULT"));
847*0Sstevel@tonic-gate 	}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 	pollwakeup(&ufs_pollhd, POLLPRI);
850*0Sstevel@tonic-gate 	MINUTE(("]\n"));
851*0Sstevel@tonic-gate 	return (0);
852*0Sstevel@tonic-gate }
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate /*
855*0Sstevel@tonic-gate  * ufsfx_unmount
856*0Sstevel@tonic-gate  *
857*0Sstevel@tonic-gate  * called during unmount
858*0Sstevel@tonic-gate  */
859*0Sstevel@tonic-gate void
860*0Sstevel@tonic-gate ufsfx_unmount(struct ufsvfs *ufsvfsp)
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	ufs_failure_t	*f;
863*0Sstevel@tonic-gate 	int		 must_unlock_list;
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_unmount"));
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	if (!ufsvfsp) {
868*0Sstevel@tonic-gate 		MINUTE((": no ufsvfsp]"));
869*0Sstevel@tonic-gate 		return;
870*0Sstevel@tonic-gate 	}
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	if ((must_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex)) != 0)
873*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
876*0Sstevel@tonic-gate 		int must_unlock_failure;
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 		must_unlock_failure = !MUTEX_HELD(&f->uf_mutex);
879*0Sstevel@tonic-gate 		if (must_unlock_failure) {
880*0Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
881*0Sstevel@tonic-gate 		}
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp) {
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 			/*
886*0Sstevel@tonic-gate 			 * if we owned the failure record lock, then this
887*0Sstevel@tonic-gate 			 * is probably a fix failure-triggered unmount, so
888*0Sstevel@tonic-gate 			 * the warning is not appropriate or needed
889*0Sstevel@tonic-gate 			 */
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 			/* XXX if rebooting don't print this? */
892*0Sstevel@tonic-gate 			if (!terminal_state(f->uf_s) && must_unlock_failure) {
893*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
894*0Sstevel@tonic-gate 					"Unmounting %s while error-locked",
895*0Sstevel@tonic-gate 					fs_name(f));
896*0Sstevel@tonic-gate 			}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 			f->uf_ufsvfsp		= NULL;
899*0Sstevel@tonic-gate 			f->uf_vfs_ufsfxp	= NULL;
900*0Sstevel@tonic-gate 			f->uf_vfs_lockp		= NULL;
901*0Sstevel@tonic-gate 			f->uf_bp		= NULL;
902*0Sstevel@tonic-gate 			f->uf_vfsp		= NULL;
903*0Sstevel@tonic-gate 			f->uf_retry		= -1;
904*0Sstevel@tonic-gate 		}
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 		if (must_unlock_failure)
907*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 	if (must_unlock_list)
910*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	pollwakeup(&ufs_pollhd, POLLPRI | POLLHUP);
913*0Sstevel@tonic-gate 	MINUTE(("] "));
914*0Sstevel@tonic-gate }
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate /*
917*0Sstevel@tonic-gate  * ufsfx_(un)lockfs
918*0Sstevel@tonic-gate  *
919*0Sstevel@tonic-gate  * provides hook from lockfs code so we can recognize unlock/relock
920*0Sstevel@tonic-gate  *  This is called after it is certain that the (un)lock will succeed.
921*0Sstevel@tonic-gate  */
922*0Sstevel@tonic-gate void
923*0Sstevel@tonic-gate ufsfx_unlockfs(struct ufsvfs *ufsvfsp)
924*0Sstevel@tonic-gate {
925*0Sstevel@tonic-gate 	ufs_failure_t	*f;
926*0Sstevel@tonic-gate 	int		 need_unlock;
927*0Sstevel@tonic-gate 	int		 need_unlock_list;
928*0Sstevel@tonic-gate 	int		 informed = 0;
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_unlockfs"));
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	if (!ufsvfsp)
933*0Sstevel@tonic-gate 		return;
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 	need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	if (need_unlock_list)
938*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
943*0Sstevel@tonic-gate 		if (need_unlock)
944*0Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s)) {
947*0Sstevel@tonic-gate 			if (!(f->uf_s & UF_FIXING)) {
948*0Sstevel@tonic-gate 				/*
949*0Sstevel@tonic-gate 				 * This might happen if we don't notice that
950*0Sstevel@tonic-gate 				 * the fs gets marked FSFIX before it is
951*0Sstevel@tonic-gate 				 * marked FSCLEAN, as might occur if the
952*0Sstevel@tonic-gate 				 * the superblock was hammered directly.
953*0Sstevel@tonic-gate 				 */
954*0Sstevel@tonic-gate 				if (!informed) {
955*0Sstevel@tonic-gate 					informed = 1;
956*0Sstevel@tonic-gate 					cmn_err(CE_NOTE,
957*0Sstevel@tonic-gate 		    "Unlock of %s succeeded before fs_clean marked FSFIX?",
958*0Sstevel@tonic-gate 							    fs_name(f));
959*0Sstevel@tonic-gate 				}
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 				/*
962*0Sstevel@tonic-gate 				 * pass through fixing state so
963*0Sstevel@tonic-gate 				 * transition protocol is satisfied
964*0Sstevel@tonic-gate 				 */
965*0Sstevel@tonic-gate 				if (!set_state(f, UF_FIXING)) {
966*0Sstevel@tonic-gate 					MINUTE((": failed] "));
967*0Sstevel@tonic-gate 				}
968*0Sstevel@tonic-gate 			}
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 			if (!set_state(f, UF_FIXED)) {
971*0Sstevel@tonic-gate 				/* it's already fixed, so don't panic now */
972*0Sstevel@tonic-gate 				MINUTE((": failed] "));
973*0Sstevel@tonic-gate 			}
974*0Sstevel@tonic-gate 		}
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 		if (need_unlock)
977*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
978*0Sstevel@tonic-gate 	}
979*0Sstevel@tonic-gate 	if (need_unlock_list)
980*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
981*0Sstevel@tonic-gate 	MINUTE(("] "));
982*0Sstevel@tonic-gate }
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate void
985*0Sstevel@tonic-gate ufsfx_lockfs(struct ufsvfs *ufsvfsp)
986*0Sstevel@tonic-gate {
987*0Sstevel@tonic-gate 	ufs_failure_t	*f;
988*0Sstevel@tonic-gate 	int		 need_unlock;
989*0Sstevel@tonic-gate 	int		 need_unlock_list;
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_lockfs"));
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	if (!ufsvfsp)
994*0Sstevel@tonic-gate 		return;
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	if (need_unlock_list)
999*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
1004*0Sstevel@tonic-gate 		if (need_unlock)
1005*0Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s) &&
1008*0Sstevel@tonic-gate 		    f->uf_s != UF_PANIC) {
1009*0Sstevel@tonic-gate 			switch (f->uf_s) {
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 			default:
1012*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
1013*0Sstevel@tonic-gate 			"fs %s not in state UF_TRYLCK, UF_LOCKED or UF_FIXING",
1014*0Sstevel@tonic-gate 								fs_name(f));
1015*0Sstevel@tonic-gate 				break;
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 			case UF_TRYLCK:
1018*0Sstevel@tonic-gate 				if (!set_state(f, UF_LOCKED)) {
1019*0Sstevel@tonic-gate 					MINUTE((": failed] "));
1020*0Sstevel@tonic-gate 				}
1021*0Sstevel@tonic-gate 				break;
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 			case UF_LOCKED:
1024*0Sstevel@tonic-gate 				if (!set_state(f, UF_FIXING)) {
1025*0Sstevel@tonic-gate 					MINUTE((": failed] "));
1026*0Sstevel@tonic-gate 				}
1027*0Sstevel@tonic-gate 				break;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 			case UF_FIXING:
1030*0Sstevel@tonic-gate 				break;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 			}
1033*0Sstevel@tonic-gate 		}
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 		if (need_unlock)
1036*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
1037*0Sstevel@tonic-gate 	}
1038*0Sstevel@tonic-gate 	if (need_unlock_list)
1039*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	MINUTE(("] "));
1042*0Sstevel@tonic-gate }
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate /*
1045*0Sstevel@tonic-gate  * error lock, trigger fsck and unlock those fs with failures
1046*0Sstevel@tonic-gate  * blatantly copied from the hlock routine, although this routine
1047*0Sstevel@tonic-gate  * triggers differently in order to use uq_ne as meaningful data.
1048*0Sstevel@tonic-gate  */
1049*0Sstevel@tonic-gate /* ARGSUSED */
1050*0Sstevel@tonic-gate void
1051*0Sstevel@tonic-gate ufsfx_thread_fix_failures(void *ignored)
1052*0Sstevel@tonic-gate {
1053*0Sstevel@tonic-gate 	int		retry;
1054*0Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ufs_fix.uq_mutex, callb_generic_cpr,
1057*0Sstevel@tonic-gate 	    "ufsfixfail");
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_thread_fix_failures] "));
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	for (;;) {
1062*0Sstevel@tonic-gate 		/* sleep until there is work to do */
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
1065*0Sstevel@tonic-gate 		(void) ufs_thread_run(&ufs_fix, &cprinfo);
1066*0Sstevel@tonic-gate 		ufs_fix.uq_ne = 0;
1067*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate 		/* process failures on our q */
1070*0Sstevel@tonic-gate 		do {
1071*0Sstevel@tonic-gate 			retry = ufsfx_do_failure_q();
1072*0Sstevel@tonic-gate 			if (retry) {
1073*0Sstevel@tonic-gate 				mutex_enter(&ufs_fix.uq_mutex);
1074*0Sstevel@tonic-gate 				CALLB_CPR_SAFE_BEGIN(&cprinfo);
1075*0Sstevel@tonic-gate 				(void) cv_timedwait(&ufs_fix.uq_cv,
1076*0Sstevel@tonic-gate 							&ufs_fix.uq_mutex,
1077*0Sstevel@tonic-gate 							lbolt + (hz * retry));
1078*0Sstevel@tonic-gate 				CALLB_CPR_SAFE_END(&cprinfo,
1079*0Sstevel@tonic-gate 				    &ufs_fix.uq_mutex);
1080*0Sstevel@tonic-gate 				mutex_exit(&ufs_fix.uq_mutex);
1081*0Sstevel@tonic-gate 			}
1082*0Sstevel@tonic-gate 		} while (retry);
1083*0Sstevel@tonic-gate 	}
1084*0Sstevel@tonic-gate 	/* NOTREACHED */
1085*0Sstevel@tonic-gate }
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate /*
1089*0Sstevel@tonic-gate  * watch for fix-on-panic work
1090*0Sstevel@tonic-gate  *
1091*0Sstevel@tonic-gate  * returns # of seconds to sleep before trying again
1092*0Sstevel@tonic-gate  * and zero if no retry is needed
1093*0Sstevel@tonic-gate  */
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate int
1096*0Sstevel@tonic-gate ufsfx_do_failure_q(void)
1097*0Sstevel@tonic-gate {
1098*0Sstevel@tonic-gate 	ufs_failure_t	*f;
1099*0Sstevel@tonic-gate 	long		 retry = 1;
1100*0Sstevel@tonic-gate 	ufsd_t		*s;
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 	MAJOR(("[ufsfx_do_failure_q"));
1103*0Sstevel@tonic-gate 	DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
1104*0Sstevel@tonic-gate 
1105*0Sstevel@tonic-gate 	if (!mutex_tryenter(&ufs_fix.uq_mutex))
1106*0Sstevel@tonic-gate 		return (retry);
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate 	retry = 0;
1109*0Sstevel@tonic-gate rescan_q:
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 	/*
1112*0Sstevel@tonic-gate 	 * walk down failure list
1113*0Sstevel@tonic-gate 	 *  depending on state of each failure, do whatever
1114*0Sstevel@tonic-gate 	 *  is appropriate to move it to the next state
1115*0Sstevel@tonic-gate 	 *  taking note of whether retry gets set
1116*0Sstevel@tonic-gate 	 *
1117*0Sstevel@tonic-gate 	 * retry protocol:
1118*0Sstevel@tonic-gate 	 * wakeup in shortest required time for any failure
1119*0Sstevel@tonic-gate 	 *   retry == 0; nothing more to do (terminal state)
1120*0Sstevel@tonic-gate 	 *   retry < 0; reprocess queue immediately, retry will
1121*0Sstevel@tonic-gate 	 *		be abs(retry) for the next cycle
1122*0Sstevel@tonic-gate 	 *   retry > 0; schedule wakeup for retry seconds
1123*0Sstevel@tonic-gate 	 */
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex)) {
1128*0Sstevel@tonic-gate 			retry = 1;
1129*0Sstevel@tonic-gate 			continue;
1130*0Sstevel@tonic-gate 		}
1131*0Sstevel@tonic-gate 		s = get_state_desc(f->uf_s);
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 		MINOR((": found%s: %s, \"%s: %s\"\n",
1134*0Sstevel@tonic-gate 			    s->ud_attr.terminal? " old": "",
1135*0Sstevel@tonic-gate 			    fs_name(f), state_name(f->uf_s), f->uf_panic_str));
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 		if (s->ud_attr.terminal) {
1138*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
1139*0Sstevel@tonic-gate 			continue;
1140*0Sstevel@tonic-gate 		}
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 		if (s->ud_sfp)
1143*0Sstevel@tonic-gate 			(*s->ud_sfp)(f, UFA_FOUND, f->uf_s);
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 		ASSERT(terminal_state(f->uf_s) || f->uf_retry != 0);
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 		if (f->uf_retry != 0) {
1148*0Sstevel@tonic-gate 			if (retry > f->uf_retry || retry == 0)
1149*0Sstevel@tonic-gate 				retry = f->uf_retry;
1150*0Sstevel@tonic-gate 			if (f->uf_retry < 0)
1151*0Sstevel@tonic-gate 				f->uf_retry = abs(f->uf_retry);
1152*0Sstevel@tonic-gate 		}
1153*0Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
1154*0Sstevel@tonic-gate 	}
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 	if (retry < 0) {
1158*0Sstevel@tonic-gate 		retry = abs(retry);
1159*0Sstevel@tonic-gate 		goto rescan_q;
1160*0Sstevel@tonic-gate 	}
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate 	DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
1165*0Sstevel@tonic-gate 	MAJOR((": retry=%ld, good night]\n\n", retry));
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	return (retry);
1168*0Sstevel@tonic-gate }
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate static void
1171*0Sstevel@tonic-gate pester_msg(ufs_failure_t *f, int seriousness)
1172*0Sstevel@tonic-gate {
1173*0Sstevel@tonic-gate 	MINUTE(("[pester_msg"));
1174*0Sstevel@tonic-gate 	ASSERT(f->uf_s & (UF_LOCKED | UF_FIXING));
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	/*
1177*0Sstevel@tonic-gate 	 * XXX if seems too long for this fs, poke administrator
1178*0Sstevel@tonic-gate 	 * XXX to run fsck manually (and change retry time?)
1179*0Sstevel@tonic-gate 	 */
1180*0Sstevel@tonic-gate 	cmn_err(seriousness,
1181*0Sstevel@tonic-gate 		"Waiting for repair of %s to %s",
1182*0Sstevel@tonic-gate 			    fs_name(f),
1183*0Sstevel@tonic-gate 			    f->uf_s & UF_LOCKED? "start": "finish");
1184*0Sstevel@tonic-gate 	MINUTE(("]"));
1185*0Sstevel@tonic-gate }
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate static time_t
1188*0Sstevel@tonic-gate trylock_time_exceeded(ufs_failure_t *f)
1189*0Sstevel@tonic-gate {
1190*0Sstevel@tonic-gate 	time_t		toolong;
1191*0Sstevel@tonic-gate 	extern time_t	time;
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	MINUTE(("[trylock_time_exceeded"));
1194*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	toolong = (time_t)ufsfx_tune.uft_too_long + f->uf_entered_tm;
1197*0Sstevel@tonic-gate 	if (time > toolong)
1198*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "error-lock timeout exceeded: %s", fs_name(f));
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate 	MINUTE(("] "));
1201*0Sstevel@tonic-gate 	return (time <= toolong? 0: time - toolong);
1202*0Sstevel@tonic-gate }
1203*0Sstevel@tonic-gate 
1204*0Sstevel@tonic-gate static int
1205*0Sstevel@tonic-gate get_lockfs_status(ufs_failure_t *f, struct lockfs *lfp)
1206*0Sstevel@tonic-gate {
1207*0Sstevel@tonic-gate 	MINUTE(("[get_lockfs_status"));
1208*0Sstevel@tonic-gate 
1209*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
1210*0Sstevel@tonic-gate 		MINUTE((": ufsvfsp is NULL]\n"));
1211*0Sstevel@tonic-gate 		return (0);
1212*0Sstevel@tonic-gate 	}
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
1215*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
1216*0Sstevel@tonic-gate 	ASSERT(!vfs_lock_held(f->uf_vfsp));
1217*0Sstevel@tonic-gate 	ASSERT(f->uf_ufsvfsp->vfs_root != NULL);
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	f->uf_lf_err = ufs_fiolfss(f->uf_ufsvfsp->vfs_root, lfp);
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate 	if (f->uf_lf_err) {
1222*0Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
1223*0Sstevel@tonic-gate 	}
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 	MINUTE(("] "));
1226*0Sstevel@tonic-gate 	return (1);
1227*0Sstevel@tonic-gate }
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate static sfrc_t
1230*0Sstevel@tonic-gate set_state(ufs_failure_t *f, ufs_failure_states_t new_state)
1231*0Sstevel@tonic-gate {
1232*0Sstevel@tonic-gate 	ufsd_t		*s;
1233*0Sstevel@tonic-gate 	sfrc_t		 sfrc = SFRC_FAIL;
1234*0Sstevel@tonic-gate 	int		 need_unlock;
1235*0Sstevel@tonic-gate 	extern time_t	 time;
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 	HIDEOUS(("[set_state: new state:%s", state_name(new_state)));
1238*0Sstevel@tonic-gate 	ASSERT(f);
1239*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 	/*
1242*0Sstevel@tonic-gate 	 * if someone else is panicking, just let panic sync proceed
1243*0Sstevel@tonic-gate 	 */
1244*0Sstevel@tonic-gate 	if (panicstr) {
1245*0Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
1246*0Sstevel@tonic-gate 		HIDEOUS((": state reset: not fixed] "));
1247*0Sstevel@tonic-gate 		return (sfrc);
1248*0Sstevel@tonic-gate 	}
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 	/*
1251*0Sstevel@tonic-gate 	 * bad state transition, an internal error
1252*0Sstevel@tonic-gate 	 */
1253*0Sstevel@tonic-gate 	if (!state_trans_valid(f->uf_s, new_state)) {
1254*0Sstevel@tonic-gate 		/* recursion */
1255*0Sstevel@tonic-gate 		if (!(f->uf_s & UF_PANIC) && !(new_state & UF_PANIC))
1256*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1257*0Sstevel@tonic-gate 		MINOR((": state reset: transition failure (\"%s\"->\"%s\")] ",
1258*0Sstevel@tonic-gate 				state_name(f->uf_s), state_name(new_state)));
1259*0Sstevel@tonic-gate 		return (sfrc);
1260*0Sstevel@tonic-gate 	}
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 	s = get_state_desc(new_state);
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 	need_unlock = !MUTEX_HELD(&ufs_fix.uq_mutex);
1265*0Sstevel@tonic-gate 	if (need_unlock)
1266*0Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 	if (s->ud_attr.at_fail && ufs_fix.uq_threadp &&
1269*0Sstevel@tonic-gate 	    curthread == ufs_fix.uq_threadp) {
1270*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "set_state: probable recursive panic of %s",
1271*0Sstevel@tonic-gate 			fs_name(f));
1272*0Sstevel@tonic-gate 	}
1273*0Sstevel@tonic-gate 	if (need_unlock)
1274*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 	/* NULL state functions always succeed */
1277*0Sstevel@tonic-gate 	sfrc = !s->ud_sfp? SFRC_SUCCESS: (*s->ud_sfp)(f, UFA_SET, new_state);
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	if (sfrc == SFRC_SUCCESS && f->uf_s != new_state) {
1280*0Sstevel@tonic-gate 		f->uf_s = new_state;
1281*0Sstevel@tonic-gate 		f->uf_entered_tm = time;
1282*0Sstevel@tonic-gate 		f->uf_counter = 0;
1283*0Sstevel@tonic-gate 	}
1284*0Sstevel@tonic-gate 
1285*0Sstevel@tonic-gate 	HIDEOUS(("]\n"));
1286*0Sstevel@tonic-gate 	return (sfrc);
1287*0Sstevel@tonic-gate }
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate static ufsd_t *
1290*0Sstevel@tonic-gate get_state_desc(ufs_failure_states_t state)
1291*0Sstevel@tonic-gate {
1292*0Sstevel@tonic-gate 	ufsd_t *s;
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 	HIDEOUS(("[get_state_desc"));
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	for (s = &state_desc[1]; s->ud_name != NULL; s++) {
1297*0Sstevel@tonic-gate 		if (s->ud_v == state) {
1298*0Sstevel@tonic-gate 			HIDEOUS(("] "));
1299*0Sstevel@tonic-gate 			return (s);
1300*0Sstevel@tonic-gate 		}
1301*0Sstevel@tonic-gate 	}
1302*0Sstevel@tonic-gate 
1303*0Sstevel@tonic-gate 	HIDEOUS(("] "));
1304*0Sstevel@tonic-gate 	return (&state_desc[0]);	/* default */
1305*0Sstevel@tonic-gate }
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate static sfrc_t
1308*0Sstevel@tonic-gate sf_undef(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
1309*0Sstevel@tonic-gate {
1310*0Sstevel@tonic-gate 	sfrc_t rc;
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 	TRIVIA(("[sf_undef, action is %s, state is %s\n",
1313*0Sstevel@tonic-gate 		act_name(a), state_name(s)));
1314*0Sstevel@tonic-gate 	ASSERT(s == UF_UNDEF);
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate 	/* shouldn't find null failure records or ever set one */
1317*0Sstevel@tonic-gate 	rc = set_state(f, UF_NOTFIX);
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate 	TRIVIA(("] "));
1320*0Sstevel@tonic-gate 	return (rc);
1321*0Sstevel@tonic-gate }
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate static sfrc_t
1325*0Sstevel@tonic-gate sf_init(
1326*0Sstevel@tonic-gate 	ufs_failure_t	*f,
1327*0Sstevel@tonic-gate 	ufsa_t	 a,
1328*0Sstevel@tonic-gate 	ufs_failure_states_t	 s)
1329*0Sstevel@tonic-gate {
1330*0Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
1331*0Sstevel@tonic-gate 	extern time_t	time;
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate 	TRIVIA(("[sf_init, action is %s", act_name(a)));
1334*0Sstevel@tonic-gate 	ASSERT(s & UF_INIT);
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 	switch (a) {
1337*0Sstevel@tonic-gate 	case UFA_SET:
1338*0Sstevel@tonic-gate 		f->uf_begin_tm = time;
1339*0Sstevel@tonic-gate 		f->uf_retry = 1;
1340*0Sstevel@tonic-gate 		if (!f->uf_ufsvfsp) {
1341*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1342*0Sstevel@tonic-gate 			TRIVIA((": NULL ufsvfsp]\n"));
1343*0Sstevel@tonic-gate 			return (rc);
1344*0Sstevel@tonic-gate 		}
1345*0Sstevel@tonic-gate 		/*
1346*0Sstevel@tonic-gate 		 * because we can call panic from many different levels,
1347*0Sstevel@tonic-gate 		 * we can't be sure that we've got the vfs_lock at this
1348*0Sstevel@tonic-gate 		 * point.  However, there's not much alternative and if
1349*0Sstevel@tonic-gate 		 * we don't (have the lock) the worst case is we'll just
1350*0Sstevel@tonic-gate 		 * panic again
1351*0Sstevel@tonic-gate 		 */
1352*0Sstevel@tonic-gate 		f->uf_vfs_lockp		= &f->uf_ufsvfsp->vfs_lock;
1353*0Sstevel@tonic-gate 		f->uf_vfs_ufsfxp	= &f->uf_ufsvfsp->vfs_fsfx;
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 		if (!f->uf_ufsvfsp->vfs_bufp) {
1356*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1357*0Sstevel@tonic-gate 			TRIVIA((": NULL vfs_bufp]\n"));
1358*0Sstevel@tonic-gate 			return (rc);
1359*0Sstevel@tonic-gate 		}
1360*0Sstevel@tonic-gate 		f->uf_bp = f->uf_ufsvfsp->vfs_bufp;
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 		if (!f->uf_ufsvfsp->vfs_bufp->b_un.b_fs) {
1363*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1364*0Sstevel@tonic-gate 			TRIVIA((": NULL vfs_fs]\n"));
1365*0Sstevel@tonic-gate 			return (rc);
1366*0Sstevel@tonic-gate 		}
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 		/* vfs_fs = vfs_bufp->b_un.b_fs */
1369*0Sstevel@tonic-gate 		bcopy(f->uf_ufsvfsp->vfs_fs->fs_fsmnt, f->uf_fsname, MAXMNTLEN);
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate 		f->uf_lf.lf_lock  = LOCKFS_ELOCK;	/* primer */
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 		if (!f->uf_vfsp || f->uf_vfsp->vfs_dev == NODEV) {
1374*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1375*0Sstevel@tonic-gate 			TRIVIA((": NULL vfsp or vfs_dev == NODEV"));
1376*0Sstevel@tonic-gate 			return (rc);
1377*0Sstevel@tonic-gate 		}
1378*0Sstevel@tonic-gate 		f->uf_dev = f->uf_vfsp->vfs_dev;
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
1381*0Sstevel@tonic-gate 		break;
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate 	case UFA_FOUND:
1384*0Sstevel@tonic-gate 	default:
1385*0Sstevel@tonic-gate 		/* failures marked init shouldn't even be on the queue yet */
1386*0Sstevel@tonic-gate 		rc = set_state(f, UF_QUEUE);
1387*0Sstevel@tonic-gate 		TRIVIA((": found failure with state init]\n"));
1388*0Sstevel@tonic-gate 	}
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 	TRIVIA(("] "));
1391*0Sstevel@tonic-gate 	return (rc);
1392*0Sstevel@tonic-gate }
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate static sfrc_t
1395*0Sstevel@tonic-gate sf_queue(
1396*0Sstevel@tonic-gate 	ufs_failure_t	*f,
1397*0Sstevel@tonic-gate 	ufsa_t	 a,
1398*0Sstevel@tonic-gate 	ufs_failure_states_t	 s)
1399*0Sstevel@tonic-gate {
1400*0Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate 	TRIVIA(("[sf_queue, action is %s", act_name(a)));
1403*0Sstevel@tonic-gate 	ASSERT(s & UF_QUEUE);
1404*0Sstevel@tonic-gate 
1405*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
1406*0Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp]\n"));
1407*0Sstevel@tonic-gate 		return (rc);
1408*0Sstevel@tonic-gate 	}
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate 	switch (a) {
1411*0Sstevel@tonic-gate 	case UFA_FOUND:
1412*0Sstevel@tonic-gate 		rc = sf_found_queue(f);
1413*0Sstevel@tonic-gate 		break;
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	case UFA_SET:
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 		mutex_enter(&uf_stats.ufst_mutex);
1420*0Sstevel@tonic-gate 		uf_stats.ufst_num_failed++;
1421*0Sstevel@tonic-gate 		mutex_exit(&uf_stats.ufst_mutex);
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 		/*
1424*0Sstevel@tonic-gate 		 * if can't get the vfs lock, just wait until
1425*0Sstevel@tonic-gate 		 * UF_TRYLCK to set fx_current
1426*0Sstevel@tonic-gate 		 */
1427*0Sstevel@tonic-gate 		if (mutex_tryenter(f->uf_vfs_lockp)) {
1428*0Sstevel@tonic-gate 			f->uf_vfs_ufsfxp->fx_current = f;
1429*0Sstevel@tonic-gate 			mutex_exit(f->uf_vfs_lockp);
1430*0Sstevel@tonic-gate 		} else {
1431*0Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
1432*0Sstevel@tonic-gate 			uf_stats.ufst_current_races++;
1433*0Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
1434*0Sstevel@tonic-gate 		}
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate 		f->uf_retry = 1;
1437*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
1438*0Sstevel@tonic-gate 		TRIVIA(("] "));
1439*0Sstevel@tonic-gate 		break;
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 	default:
1442*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1443*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1444*0Sstevel@tonic-gate 	}
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 	return (rc);
1447*0Sstevel@tonic-gate }
1448*0Sstevel@tonic-gate 
1449*0Sstevel@tonic-gate static sfrc_t
1450*0Sstevel@tonic-gate sf_found_queue(ufs_failure_t *f)
1451*0Sstevel@tonic-gate {
1452*0Sstevel@tonic-gate 	int		replica;
1453*0Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
1454*0Sstevel@tonic-gate 
1455*0Sstevel@tonic-gate 	TRIVIA(("[sf_found_queue"));
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 	/*
1458*0Sstevel@tonic-gate 	 * don't need to check for null ufsvfsp because
1459*0Sstevel@tonic-gate 	 * unmount must own list's ufs_fix.uq_mutex
1460*0Sstevel@tonic-gate 	 * to mark it null and we own that lock since
1461*0Sstevel@tonic-gate 	 * we got here.
1462*0Sstevel@tonic-gate 	 */
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
1465*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 	if (!mutex_tryenter(f->uf_vfs_lockp)) {
1468*0Sstevel@tonic-gate 		TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
1469*0Sstevel@tonic-gate 		f->uf_retry = 1;
1470*0Sstevel@tonic-gate 		return (rc);
1471*0Sstevel@tonic-gate 	}
1472*0Sstevel@tonic-gate 
1473*0Sstevel@tonic-gate 	replica = f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current != NULL &&
1474*0Sstevel@tonic-gate 		    f->uf_vfs_ufsfxp->fx_current != f &&
1475*0Sstevel@tonic-gate 		    !terminal_state(f->uf_vfs_ufsfxp->fx_current->uf_s);
1476*0Sstevel@tonic-gate 
1477*0Sstevel@tonic-gate 	/*
1478*0Sstevel@tonic-gate 	 * copy general flags to this ufs_failure so we don't
1479*0Sstevel@tonic-gate 	 * need to refer back to the ufsvfs, or, more importantly,
1480*0Sstevel@tonic-gate 	 * don't need to keep acquiring (trying to acquire) vfs_lockp
1481*0Sstevel@tonic-gate 	 *
1482*0Sstevel@tonic-gate 	 * The most restrictive option wins:
1483*0Sstevel@tonic-gate 	 *  panic > errlock only > errlock+unmount > repair
1484*0Sstevel@tonic-gate 	 * XXX panic > elock > elock > elock+umount
1485*0Sstevel@tonic-gate 	 */
1486*0Sstevel@tonic-gate 	if (f->uf_vfs_ufsfxp->fx_flags & UFSFX_PANIC) {
1487*0Sstevel@tonic-gate 		if (!set_state(f, UF_PANIC)) {
1488*0Sstevel@tonic-gate 			TRIVIA((": marked panic but was queued?"));
1489*0Sstevel@tonic-gate 			real_panic(f, " ");
1490*0Sstevel@tonic-gate 			/*NOTREACHED*/
1491*0Sstevel@tonic-gate 		}
1492*0Sstevel@tonic-gate 		mutex_exit(f->uf_vfs_lockp);
1493*0Sstevel@tonic-gate 		return (rc);
1494*0Sstevel@tonic-gate 	}
1495*0Sstevel@tonic-gate 	f->uf_flags = f->uf_vfs_ufsfxp->fx_flags;
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	if (replica) {
1498*0Sstevel@tonic-gate 		if (!set_state(f, UF_REPLICA)) {
1499*0Sstevel@tonic-gate 			f->uf_retry = 1;
1500*0Sstevel@tonic-gate 			TRIVIA((": set to replica failed] "));
1501*0Sstevel@tonic-gate 		} else {
1502*0Sstevel@tonic-gate 			TRIVIA(("] "));
1503*0Sstevel@tonic-gate 		}
1504*0Sstevel@tonic-gate 		mutex_exit(f->uf_vfs_lockp);
1505*0Sstevel@tonic-gate 		return (rc);
1506*0Sstevel@tonic-gate 	}
1507*0Sstevel@tonic-gate 	mutex_exit(f->uf_vfs_lockp);
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate 	if (!set_state(f, UF_TRYLCK)) {
1510*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1511*0Sstevel@tonic-gate 	} else {
1512*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
1513*0Sstevel@tonic-gate 	}
1514*0Sstevel@tonic-gate 	return (rc);
1515*0Sstevel@tonic-gate }
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate static sfrc_t
1518*0Sstevel@tonic-gate sf_nonterm_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
1519*0Sstevel@tonic-gate {
1520*0Sstevel@tonic-gate 	sfrc_t	rc = SFRC_FAIL;
1521*0Sstevel@tonic-gate 
1522*0Sstevel@tonic-gate 	TRIVIA(("[sf_nonterm_cmn, action: %s, %s", act_name(a), state_name(s)));
1523*0Sstevel@tonic-gate 	ASSERT(s & (UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING));
1524*0Sstevel@tonic-gate 	ASSERT(!terminal_state(s));
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp && !(f->uf_s & UF_UMOUNT)) {
1527*0Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp (state != UMOUNT)]\n"));
1528*0Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
1529*0Sstevel@tonic-gate 		return (rc);
1530*0Sstevel@tonic-gate 	}
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	switch (a) {
1533*0Sstevel@tonic-gate 	case UFA_SET:
1534*0Sstevel@tonic-gate 		switch (s) {
1535*0Sstevel@tonic-gate 		case UF_TRYLCK:
1536*0Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
1537*0Sstevel@tonic-gate 			rc = sf_set_trylck(f);
1538*0Sstevel@tonic-gate 			break;
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 		case UF_LOCKED:
1541*0Sstevel@tonic-gate 			rc = sf_set_locked(f);
1542*0Sstevel@tonic-gate 			break;
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate 		case UF_FIXING:
1545*0Sstevel@tonic-gate 			f->uf_flags |= UFSFX_REPAIR_START;
1546*0Sstevel@tonic-gate 			f->uf_retry  = ufsfx_tune.uft_fixpoll_period;
1547*0Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
1548*0Sstevel@tonic-gate 			break;
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate 		case UF_UMOUNT:
1551*0Sstevel@tonic-gate 			f->uf_retry = -ufsfx_tune.uft_short_err_period;
1552*0Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
1553*0Sstevel@tonic-gate 			break;
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 		default:
1556*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1557*0Sstevel@tonic-gate 			TRIVIA((": failed] "));
1558*0Sstevel@tonic-gate 		}
1559*0Sstevel@tonic-gate 		break;
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate 	case UFA_FOUND:
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 		switch (s) {
1564*0Sstevel@tonic-gate 		case UF_TRYLCK:
1565*0Sstevel@tonic-gate 			rc = sf_found_trylck(f);
1566*0Sstevel@tonic-gate 			break;
1567*0Sstevel@tonic-gate 
1568*0Sstevel@tonic-gate 		case UF_LOCKED:
1569*0Sstevel@tonic-gate 		case UF_FIXING:
1570*0Sstevel@tonic-gate 			rc = sf_found_lock_fix_cmn(f, s);
1571*0Sstevel@tonic-gate 			break;
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 		case UF_UMOUNT:
1574*0Sstevel@tonic-gate 			rc = sf_found_umount(f);
1575*0Sstevel@tonic-gate 			break;
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate 		default:
1578*0Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
1579*0Sstevel@tonic-gate 			TRIVIA((": failed] "));
1580*0Sstevel@tonic-gate 			break;
1581*0Sstevel@tonic-gate 		}
1582*0Sstevel@tonic-gate 		break;
1583*0Sstevel@tonic-gate 	default:
1584*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1585*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1586*0Sstevel@tonic-gate 		break;
1587*0Sstevel@tonic-gate 	}
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	TRIVIA(("] "));
1590*0Sstevel@tonic-gate 	return (rc);
1591*0Sstevel@tonic-gate }
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate static sfrc_t
1594*0Sstevel@tonic-gate sf_set_trylck(ufs_failure_t *f)
1595*0Sstevel@tonic-gate {
1596*0Sstevel@tonic-gate 	TRIVIA(("[sf_set_trylck"));
1597*0Sstevel@tonic-gate 
1598*0Sstevel@tonic-gate 	if (!mutex_tryenter(f->uf_vfs_lockp)) {
1599*0Sstevel@tonic-gate 		TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
1600*0Sstevel@tonic-gate 		f->uf_retry = 1;
1601*0Sstevel@tonic-gate 		return (SFRC_FAIL);
1602*0Sstevel@tonic-gate 	}
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	if (!f->uf_vfs_ufsfxp->fx_current)
1605*0Sstevel@tonic-gate 		f->uf_vfs_ufsfxp->fx_current = f;
1606*0Sstevel@tonic-gate 
1607*0Sstevel@tonic-gate 	mutex_exit(f->uf_vfs_lockp);
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate 	f->uf_lf.lf_flags = 0;
1610*0Sstevel@tonic-gate 	f->uf_lf.lf_lock  = LOCKFS_ELOCK;
1611*0Sstevel@tonic-gate 	f->uf_retry = -ufsfx_tune.uft_fixstart_period;
1612*0Sstevel@tonic-gate 	TRIVIA(("] "));
1613*0Sstevel@tonic-gate 	return (SFRC_SUCCESS);
1614*0Sstevel@tonic-gate }
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate static sfrc_t
1617*0Sstevel@tonic-gate sf_found_trylck(ufs_failure_t *f)
1618*0Sstevel@tonic-gate {
1619*0Sstevel@tonic-gate 	struct lockfs lockfs_status;
1620*0Sstevel@tonic-gate 
1621*0Sstevel@tonic-gate 	TRIVIA(("[sf_found_trylck"));
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 	if (trylock_time_exceeded(f) > 0) {
1624*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1625*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1626*0Sstevel@tonic-gate 		return (SFRC_FAIL);
1627*0Sstevel@tonic-gate 	}
1628*0Sstevel@tonic-gate 
1629*0Sstevel@tonic-gate 	if (!get_lockfs_status(f, &lockfs_status)) {
1630*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1631*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1632*0Sstevel@tonic-gate 		return (SFRC_FAIL);
1633*0Sstevel@tonic-gate 	}
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 	if (f->uf_lf_err == NO_ERROR)
1636*0Sstevel@tonic-gate 		f->uf_lf.lf_key = lockfs_status.lf_key;
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate 	if (!set_lockfs(f, &lockfs_status)) {
1639*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1640*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1641*0Sstevel@tonic-gate 		return (SFRC_FAIL);
1642*0Sstevel@tonic-gate 	}
1643*0Sstevel@tonic-gate 	TRIVIA(("] "));
1644*0Sstevel@tonic-gate 	return (SFRC_SUCCESS);
1645*0Sstevel@tonic-gate }
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate static sfrc_t
1648*0Sstevel@tonic-gate sf_set_locked(ufs_failure_t *f)
1649*0Sstevel@tonic-gate {
1650*0Sstevel@tonic-gate 	TRIVIA(("[sf_set_locked"));
1651*0Sstevel@tonic-gate 
1652*0Sstevel@tonic-gate 	f->uf_retry = -ufsfx_tune.uft_fixstart_period;
1653*0Sstevel@tonic-gate 
1654*0Sstevel@tonic-gate #if defined(DEBUG)
1655*0Sstevel@tonic-gate 	if (f->uf_flags & UFSFX_REPAIR_START)
1656*0Sstevel@tonic-gate 		TRIVIA(("clearing UFSFX_REPAIR_START "));
1657*0Sstevel@tonic-gate #endif /* DEBUG */
1658*0Sstevel@tonic-gate 
1659*0Sstevel@tonic-gate 	f->uf_flags &= ~UFSFX_REPAIR_START;
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 	if (f->uf_s & UF_TRYLCK) {
1662*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "Error-locked %s: \"%s\"",
1663*0Sstevel@tonic-gate 				    fs_name(f), f->uf_panic_str);
1664*0Sstevel@tonic-gate 
1665*0Sstevel@tonic-gate 		if (f->uf_flags & UFSFX_LCKONLY)
1666*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "Manual repair of %s required",
1667*0Sstevel@tonic-gate 								fs_name(f));
1668*0Sstevel@tonic-gate 	}
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 	/*
1671*0Sstevel@tonic-gate 	 * just reset to current state
1672*0Sstevel@tonic-gate 	 */
1673*0Sstevel@tonic-gate #if defined(DEBUG)
1674*0Sstevel@tonic-gate 	TRIVIA(("locked->locked "));
1675*0Sstevel@tonic-gate #endif /* DEBUG */
1676*0Sstevel@tonic-gate 
1677*0Sstevel@tonic-gate 	TRIVIA(("] "));
1678*0Sstevel@tonic-gate 	return (SFRC_SUCCESS);
1679*0Sstevel@tonic-gate }
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate static sfrc_t
1682*0Sstevel@tonic-gate sf_found_lock_fix_cmn(ufs_failure_t *f, ufs_failure_states_t s)
1683*0Sstevel@tonic-gate {
1684*0Sstevel@tonic-gate 	time_t		toolong;
1685*0Sstevel@tonic-gate 	extern time_t	time;
1686*0Sstevel@tonic-gate 	struct buf	*bp			= NULL;
1687*0Sstevel@tonic-gate 	struct fs	*dfs;
1688*0Sstevel@tonic-gate 	time_t		 concerned, anxious;
1689*0Sstevel@tonic-gate 	sfrc_t		 rc			= SFRC_FAIL;
1690*0Sstevel@tonic-gate 	ulong_t		 gb_size;
1691*0Sstevel@tonic-gate 
1692*0Sstevel@tonic-gate 	TRIVIA(("[sf_found_lock_fix_cmn (\"%s\")", state_name(s)));
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate 	if (s & UF_LOCKED) {
1695*0Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&f->uf_mutex));
1696*0Sstevel@tonic-gate 
1697*0Sstevel@tonic-gate 		toolong = time > (ufsfx_tune.uft_too_long +
1698*0Sstevel@tonic-gate 							f->uf_entered_tm);
1699*0Sstevel@tonic-gate 		TRIVIA(("%stoolong", !toolong? "not": ""));
1700*0Sstevel@tonic-gate 		HIDEOUS((": time:%ld, too long:%ld, entered_tm:%ld ",
1701*0Sstevel@tonic-gate 		    time, ufsfx_tune.uft_too_long, f->uf_entered_tm));
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 		if (f->uf_flags & UFSFX_LCKUMOUNT) {
1704*0Sstevel@tonic-gate 			if (set_state(f, UF_UMOUNT)) {
1705*0Sstevel@tonic-gate 				TRIVIA(("] "));
1706*0Sstevel@tonic-gate 				rc = SFRC_SUCCESS;
1707*0Sstevel@tonic-gate 			} else {
1708*0Sstevel@tonic-gate 				TRIVIA((": failed] "));
1709*0Sstevel@tonic-gate 				f->uf_retry = 1;
1710*0Sstevel@tonic-gate 			}
1711*0Sstevel@tonic-gate 			return (rc);
1712*0Sstevel@tonic-gate 		}
1713*0Sstevel@tonic-gate 		if (!toolong) {
1714*0Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
1715*0Sstevel@tonic-gate 		} else {
1716*0Sstevel@tonic-gate 			if (!(f->uf_flags & UFSFX_REPAIR_START)) {
1717*0Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s repair of %s not started.",
1718*0Sstevel@tonic-gate 						(f->uf_flags & UFSFX_LCKONLY)?
1719*0Sstevel@tonic-gate 						"Manual": "Automatic",
1720*0Sstevel@tonic-gate 						fs_name(f));
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 				f->uf_retry = ufsfx_tune.uft_long_err_period;
1723*0Sstevel@tonic-gate 			} else {
1724*0Sstevel@tonic-gate 				f->uf_retry = ufsfx_tune.uft_long_err_period;
1725*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
1726*0Sstevel@tonic-gate 		"Repair of %s is not timely; operator attention is required.",
1727*0Sstevel@tonic-gate 								    fs_name(f));
1728*0Sstevel@tonic-gate 			}
1729*0Sstevel@tonic-gate 			TRIVIA(("] "));
1730*0Sstevel@tonic-gate 			return (rc);
1731*0Sstevel@tonic-gate 		}
1732*0Sstevel@tonic-gate 	}
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate #if defined(DEBUG)
1735*0Sstevel@tonic-gate 	else {
1736*0Sstevel@tonic-gate 		ASSERT(s & UF_FIXING);
1737*0Sstevel@tonic-gate 	}
1738*0Sstevel@tonic-gate #endif /* DEBUG */
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate 	/*
1741*0Sstevel@tonic-gate 	 * get on disk superblock; force it to really
1742*0Sstevel@tonic-gate 	 * come from the disk
1743*0Sstevel@tonic-gate 	 */
1744*0Sstevel@tonic-gate 	(void) bfinval(f->uf_dev, 0);
1745*0Sstevel@tonic-gate 	bp = UFS_BREAD(f->uf_ufsvfsp, f->uf_dev, SBLOCK, SBSIZE);
1746*0Sstevel@tonic-gate 	if (bp) {
1747*0Sstevel@tonic-gate 		bp->b_flags |= (B_STALE | B_AGE);
1748*0Sstevel@tonic-gate 		dfs = bp->b_un.b_fs;
1749*0Sstevel@tonic-gate 	}
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 	if (!bp || (bp->b_flags & B_ERROR) || ((dfs->fs_magic != FS_MAGIC) &&
1752*0Sstevel@tonic-gate 	    (dfs->fs_magic != MTB_UFS_MAGIC))) {
1753*0Sstevel@tonic-gate 		TRIVIA((": UFS_BREAD(SBLOCK) failed]\n"));
1754*0Sstevel@tonic-gate 		f->uf_retry = 1;
1755*0Sstevel@tonic-gate 		goto out;
1756*0Sstevel@tonic-gate 	}
1757*0Sstevel@tonic-gate 
1758*0Sstevel@tonic-gate 	/* fsck started but we haven't noticed yet? */
1759*0Sstevel@tonic-gate 	if (!(s & UF_FIXING) && dfs->fs_clean == FSFIX) {
1760*0Sstevel@tonic-gate 		if (!set_state(f, UF_FIXING)) {
1761*0Sstevel@tonic-gate 			TRIVIA((": failed]\n"));
1762*0Sstevel@tonic-gate 			f->uf_retry = 1;
1763*0Sstevel@tonic-gate 			goto out;
1764*0Sstevel@tonic-gate 		}
1765*0Sstevel@tonic-gate 	}
1766*0Sstevel@tonic-gate 
1767*0Sstevel@tonic-gate 	/* fsck started but didn't succeed? */
1768*0Sstevel@tonic-gate 	if ((s & UF_FIXING) && ((dfs->fs_clean == FSBAD) || !fsck_active(f))) {
1769*0Sstevel@tonic-gate 		TRIVIA((": fs_clean: %d", (int)dfs->fs_clean));
1770*0Sstevel@tonic-gate 		(void) set_state(f, UF_LOCKED);
1771*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: Manual repair is necessary.", fs_name(f));
1772*0Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_long_err_period;
1773*0Sstevel@tonic-gate 		goto out;
1774*0Sstevel@tonic-gate 	}
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 	gb_size = (dfs->fs_size * dfs->fs_bshift) / GB;
1777*0Sstevel@tonic-gate 	toolong = (time_t)((gb_size == 0? 1: gb_size) * SecondsPerGig);
1778*0Sstevel@tonic-gate 
1779*0Sstevel@tonic-gate 	/* fsck started but doesn't seem to be proceeding? */
1780*0Sstevel@tonic-gate 	if ((s & UF_FIXING) && dfs->fs_clean == FSFIX) {
1781*0Sstevel@tonic-gate 		if (time > f->uf_entered_tm + toolong) {
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
1784*0Sstevel@tonic-gate "Repair completion timeout exceeded on %s; manual fsck may be required",
1785*0Sstevel@tonic-gate 								    fs_name(f));
1786*0Sstevel@tonic-gate 			f->uf_retry = ufsfx_tune.uft_long_err_period;
1787*0Sstevel@tonic-gate 		}
1788*0Sstevel@tonic-gate 	}
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate 	concerned = f->uf_entered_tm + (toolong / 3);
1791*0Sstevel@tonic-gate 	anxious = f->uf_entered_tm + ((2 * toolong) / 3);
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	if (time > concerned)
1794*0Sstevel@tonic-gate 		pester_msg(f, time > anxious? CE_WARN: CE_NOTE);
1795*0Sstevel@tonic-gate 
1796*0Sstevel@tonic-gate 	TRIVIA(("] "));
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate out:
1799*0Sstevel@tonic-gate 	if (bp)
1800*0Sstevel@tonic-gate 		brelse(bp);
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	return (rc);
1803*0Sstevel@tonic-gate }
1804*0Sstevel@tonic-gate 
1805*0Sstevel@tonic-gate static sfrc_t
1806*0Sstevel@tonic-gate sf_found_umount(ufs_failure_t *f)
1807*0Sstevel@tonic-gate {
1808*0Sstevel@tonic-gate 	extern time_t	 time;
1809*0Sstevel@tonic-gate 	sfrc_t		 rc			= SFRC_FAIL;
1810*0Sstevel@tonic-gate 	struct vfs	*vfsp			= f->uf_vfsp;
1811*0Sstevel@tonic-gate 	struct ufsvfs	*ufsvfsp		= f->uf_ufsvfsp;
1812*0Sstevel@tonic-gate 	int		 toolong		= 0;
1813*0Sstevel@tonic-gate 	int		 err			= 0;
1814*0Sstevel@tonic-gate 
1815*0Sstevel@tonic-gate 	TRIVIA(("[sf_found_umount"));
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 	toolong = time > ufsfx_tune.uft_too_long + f->uf_entered_tm;
1818*0Sstevel@tonic-gate 	if (toolong) {
1819*0Sstevel@tonic-gate 		TRIVIA((": unmount time limit exceeded] "));
1820*0Sstevel@tonic-gate 		goto out;
1821*0Sstevel@tonic-gate 	}
1822*0Sstevel@tonic-gate 
1823*0Sstevel@tonic-gate 	if (!vfsp || !ufsvfsp) {	/* trivial case */
1824*0Sstevel@tonic-gate 		TRIVIA((": NULL vfsp and/or ufsvfsp, already unmounted?] "));
1825*0Sstevel@tonic-gate 		goto out;
1826*0Sstevel@tonic-gate 	}
1827*0Sstevel@tonic-gate 
1828*0Sstevel@tonic-gate 	if (!ULOCKFS_IS_ELOCK(&ufsvfsp->vfs_ulockfs)) {
1829*0Sstevel@tonic-gate 		TRIVIA((": !not error locked?"));
1830*0Sstevel@tonic-gate 		err = EINVAL;
1831*0Sstevel@tonic-gate 		goto out;
1832*0Sstevel@tonic-gate 	}
1833*0Sstevel@tonic-gate 
1834*0Sstevel@tonic-gate 	/* The vn_vfsunlock will be done in dounmount() [.../common/fs/vfs.c] */
1835*0Sstevel@tonic-gate 	if (vn_vfslock(vfsp->vfs_vnodecovered)) {
1836*0Sstevel@tonic-gate 		TRIVIA((": couldn't lock coveredvp"));
1837*0Sstevel@tonic-gate 		err = EBUSY;
1838*0Sstevel@tonic-gate 		goto out;
1839*0Sstevel@tonic-gate 	}
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 	if ((err = dounmount(vfsp, 0, kcred)) != 0) {
1842*0Sstevel@tonic-gate 
1843*0Sstevel@tonic-gate 		/* take note, but not many alternatives here */
1844*0Sstevel@tonic-gate 		mutex_enter(&uf_stats.ufst_mutex);
1845*0Sstevel@tonic-gate 		uf_stats.ufst_unmount_failures++;
1846*0Sstevel@tonic-gate 		mutex_exit(&uf_stats.ufst_mutex);
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 		TRIVIA((": unmount failed] "));
1849*0Sstevel@tonic-gate 	} else {
1850*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "unmounted error-locked %s", fs_name(f));
1851*0Sstevel@tonic-gate 	}
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate out:
1854*0Sstevel@tonic-gate 	if (toolong || (err != EBUSY && err != EAGAIN))
1855*0Sstevel@tonic-gate 		rc = set_state(f, UF_NOTFIX);
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 	TRIVIA(("] "));
1858*0Sstevel@tonic-gate 	return (rc);
1859*0Sstevel@tonic-gate }
1860*0Sstevel@tonic-gate 
1861*0Sstevel@tonic-gate static sfrc_t
1862*0Sstevel@tonic-gate sf_term_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
1863*0Sstevel@tonic-gate {
1864*0Sstevel@tonic-gate 	extern time_t	time;
1865*0Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
1866*0Sstevel@tonic-gate 
1867*0Sstevel@tonic-gate 	TRIVIA(("[sf_term_cmn, action is %s, state is %s",
1868*0Sstevel@tonic-gate 						act_name(a), state_name(s)));
1869*0Sstevel@tonic-gate 	ASSERT(s & (UF_FIXED | UF_NOTFIX | UF_REPLICA));
1870*0Sstevel@tonic-gate 	ASSERT(terminal_state(s));
1871*0Sstevel@tonic-gate 
1872*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp && !(f->uf_s & (UF_UMOUNT | UF_NOTFIX))) {
1873*0Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp (state != UMOUNT | NOTFIX)]\n"));
1874*0Sstevel@tonic-gate 		return (rc);
1875*0Sstevel@tonic-gate 	}
1876*0Sstevel@tonic-gate 
1877*0Sstevel@tonic-gate 	switch (a) {
1878*0Sstevel@tonic-gate 	case UFA_SET:
1879*0Sstevel@tonic-gate 		switch (s) {
1880*0Sstevel@tonic-gate 		case UF_NOTFIX:
1881*0Sstevel@tonic-gate 		case UF_FIXED:
1882*0Sstevel@tonic-gate 		{	int need_lock_vfs;
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 			if (f->uf_ufsvfsp && f->uf_vfs_lockp)
1885*0Sstevel@tonic-gate 				need_lock_vfs = !MUTEX_HELD(f->uf_vfs_lockp);
1886*0Sstevel@tonic-gate 			else
1887*0Sstevel@tonic-gate 				need_lock_vfs = 0;
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate 			if (need_lock_vfs && !mutex_tryenter(f->uf_vfs_lockp)) {
1890*0Sstevel@tonic-gate 				TRIVIA((": tryenter(vfslockp) fail; retry]\n"));
1891*0Sstevel@tonic-gate 				f->uf_retry = 1;
1892*0Sstevel@tonic-gate 				break;
1893*0Sstevel@tonic-gate 			}
1894*0Sstevel@tonic-gate 
1895*0Sstevel@tonic-gate 			f->uf_end_tm = time;
1896*0Sstevel@tonic-gate 			f->uf_lf.lf_lock = LOCKFS_OLOCK;
1897*0Sstevel@tonic-gate 			f->uf_retry = 0;
1898*0Sstevel@tonic-gate 
1899*0Sstevel@tonic-gate 			if (f->uf_vfs_ufsfxp)
1900*0Sstevel@tonic-gate 				f->uf_vfs_ufsfxp->fx_current = NULL;
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate 			if (need_lock_vfs)
1903*0Sstevel@tonic-gate 				mutex_exit(f->uf_vfs_lockp);
1904*0Sstevel@tonic-gate 
1905*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, (s & UF_NOTFIX)? "Could not fix %s":
1906*0Sstevel@tonic-gate 				    "%s is now accessible", fs_name(f));
1907*0Sstevel@tonic-gate 
1908*0Sstevel@tonic-gate 			if (s & UF_FIXED) {
1909*0Sstevel@tonic-gate 				mutex_enter(&uf_stats.ufst_mutex);
1910*0Sstevel@tonic-gate 				uf_stats.ufst_num_fixed++;
1911*0Sstevel@tonic-gate 				mutex_exit(&uf_stats.ufst_mutex);
1912*0Sstevel@tonic-gate 			}
1913*0Sstevel@tonic-gate 			(void) timeout(ufsfx_kill_fix_failure_thread,
1914*0Sstevel@tonic-gate 			    (void *)(ufsfx_tune.uft_short_err_period * hz),
1915*0Sstevel@tonic-gate 			    ufsfx_tune.uft_short_err_period * hz);
1916*0Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
1917*0Sstevel@tonic-gate 			break;
1918*0Sstevel@tonic-gate 		}
1919*0Sstevel@tonic-gate 		case UF_REPLICA:
1920*0Sstevel@tonic-gate 
1921*0Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(f->uf_vfs_lockp));
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate 			/* not actually a replica? */
1924*0Sstevel@tonic-gate 			if (f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current &&
1925*0Sstevel@tonic-gate 			    f->uf_vfs_ufsfxp->fx_current != f &&
1926*0Sstevel@tonic-gate 			!terminal_state(f->uf_vfs_ufsfxp->fx_current->uf_s)) {
1927*0Sstevel@tonic-gate 
1928*0Sstevel@tonic-gate 				f->uf_orig = f->uf_vfs_ufsfxp->fx_current;
1929*0Sstevel@tonic-gate 				f->uf_retry = 0;
1930*0Sstevel@tonic-gate 				rc = SFRC_SUCCESS;
1931*0Sstevel@tonic-gate 			} else {
1932*0Sstevel@tonic-gate 				TRIVIA((": NULL fx_current]\n"));
1933*0Sstevel@tonic-gate 				f->uf_retry = 1;
1934*0Sstevel@tonic-gate 			}
1935*0Sstevel@tonic-gate 
1936*0Sstevel@tonic-gate 			break;
1937*0Sstevel@tonic-gate 
1938*0Sstevel@tonic-gate 		default:
1939*0Sstevel@tonic-gate 			rc = set_state(f, UF_PANIC);
1940*0Sstevel@tonic-gate 			TRIVIA((": failed] "));
1941*0Sstevel@tonic-gate 			break;
1942*0Sstevel@tonic-gate 		}
1943*0Sstevel@tonic-gate 		break;
1944*0Sstevel@tonic-gate 
1945*0Sstevel@tonic-gate 	case UFA_FOUND:
1946*0Sstevel@tonic-gate 		/*
1947*0Sstevel@tonic-gate 		 * XXX de-allocate these after some period?
1948*0Sstevel@tonic-gate 		 * XXX or move to an historical list?
1949*0Sstevel@tonic-gate 		 * XXX or have an ioctl which reaps them?
1950*0Sstevel@tonic-gate 		 */
1951*0Sstevel@tonic-gate 		/*
1952*0Sstevel@tonic-gate 		 * For now, since we don't expect lots of failures
1953*0Sstevel@tonic-gate 		 * to occur (to the point of memory shortages),
1954*0Sstevel@tonic-gate 		 * just punt
1955*0Sstevel@tonic-gate 		 */
1956*0Sstevel@tonic-gate 
1957*0Sstevel@tonic-gate 		/* be sure we're not wasting cpu on old failures */
1958*0Sstevel@tonic-gate 		if (f->uf_retry != 0) {
1959*0Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
1960*0Sstevel@tonic-gate 			uf_stats.ufst_cpu_waste++;
1961*0Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
1962*0Sstevel@tonic-gate 			f->uf_retry = 0;
1963*0Sstevel@tonic-gate 		}
1964*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
1965*0Sstevel@tonic-gate 		break;
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	default:
1968*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
1969*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
1970*0Sstevel@tonic-gate 		break;
1971*0Sstevel@tonic-gate 	}
1972*0Sstevel@tonic-gate 
1973*0Sstevel@tonic-gate 	TRIVIA(("] "));
1974*0Sstevel@tonic-gate 	return (rc);
1975*0Sstevel@tonic-gate }
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate static sfrc_t
1978*0Sstevel@tonic-gate sf_panic(
1979*0Sstevel@tonic-gate 	ufs_failure_t	*f,
1980*0Sstevel@tonic-gate 	ufsa_t	 a,
1981*0Sstevel@tonic-gate 	ufs_failure_states_t	 s)
1982*0Sstevel@tonic-gate {
1983*0Sstevel@tonic-gate 	sfrc_t	rc = SFRC_FAIL;
1984*0Sstevel@tonic-gate 
1985*0Sstevel@tonic-gate 	TRIVIA(("[sf_panic, action is %s, prev. state is %s",
1986*0Sstevel@tonic-gate 		act_name(a), state_name(f->uf_s)));
1987*0Sstevel@tonic-gate 	ASSERT(s & UF_PANIC);
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate 	switch (a) {
1990*0Sstevel@tonic-gate 	case UFA_SET:
1991*0Sstevel@tonic-gate 		f->uf_retry = -ufsfx_tune.uft_short_err_period;
1992*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
1993*0Sstevel@tonic-gate 		break;
1994*0Sstevel@tonic-gate 
1995*0Sstevel@tonic-gate 	case UFA_FOUND:
1996*0Sstevel@tonic-gate 	default:
1997*0Sstevel@tonic-gate 		real_panic(f, " ");
1998*0Sstevel@tonic-gate 
1999*0Sstevel@tonic-gate 		/* LINTED: warning: logical expression always true: op "||" */
2000*0Sstevel@tonic-gate 		ASSERT(DEBUG);
2001*0Sstevel@tonic-gate 
2002*0Sstevel@tonic-gate 		(void) set_state(f, UF_UMOUNT);	/* XXX UF_NOTFIX? */
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate 		break;
2005*0Sstevel@tonic-gate 	}
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 	TRIVIA(("] "));
2008*0Sstevel@tonic-gate 	return (rc);
2009*0Sstevel@tonic-gate }
2010*0Sstevel@tonic-gate 
2011*0Sstevel@tonic-gate /*
2012*0Sstevel@tonic-gate  * minimum state function
2013*0Sstevel@tonic-gate  */
2014*0Sstevel@tonic-gate static sfrc_t
2015*0Sstevel@tonic-gate sf_minimum(
2016*0Sstevel@tonic-gate 	ufs_failure_t	*f,
2017*0Sstevel@tonic-gate 	ufsa_t	 a, /* LINTED argument unused in function: ignored */
2018*0Sstevel@tonic-gate 	ufs_failure_states_t	 ignored)
2019*0Sstevel@tonic-gate {
2020*0Sstevel@tonic-gate 	sfrc_t rc = SFRC_FAIL;
2021*0Sstevel@tonic-gate 
2022*0Sstevel@tonic-gate 	TRIVIA(("[sf_minimum, action is %s", act_name(a)));
2023*0Sstevel@tonic-gate 
2024*0Sstevel@tonic-gate 	switch (a) {
2025*0Sstevel@tonic-gate 	case UFA_SET:
2026*0Sstevel@tonic-gate 		f->uf_retry = 0;
2027*0Sstevel@tonic-gate 		/* FALLTHROUGH */
2028*0Sstevel@tonic-gate 
2029*0Sstevel@tonic-gate 	case UFA_FOUND:
2030*0Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
2031*0Sstevel@tonic-gate 		break;
2032*0Sstevel@tonic-gate 
2033*0Sstevel@tonic-gate 	default:
2034*0Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
2035*0Sstevel@tonic-gate 		TRIVIA((": failed] "));
2036*0Sstevel@tonic-gate 		break;
2037*0Sstevel@tonic-gate 	}
2038*0Sstevel@tonic-gate 
2039*0Sstevel@tonic-gate 	TRIVIA(("] "));
2040*0Sstevel@tonic-gate 	return (rc);
2041*0Sstevel@tonic-gate }
2042*0Sstevel@tonic-gate 
2043*0Sstevel@tonic-gate static int
2044*0Sstevel@tonic-gate state_trans_valid(ufs_failure_states_t from, ufs_failure_states_t to)
2045*0Sstevel@tonic-gate {
2046*0Sstevel@tonic-gate 	ufsd_t	*s;
2047*0Sstevel@tonic-gate 	int	 valid;
2048*0Sstevel@tonic-gate 
2049*0Sstevel@tonic-gate 	HIDEOUS(("[state_trans_valid"));
2050*0Sstevel@tonic-gate 
2051*0Sstevel@tonic-gate 	if (from & to)
2052*0Sstevel@tonic-gate 		return (1);
2053*0Sstevel@tonic-gate 
2054*0Sstevel@tonic-gate 	s = get_state_desc(to);
2055*0Sstevel@tonic-gate 
2056*0Sstevel@tonic-gate 	/*
2057*0Sstevel@tonic-gate 	 * extra test is necessary since we want UF_UNDEF = 0,
2058*0Sstevel@tonic-gate 	 * (to detect freshly allocated memory)
2059*0Sstevel@tonic-gate 	 * but can't check for that value with a bit test
2060*0Sstevel@tonic-gate 	 */
2061*0Sstevel@tonic-gate 	valid = (to & UF_INIT)? from == s->ud_prev: from & s->ud_prev;
2062*0Sstevel@tonic-gate 
2063*0Sstevel@tonic-gate 	HIDEOUS((": %svalid] ", valid? "": "in"));
2064*0Sstevel@tonic-gate 	return (valid);
2065*0Sstevel@tonic-gate }
2066*0Sstevel@tonic-gate 
2067*0Sstevel@tonic-gate static int
2068*0Sstevel@tonic-gate terminal_state(ufs_failure_states_t state)
2069*0Sstevel@tonic-gate {
2070*0Sstevel@tonic-gate 	ufsd_t	*s;
2071*0Sstevel@tonic-gate 
2072*0Sstevel@tonic-gate 	HIDEOUS(("[terminal_state"));
2073*0Sstevel@tonic-gate 
2074*0Sstevel@tonic-gate 	s = get_state_desc(state);
2075*0Sstevel@tonic-gate 
2076*0Sstevel@tonic-gate 	HIDEOUS((": %sterminal] ", s->ud_attr.terminal? "": "not "));
2077*0Sstevel@tonic-gate 	return ((int)s->ud_attr.terminal);
2078*0Sstevel@tonic-gate }
2079*0Sstevel@tonic-gate 
2080*0Sstevel@tonic-gate static void
2081*0Sstevel@tonic-gate alloc_lockfs_comment(ufs_failure_t *f, struct lockfs *lfp)
2082*0Sstevel@tonic-gate {
2083*0Sstevel@tonic-gate 	MINUTE(("[alloc_lockfs_comment"));
2084*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2085*0Sstevel@tonic-gate 
2086*0Sstevel@tonic-gate 	/*
2087*0Sstevel@tonic-gate 	 * ufs_fiolfs expects a kmem_alloc'ed comment;
2088*0Sstevel@tonic-gate 	 * it frees the comment if the lock fails
2089*0Sstevel@tonic-gate 	 * or else when the lock is unlocked.
2090*0Sstevel@tonic-gate 	 */
2091*0Sstevel@tonic-gate 
2092*0Sstevel@tonic-gate 	f->uf_lf.lf_comment = kmem_zalloc(LOCKFS_MAXCOMMENTLEN, KM_NOSLEEP);
2093*0Sstevel@tonic-gate 	if (f->uf_lf.lf_comment) {
2094*0Sstevel@tonic-gate 		char	*from;
2095*0Sstevel@tonic-gate 		size_t	 len;
2096*0Sstevel@tonic-gate 
2097*0Sstevel@tonic-gate 		/*
2098*0Sstevel@tonic-gate 		 * use panic string if there's no previous comment
2099*0Sstevel@tonic-gate 		 * or if we're setting the error lock
2100*0Sstevel@tonic-gate 		 */
2101*0Sstevel@tonic-gate 		if ((LOCKFS_IS_ELOCK(&f->uf_lf) || !lfp->lf_comment ||
2102*0Sstevel@tonic-gate 		    lfp->lf_comlen <= 0)) {
2103*0Sstevel@tonic-gate 			from = f->uf_panic_str;
2104*0Sstevel@tonic-gate 			len = LOCKFS_MAXCOMMENTLEN;
2105*0Sstevel@tonic-gate 		} else {
2106*0Sstevel@tonic-gate 			from = lfp->lf_comment;
2107*0Sstevel@tonic-gate 			len = lfp->lf_comlen;
2108*0Sstevel@tonic-gate 		}
2109*0Sstevel@tonic-gate 
2110*0Sstevel@tonic-gate 		bcopy(from, f->uf_lf.lf_comment, len);
2111*0Sstevel@tonic-gate 		f->uf_lf.lf_comlen = len;
2112*0Sstevel@tonic-gate 
2113*0Sstevel@tonic-gate 	} else {
2114*0Sstevel@tonic-gate 		f->uf_lf.lf_comlen = 0;
2115*0Sstevel@tonic-gate 	}
2116*0Sstevel@tonic-gate 	MINUTE(("] "));
2117*0Sstevel@tonic-gate }
2118*0Sstevel@tonic-gate 
2119*0Sstevel@tonic-gate static int
2120*0Sstevel@tonic-gate set_lockfs(ufs_failure_t *f, struct lockfs *lfp)
2121*0Sstevel@tonic-gate {
2122*0Sstevel@tonic-gate 	int	(*handle_lockfs_rc)(ufs_failure_t *);
2123*0Sstevel@tonic-gate 	int	  rc;
2124*0Sstevel@tonic-gate 
2125*0Sstevel@tonic-gate 	MINUTE(("[set_lockfs"));
2126*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2127*0Sstevel@tonic-gate 	ASSERT(!vfs_lock_held(f->uf_vfsp));
2128*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
2129*0Sstevel@tonic-gate 
2130*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
2131*0Sstevel@tonic-gate 		MINUTE((": ufsvfsp is NULL]\n"));
2132*0Sstevel@tonic-gate 		return (0);
2133*0Sstevel@tonic-gate 	}
2134*0Sstevel@tonic-gate 
2135*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&f->uf_ufsvfsp->vfs_ulockfs.ul_lock));
2136*0Sstevel@tonic-gate 
2137*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp->vfs_root) {
2138*0Sstevel@tonic-gate 		MINUTE((": vfs_root is NULL]\n"));
2139*0Sstevel@tonic-gate 		return (0);
2140*0Sstevel@tonic-gate 	}
2141*0Sstevel@tonic-gate 
2142*0Sstevel@tonic-gate 	alloc_lockfs_comment(f, lfp);
2143*0Sstevel@tonic-gate 	f->uf_lf_err = 0;
2144*0Sstevel@tonic-gate 
2145*0Sstevel@tonic-gate 	if (!LOCKFS_IS_ELOCK(lfp)) {
2146*0Sstevel@tonic-gate 		lfp->lf_lock = f->uf_lf.lf_lock = LOCKFS_ELOCK;
2147*0Sstevel@tonic-gate 		VN_HOLD(f->uf_ufsvfsp->vfs_root);
2148*0Sstevel@tonic-gate 		f->uf_lf_err = ufs__fiolfs(f->uf_ufsvfsp->vfs_root,
2149*0Sstevel@tonic-gate 						&f->uf_lf,
2150*0Sstevel@tonic-gate 						/* from_user */ 0,
2151*0Sstevel@tonic-gate 						/* from_log  */ 0);
2152*0Sstevel@tonic-gate 		VN_RELE(f->uf_ufsvfsp->vfs_root);
2153*0Sstevel@tonic-gate 	}
2154*0Sstevel@tonic-gate 
2155*0Sstevel@tonic-gate 	handle_lockfs_rc = f->uf_lf_err != 0? lockfs_failure: lockfs_success;
2156*0Sstevel@tonic-gate 	rc = handle_lockfs_rc(f);
2157*0Sstevel@tonic-gate 
2158*0Sstevel@tonic-gate 	MINUTE(("] "));
2159*0Sstevel@tonic-gate 	return (rc);
2160*0Sstevel@tonic-gate }
2161*0Sstevel@tonic-gate 
2162*0Sstevel@tonic-gate static int
2163*0Sstevel@tonic-gate lockfs_failure(ufs_failure_t *f)
2164*0Sstevel@tonic-gate {
2165*0Sstevel@tonic-gate 	int	error;
2166*0Sstevel@tonic-gate 	ufs_failure_states_t	s;
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate 	TRIVIA(("[lockfs_failure"));
2169*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2170*0Sstevel@tonic-gate 
2171*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
2172*0Sstevel@tonic-gate 		TRIVIA((": ufsvfsp is NULL]\n"));
2173*0Sstevel@tonic-gate 		return (0);
2174*0Sstevel@tonic-gate 	}
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 	error = f->uf_lf_err;
2177*0Sstevel@tonic-gate 	switch (error) {
2178*0Sstevel@tonic-gate 			/* non-transient errors: */
2179*0Sstevel@tonic-gate 	case EACCES:	/* disk/in-core metadata reconciliation failed  */
2180*0Sstevel@tonic-gate 	case EPERM:	/* inode reconciliation failed; incore inode changed? */
2181*0Sstevel@tonic-gate 	case EIO:	/* device is hard-locked or not responding */
2182*0Sstevel@tonic-gate 	case EROFS:	/* device is write-locked */
2183*0Sstevel@tonic-gate 	case EDEADLK:	/* can't lockfs; deadlock would result; */
2184*0Sstevel@tonic-gate 			/* Swapping or saving accounting records */
2185*0Sstevel@tonic-gate 			/* onto this fs can cause this errno. */
2186*0Sstevel@tonic-gate 
2187*0Sstevel@tonic-gate 		MINOR(("ufs_fiolfs(\"%s\") of %s failed: %s (%d)",
2188*0Sstevel@tonic-gate 				fs_name(f),
2189*0Sstevel@tonic-gate 				lock_name(&f->uf_lf),
2190*0Sstevel@tonic-gate 				err_name(error),
2191*0Sstevel@tonic-gate 				error));
2192*0Sstevel@tonic-gate 
2193*0Sstevel@tonic-gate 		/*
2194*0Sstevel@tonic-gate 		 * if can't get lock, then fallback to panic, unless
2195*0Sstevel@tonic-gate 		 * unless unmount was requested (although unmount will
2196*0Sstevel@tonic-gate 		 * probably fail if the lock failed, so we'll panic
2197*0Sstevel@tonic-gate 		 * anyway
2198*0Sstevel@tonic-gate 		 */
2199*0Sstevel@tonic-gate 
2200*0Sstevel@tonic-gate 		s = ((f->uf_flags & UFSFX_LCKUMOUNT) && error != EDEADLK)?
2201*0Sstevel@tonic-gate 							UF_UMOUNT: UF_PANIC;
2202*0Sstevel@tonic-gate 
2203*0Sstevel@tonic-gate 		if (!set_state(f, s)) {
2204*0Sstevel@tonic-gate 			real_panic(f, " ");
2205*0Sstevel@tonic-gate 			/*NOTREACHED*/
2206*0Sstevel@tonic-gate 			break;
2207*0Sstevel@tonic-gate 		}
2208*0Sstevel@tonic-gate 		break;
2209*0Sstevel@tonic-gate 
2210*0Sstevel@tonic-gate 
2211*0Sstevel@tonic-gate 	case EBUSY:
2212*0Sstevel@tonic-gate 	case EAGAIN:
2213*0Sstevel@tonic-gate 
2214*0Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
2215*0Sstevel@tonic-gate 		if (curthread->t_flag & T_DONTPEND) {
2216*0Sstevel@tonic-gate 			curthread->t_flag &= ~T_DONTPEND;
2217*0Sstevel@tonic-gate 
2218*0Sstevel@tonic-gate 		} else if (!(f->uf_s & (UF_LOCKED | UF_FIXING))) {
2219*0Sstevel@tonic-gate 			ufs_failure_states_t state;
2220*0Sstevel@tonic-gate 			/*
2221*0Sstevel@tonic-gate 			 * if we didn't know that the fix had started,
2222*0Sstevel@tonic-gate 			 * take note
2223*0Sstevel@tonic-gate 			 */
2224*0Sstevel@tonic-gate 			state = error == EBUSY? UF_LOCKED: UF_FIXING;
2225*0Sstevel@tonic-gate 			if (!set_state(f, state)) {
2226*0Sstevel@tonic-gate 				TRIVIA((": failed] "));
2227*0Sstevel@tonic-gate 				return (0);
2228*0Sstevel@tonic-gate 			}
2229*0Sstevel@tonic-gate 		}
2230*0Sstevel@tonic-gate 		break;
2231*0Sstevel@tonic-gate 
2232*0Sstevel@tonic-gate 	default:	/* some other non-fatal error */
2233*0Sstevel@tonic-gate 		MINOR(("lockfs(\"%s\") of %s returned %s (%d)",
2234*0Sstevel@tonic-gate 					lock_name(&f->uf_lf),
2235*0Sstevel@tonic-gate 					fs_name(f),
2236*0Sstevel@tonic-gate 					err_name(f->uf_lf_err),
2237*0Sstevel@tonic-gate 					f->uf_lf_err));
2238*0Sstevel@tonic-gate 
2239*0Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
2240*0Sstevel@tonic-gate 		break;
2241*0Sstevel@tonic-gate 
2242*0Sstevel@tonic-gate 	case EINVAL:	/* unmounted? */
2243*0Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
2244*0Sstevel@tonic-gate 		break;
2245*0Sstevel@tonic-gate 	}
2246*0Sstevel@tonic-gate 	TRIVIA(("] "));
2247*0Sstevel@tonic-gate 	return (1);
2248*0Sstevel@tonic-gate }
2249*0Sstevel@tonic-gate 
2250*0Sstevel@tonic-gate static int
2251*0Sstevel@tonic-gate lockfs_success(ufs_failure_t *f)
2252*0Sstevel@tonic-gate {
2253*0Sstevel@tonic-gate 	TRIVIA(("[lockfs_success"));
2254*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2255*0Sstevel@tonic-gate 
2256*0Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
2257*0Sstevel@tonic-gate 		TRIVIA((": ufsvfsp is NULL]\n"));
2258*0Sstevel@tonic-gate 		return (0);
2259*0Sstevel@tonic-gate 	}
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 	switch (f->uf_lf.lf_lock) {
2262*0Sstevel@tonic-gate 	case LOCKFS_ELOCK:	/* error lock worked */
2263*0Sstevel@tonic-gate 
2264*0Sstevel@tonic-gate 		if (!set_state(f, UF_LOCKED)) {
2265*0Sstevel@tonic-gate 			TRIVIA((": failed] "));
2266*0Sstevel@tonic-gate 			return (0);
2267*0Sstevel@tonic-gate 		}
2268*0Sstevel@tonic-gate 		break;
2269*0Sstevel@tonic-gate 
2270*0Sstevel@tonic-gate 	case LOCKFS_ULOCK: 			/* unlock worked */
2271*0Sstevel@tonic-gate 		/*
2272*0Sstevel@tonic-gate 		 * how'd we get here?
2273*0Sstevel@tonic-gate 		 * This should be done from fsck's unlock,
2274*0Sstevel@tonic-gate 		 * not from this thread's context.
2275*0Sstevel@tonic-gate 		 */
2276*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "Unlocked error-lock of %s", fs_name(f));
2277*0Sstevel@tonic-gate 		ufsfx_unlockfs(f->uf_ufsvfsp);
2278*0Sstevel@tonic-gate 		break;
2279*0Sstevel@tonic-gate 
2280*0Sstevel@tonic-gate 	default:
2281*0Sstevel@tonic-gate 		if (!set_state(f, UF_NOTFIX)) {
2282*0Sstevel@tonic-gate 			TRIVIA((": failed] "));
2283*0Sstevel@tonic-gate 			return (0);
2284*0Sstevel@tonic-gate 		}
2285*0Sstevel@tonic-gate 		break;
2286*0Sstevel@tonic-gate 	}
2287*0Sstevel@tonic-gate 	TRIVIA(("] "));
2288*0Sstevel@tonic-gate 	return (1);
2289*0Sstevel@tonic-gate }
2290*0Sstevel@tonic-gate 
2291*0Sstevel@tonic-gate /*
2292*0Sstevel@tonic-gate  * when fsck is running it puts its pid into the lockfs
2293*0Sstevel@tonic-gate  * comment structure, prefaced by PIDSTR
2294*0Sstevel@tonic-gate  */
2295*0Sstevel@tonic-gate const char *PIDSTR = "[pid:";
2296*0Sstevel@tonic-gate static int
2297*0Sstevel@tonic-gate fsck_active(ufs_failure_t *f)
2298*0Sstevel@tonic-gate {
2299*0Sstevel@tonic-gate 	char		*cp;
2300*0Sstevel@tonic-gate 	int		 i, found, errlocked;
2301*0Sstevel@tonic-gate 	size_t		 comlen;
2302*0Sstevel@tonic-gate 	const int	 PIDSTRLEN = (int)strlen(PIDSTR);
2303*0Sstevel@tonic-gate 	struct ulockfs	*ulp = &f->uf_ufsvfsp->vfs_ulockfs;
2304*0Sstevel@tonic-gate 
2305*0Sstevel@tonic-gate 	TRIVIA(("[fsck_active"));
2306*0Sstevel@tonic-gate 
2307*0Sstevel@tonic-gate 	ASSERT(f);
2308*0Sstevel@tonic-gate 	ASSERT(f->uf_s & UF_FIXING);
2309*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2310*0Sstevel@tonic-gate 	ASSERT(f->uf_ufsvfsp);
2311*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
2312*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&ulp->ul_lock));
2313*0Sstevel@tonic-gate 
2314*0Sstevel@tonic-gate 	mutex_enter(&ulp->ul_lock);
2315*0Sstevel@tonic-gate 	cp = ulp->ul_lockfs.lf_comment;
2316*0Sstevel@tonic-gate 	comlen = ulp->ul_lockfs.lf_comlen;
2317*0Sstevel@tonic-gate 	errlocked = (int)ULOCKFS_IS_ELOCK(ulp);
2318*0Sstevel@tonic-gate 	mutex_exit(&ulp->ul_lock);
2319*0Sstevel@tonic-gate 
2320*0Sstevel@tonic-gate 	if (!cp || comlen == 0) {
2321*0Sstevel@tonic-gate 		TRIVIA((": null comment or comlen <= 0, found:0]"));
2322*0Sstevel@tonic-gate 		return (0);
2323*0Sstevel@tonic-gate 	}
2324*0Sstevel@tonic-gate 
2325*0Sstevel@tonic-gate 	for (found = i = 0; !found && i < (comlen - PIDSTRLEN); i++, cp++)
2326*0Sstevel@tonic-gate 		found = strncmp(cp, PIDSTR, PIDSTRLEN) == 0;
2327*0Sstevel@tonic-gate 
2328*0Sstevel@tonic-gate 	TRIVIA(("found:%d, is_elock:%d]", found, errlocked));
2329*0Sstevel@tonic-gate 	return (errlocked & found);
2330*0Sstevel@tonic-gate }
2331*0Sstevel@tonic-gate 
2332*0Sstevel@tonic-gate static const char unknown_fs[]		= "<unknown fs>";
2333*0Sstevel@tonic-gate static const char null_failure[] = "<NULL ufs failure record; unknown fs>";
2334*0Sstevel@tonic-gate static const char mutated_vfs_bufp[]	= "<mutated vfs_bufp, unknown fs>";
2335*0Sstevel@tonic-gate static const char mutated_vfs_fs[]	= "<mutated vfs_fs, unknown fs>";
2336*0Sstevel@tonic-gate 
2337*0Sstevel@tonic-gate static char *
2338*0Sstevel@tonic-gate fs_name(ufs_failure_t *f)
2339*0Sstevel@tonic-gate {
2340*0Sstevel@tonic-gate 	HIDEOUS(("[fs_name"));
2341*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
2342*0Sstevel@tonic-gate 
2343*0Sstevel@tonic-gate 	if (!f) {
2344*0Sstevel@tonic-gate 		HIDEOUS((": failure ptr is NULL]\n"));
2345*0Sstevel@tonic-gate 		return ((char *)null_failure);
2346*0Sstevel@tonic-gate 	}
2347*0Sstevel@tonic-gate 
2348*0Sstevel@tonic-gate 	if (f->uf_fsname[0] != '\0') {
2349*0Sstevel@tonic-gate 		HIDEOUS((": return (uf_fsname)]\n"));
2350*0Sstevel@tonic-gate 		return (f->uf_fsname);
2351*0Sstevel@tonic-gate 	}
2352*0Sstevel@tonic-gate 
2353*0Sstevel@tonic-gate 	if (MUTEX_HELD(f->uf_vfs_lockp)) {
2354*0Sstevel@tonic-gate 		if (f->uf_bp != f->uf_ufsvfsp->vfs_bufp) {
2355*0Sstevel@tonic-gate 			HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
2356*0Sstevel@tonic-gate 			    (void *)f->uf_bp, (void *)f->uf_ufsvfsp->vfs_bufp));
2357*0Sstevel@tonic-gate 			return ((char *)mutated_vfs_bufp);
2358*0Sstevel@tonic-gate 		}
2359*0Sstevel@tonic-gate 		if (f->uf_fs != f->uf_ufsvfsp->vfs_fs) {
2360*0Sstevel@tonic-gate 			HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
2361*0Sstevel@tonic-gate 			    (void *)f->uf_fs, (void *)f->uf_ufsvfsp->vfs_fs));
2362*0Sstevel@tonic-gate 			return ((char *)mutated_vfs_fs);
2363*0Sstevel@tonic-gate 		}
2364*0Sstevel@tonic-gate 		if (f->uf_ufsvfsp && f->uf_bp && f->uf_fs &&
2365*0Sstevel@tonic-gate 		    *f->uf_fs->fs_fsmnt != '\0') {
2366*0Sstevel@tonic-gate 			HIDEOUS((": return (fs_fsmnt)]\n"));
2367*0Sstevel@tonic-gate 			return (f->uf_fs->fs_fsmnt);
2368*0Sstevel@tonic-gate 		}
2369*0Sstevel@tonic-gate 	}
2370*0Sstevel@tonic-gate 
2371*0Sstevel@tonic-gate 	HIDEOUS((": unknown file system]\n"));
2372*0Sstevel@tonic-gate 	return ((char *)unknown_fs);
2373*0Sstevel@tonic-gate }
2374*0Sstevel@tonic-gate 
2375*0Sstevel@tonic-gate #if defined(DEBUG)
2376*0Sstevel@tonic-gate static char *
2377*0Sstevel@tonic-gate lock_name(struct lockfs *lfp)
2378*0Sstevel@tonic-gate {
2379*0Sstevel@tonic-gate 	struct lock_description	*l;
2380*0Sstevel@tonic-gate 	char			*lname;
2381*0Sstevel@tonic-gate 
2382*0Sstevel@tonic-gate 	HIDEOUS(("[lock_name"));
2383*0Sstevel@tonic-gate 
2384*0Sstevel@tonic-gate 	lname = lock_desc[0].ld_name;
2385*0Sstevel@tonic-gate 	for (l = &lock_desc[1]; l->ld_name != NULL; l++) {
2386*0Sstevel@tonic-gate 		if (lfp && lfp->lf_lock == l->ld_type) {
2387*0Sstevel@tonic-gate 			lname = l->ld_name;
2388*0Sstevel@tonic-gate 			break;
2389*0Sstevel@tonic-gate 		}
2390*0Sstevel@tonic-gate 	}
2391*0Sstevel@tonic-gate 	HIDEOUS(("]"));
2392*0Sstevel@tonic-gate 	return (lname);
2393*0Sstevel@tonic-gate }
2394*0Sstevel@tonic-gate 
2395*0Sstevel@tonic-gate static char *
2396*0Sstevel@tonic-gate state_name(ufs_failure_states_t state)
2397*0Sstevel@tonic-gate {
2398*0Sstevel@tonic-gate 	ufsd_t	*s;
2399*0Sstevel@tonic-gate 
2400*0Sstevel@tonic-gate 	HIDEOUS(("[state_name"));
2401*0Sstevel@tonic-gate 
2402*0Sstevel@tonic-gate 	s = get_state_desc(state);
2403*0Sstevel@tonic-gate 
2404*0Sstevel@tonic-gate 	HIDEOUS(("]"));
2405*0Sstevel@tonic-gate 	return (s->ud_name);
2406*0Sstevel@tonic-gate }
2407*0Sstevel@tonic-gate 
2408*0Sstevel@tonic-gate static char *
2409*0Sstevel@tonic-gate err_name(int error)
2410*0Sstevel@tonic-gate {
2411*0Sstevel@tonic-gate 	struct error_description *e;
2412*0Sstevel@tonic-gate 
2413*0Sstevel@tonic-gate 	HIDEOUS(("[err_name"));
2414*0Sstevel@tonic-gate 
2415*0Sstevel@tonic-gate 	for (e = &err_desc[1]; e->ed_name != NULL; e++) {
2416*0Sstevel@tonic-gate 		if (error == e->ed_errno) {
2417*0Sstevel@tonic-gate 			HIDEOUS(("]"));
2418*0Sstevel@tonic-gate 			return (e->ed_name);
2419*0Sstevel@tonic-gate 		}
2420*0Sstevel@tonic-gate 	}
2421*0Sstevel@tonic-gate 	HIDEOUS(("]"));
2422*0Sstevel@tonic-gate 	return (err_desc[0].ed_name);
2423*0Sstevel@tonic-gate }
2424*0Sstevel@tonic-gate 
2425*0Sstevel@tonic-gate static char *
2426*0Sstevel@tonic-gate act_name(ufsa_t action)
2427*0Sstevel@tonic-gate {
2428*0Sstevel@tonic-gate 	struct action_description *a;
2429*0Sstevel@tonic-gate 
2430*0Sstevel@tonic-gate 	HIDEOUS(("[act_name"));
2431*0Sstevel@tonic-gate 
2432*0Sstevel@tonic-gate 	for (a = &act_desc[1]; a->ad_name != NULL; a++) {
2433*0Sstevel@tonic-gate 		if (action == a->ad_v) {
2434*0Sstevel@tonic-gate 			HIDEOUS(("]"));
2435*0Sstevel@tonic-gate 			return (a->ad_name);
2436*0Sstevel@tonic-gate 		}
2437*0Sstevel@tonic-gate 	}
2438*0Sstevel@tonic-gate 	HIDEOUS(("]"));
2439*0Sstevel@tonic-gate 	return (act_desc[0].ad_name);
2440*0Sstevel@tonic-gate }
2441*0Sstevel@tonic-gate 
2442*0Sstevel@tonic-gate /*
2443*0Sstevel@tonic-gate  * dump failure list
2444*0Sstevel@tonic-gate  */
2445*0Sstevel@tonic-gate static void
2446*0Sstevel@tonic-gate dump_uf_list(char *msg)
2447*0Sstevel@tonic-gate {
2448*0Sstevel@tonic-gate 	ufs_failure_t	*f;
2449*0Sstevel@tonic-gate 	int		 i;
2450*0Sstevel@tonic-gate 	int		 list_was_locked = MUTEX_HELD(&ufs_fix.uq_mutex);
2451*0Sstevel@tonic-gate 
2452*0Sstevel@tonic-gate 	if (!list_was_locked && !mutex_tryenter(&ufs_fix.uq_mutex)) {
2453*0Sstevel@tonic-gate 		printf("dump_uf_list: couldn't get list lock\n");
2454*0Sstevel@tonic-gate 		return;
2455*0Sstevel@tonic-gate 	}
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate 	if (msg) {
2458*0Sstevel@tonic-gate 		printf("\n%s", msg);
2459*0Sstevel@tonic-gate 	}
2460*0Sstevel@tonic-gate 	printf("\ndump_uf_list:\n\tuq_lowat: %d, uq_ne: %d\n",
2461*0Sstevel@tonic-gate 		ufs_fix.uq_lowat, ufs_fix.uq_ne);
2462*0Sstevel@tonic-gate 
2463*0Sstevel@tonic-gate 	mutex_enter(&uf_stats.ufst_mutex);
2464*0Sstevel@tonic-gate 	printf("\tuf_stats.current_races: %ld\n", uf_stats.ufst_current_races);
2465*0Sstevel@tonic-gate 	printf("\tuf_stats.num_failed: %ld\n", uf_stats.ufst_num_failed);
2466*0Sstevel@tonic-gate 	printf("\tuf_stats.num_fixed: %ld\n", uf_stats.ufst_num_fixed);
2467*0Sstevel@tonic-gate 	printf("\tuf_stats.cpu_waste: %ld\n", uf_stats.ufst_cpu_waste);
2468*0Sstevel@tonic-gate 	printf("\tuf_stats.lock_violations: %ld, unmount_failures: %ld\n",
2469*0Sstevel@tonic-gate 		uf_stats.ufst_lock_violations, uf_stats.ufst_unmount_failures);
2470*0Sstevel@tonic-gate 	mutex_exit(&uf_stats.ufst_mutex);
2471*0Sstevel@tonic-gate 
2472*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead, i = 1; f; f = f->uf_next, i++) {
2473*0Sstevel@tonic-gate 
2474*0Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex)) {
2475*0Sstevel@tonic-gate 			printf("%d.\t\"skipped - try enter failed\"\n", i);
2476*0Sstevel@tonic-gate 			continue;
2477*0Sstevel@tonic-gate 		}
2478*0Sstevel@tonic-gate 
2479*0Sstevel@tonic-gate 		dump_uf(f, i);
2480*0Sstevel@tonic-gate 
2481*0Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
2482*0Sstevel@tonic-gate 	}
2483*0Sstevel@tonic-gate 
2484*0Sstevel@tonic-gate 	printf("\n");
2485*0Sstevel@tonic-gate 
2486*0Sstevel@tonic-gate 	if (!list_was_locked)
2487*0Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
2488*0Sstevel@tonic-gate }
2489*0Sstevel@tonic-gate 
2490*0Sstevel@tonic-gate static void
2491*0Sstevel@tonic-gate dump_uf(ufs_failure_t *f, int i)
2492*0Sstevel@tonic-gate {
2493*0Sstevel@tonic-gate 	if (!f) {
2494*0Sstevel@tonic-gate 		printf("dump_uf: NULL failure record\n");
2495*0Sstevel@tonic-gate 		return;
2496*0Sstevel@tonic-gate 	}
2497*0Sstevel@tonic-gate 
2498*0Sstevel@tonic-gate 	printf("%d.\t\"%s\" is %s.\n",
2499*0Sstevel@tonic-gate 		    i, fs_name(f), state_name(f->uf_s));
2500*0Sstevel@tonic-gate 	printf("\t\"%s\"\tAddr: 0x%p\n", f->uf_panic_str, (void *)f);
2501*0Sstevel@tonic-gate 	printf("\tNext: 0x%p\t\tPrev: 0x%p\n",
2502*0Sstevel@tonic-gate 					(void *)f->uf_next, (void *)f->uf_prev);
2503*0Sstevel@tonic-gate 
2504*0Sstevel@tonic-gate 	if (f->uf_orig)
2505*0Sstevel@tonic-gate 		printf("\tOriginal failure: 0x%p \"%s\"\n",
2506*0Sstevel@tonic-gate 		    (void *)f->uf_orig, f->uf_orig->uf_panic_str);
2507*0Sstevel@tonic-gate 
2508*0Sstevel@tonic-gate 	printf("\tUfsvfs: 0x%p\t\tVfs_lockp: 0x%p\n",
2509*0Sstevel@tonic-gate 		    (void *)f->uf_ufsvfsp, (void *)f->uf_vfs_lockp);
2510*0Sstevel@tonic-gate 	printf("\tVfs_fsfxp: 0x%p\n", (void *)f->uf_vfs_ufsfxp);
2511*0Sstevel@tonic-gate 	printf("\tVfs_bufp: 0x%p", (void *)f->uf_bp);
2512*0Sstevel@tonic-gate 
2513*0Sstevel@tonic-gate 	if (f->uf_bp)
2514*0Sstevel@tonic-gate 		printf("\t\tVfs_fs: 0x%p\n", (void *)f->uf_fs);
2515*0Sstevel@tonic-gate 	else
2516*0Sstevel@tonic-gate 		printf("\n");
2517*0Sstevel@tonic-gate 
2518*0Sstevel@tonic-gate 	printf("\tBegin: 0x%lx\tEntered: 0x%lx\tEnd: 0x%lx\n",
2519*0Sstevel@tonic-gate 	    f->uf_begin_tm, f->uf_entered_tm, f->uf_end_tm);
2520*0Sstevel@tonic-gate 
2521*0Sstevel@tonic-gate 	printf("\tFlags: (%d) %s%s%s%s", f->uf_flags,
2522*0Sstevel@tonic-gate 		f->uf_flags & UFSFX_LCKONLY?	 "\"lock only\" "	: "",
2523*0Sstevel@tonic-gate 		f->uf_flags & UFSFX_LCKUMOUNT?	 "\"lock+unmount\" "	: "",
2524*0Sstevel@tonic-gate 		f->uf_flags & UFSFX_REPAIR_START? "\"started repair\" "	: "",
2525*0Sstevel@tonic-gate 		f->uf_flags == 0?                "<none>"               : "");
2526*0Sstevel@tonic-gate 
2527*0Sstevel@tonic-gate 	printf("\tRetry: %ld seconds\n", f->uf_retry);
2528*0Sstevel@tonic-gate 
2529*0Sstevel@tonic-gate 	printf("\tLockfs:\ttype: %s\terror: %s (%d)\n",
2530*0Sstevel@tonic-gate 		lock_name(&f->uf_lf),
2531*0Sstevel@tonic-gate 		err_name(f->uf_lf_err), f->uf_lf_err);
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate }
2534*0Sstevel@tonic-gate #endif /* DEBUG */
2535*0Sstevel@tonic-gate 
2536*0Sstevel@tonic-gate /*
2537*0Sstevel@tonic-gate  * returns # of ufs_failures in a non-terminal state on queue
2538*0Sstevel@tonic-gate  * used to coordinate with hlock thread (see ufs_thread.c)
2539*0Sstevel@tonic-gate  * and to determine when the error lock thread may exit
2540*0Sstevel@tonic-gate  */
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate int
2543*0Sstevel@tonic-gate ufsfx_get_failure_qlen(void)
2544*0Sstevel@tonic-gate {
2545*0Sstevel@tonic-gate 	ufs_failure_t	*f;
2546*0Sstevel@tonic-gate 	ufsd_t		*s;
2547*0Sstevel@tonic-gate 	int		 qlen = 0;
2548*0Sstevel@tonic-gate 
2549*0Sstevel@tonic-gate 	MINUTE(("[ufsfx_get_failure_qlen"));
2550*0Sstevel@tonic-gate 
2551*0Sstevel@tonic-gate 	if (!mutex_tryenter(&ufs_fix.uq_mutex))
2552*0Sstevel@tonic-gate 		return (-1);
2553*0Sstevel@tonic-gate 
2554*0Sstevel@tonic-gate 	/*
2555*0Sstevel@tonic-gate 	 * walk down failure list
2556*0Sstevel@tonic-gate 	 */
2557*0Sstevel@tonic-gate 
2558*0Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
2559*0Sstevel@tonic-gate 
2560*0Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex))
2561*0Sstevel@tonic-gate 			continue;
2562*0Sstevel@tonic-gate 
2563*0Sstevel@tonic-gate 		s = get_state_desc(f->uf_s);
2564*0Sstevel@tonic-gate 
2565*0Sstevel@tonic-gate 		if (s->ud_attr.terminal) {
2566*0Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
2567*0Sstevel@tonic-gate 			continue;
2568*0Sstevel@tonic-gate 		}
2569*0Sstevel@tonic-gate 
2570*0Sstevel@tonic-gate 		MINUTE((": found: %s, \"%s: %s\"\n",
2571*0Sstevel@tonic-gate 			    fs_name(f), state_name(f->uf_s), f->uf_panic_str));
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate 		qlen++;
2574*0Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
2575*0Sstevel@tonic-gate 	}
2576*0Sstevel@tonic-gate 
2577*0Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
2578*0Sstevel@tonic-gate 
2579*0Sstevel@tonic-gate 	MINUTE((": qlen=%d]\n", qlen));
2580*0Sstevel@tonic-gate 
2581*0Sstevel@tonic-gate 	return (qlen);
2582*0Sstevel@tonic-gate }
2583*0Sstevel@tonic-gate 
2584*0Sstevel@tonic-gate /*
2585*0Sstevel@tonic-gate  * timeout routine
2586*0Sstevel@tonic-gate  *  called to shutdown fix failure thread and server daemon
2587*0Sstevel@tonic-gate  */
2588*0Sstevel@tonic-gate static void
2589*0Sstevel@tonic-gate ufsfx_kill_fix_failure_thread(void *arg)
2590*0Sstevel@tonic-gate {
2591*0Sstevel@tonic-gate 	clock_t odelta = (clock_t)arg;
2592*0Sstevel@tonic-gate 	int	qlen;
2593*0Sstevel@tonic-gate 
2594*0Sstevel@tonic-gate 	MAJOR(("[ufsfx_kill_fix_failure_thread"));
2595*0Sstevel@tonic-gate 
2596*0Sstevel@tonic-gate 	qlen = ufsfx_get_failure_qlen();
2597*0Sstevel@tonic-gate 
2598*0Sstevel@tonic-gate 	if (qlen < 0) {
2599*0Sstevel@tonic-gate 		clock_t delta;
2600*0Sstevel@tonic-gate 
2601*0Sstevel@tonic-gate 		delta = odelta << 1;
2602*0Sstevel@tonic-gate 		if (delta <= 0)
2603*0Sstevel@tonic-gate 			delta = INT_MAX;
2604*0Sstevel@tonic-gate 
2605*0Sstevel@tonic-gate 		(void) timeout(ufsfx_kill_fix_failure_thread,
2606*0Sstevel@tonic-gate 		    (void *)delta, delta);
2607*0Sstevel@tonic-gate 		MAJOR((": rescheduled"));
2608*0Sstevel@tonic-gate 
2609*0Sstevel@tonic-gate 	} else if (qlen == 0) {
2610*0Sstevel@tonic-gate 		ufs_thread_exit(&ufs_fix);
2611*0Sstevel@tonic-gate 		MAJOR((": killed"));
2612*0Sstevel@tonic-gate 	}
2613*0Sstevel@tonic-gate 	/*
2614*0Sstevel@tonic-gate 	 * else
2615*0Sstevel@tonic-gate 	 *  let timeout expire
2616*0Sstevel@tonic-gate 	 */
2617*0Sstevel@tonic-gate 	MAJOR(("]\n"));
2618*0Sstevel@tonic-gate }
2619