xref: /onnv-gate/usr/src/uts/common/fs/ufs/ufs_panic.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51365Sowenr  * Common Development and Distribution License (the "License").
61365Sowenr  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/errno.h>
300Sstevel@tonic-gate #include <sys/mode.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/varargs.h>
340Sstevel@tonic-gate #include <sys/time.h>
350Sstevel@tonic-gate #include <sys/buf.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/t_lock.h>
380Sstevel@tonic-gate #include <sys/poll.h>
390Sstevel@tonic-gate #include <sys/debug.h>
400Sstevel@tonic-gate #include <sys/cred.h>
410Sstevel@tonic-gate #include <sys/lockfs.h>
420Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
430Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
440Sstevel@tonic-gate #include <sys/fs/ufs_panic.h>
450Sstevel@tonic-gate #include <sys/fs/ufs_lockfs.h>
460Sstevel@tonic-gate #include <sys/fs/ufs_trans.h>
470Sstevel@tonic-gate #include <sys/fs/ufs_mount.h>
480Sstevel@tonic-gate #include <sys/fs/ufs_prot.h>
490Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
500Sstevel@tonic-gate #include <sys/pathname.h>
510Sstevel@tonic-gate #include <sys/utsname.h>
520Sstevel@tonic-gate #include <sys/conf.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /* handy */
550Sstevel@tonic-gate #define	abs(x)		((x) < 0? -(x): (x))
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #if defined(DEBUG)
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	DBGLVL_NONE	0x00000000
600Sstevel@tonic-gate #define	DBGLVL_MAJOR	0x00000100
610Sstevel@tonic-gate #define	DBGLVL_MINOR	0x00000200
620Sstevel@tonic-gate #define	DBGLVL_MINUTE	0x00000400
630Sstevel@tonic-gate #define	DBGLVL_TRIVIA	0x00000800
640Sstevel@tonic-gate #define	DBGLVL_HIDEOUS	0x00001000
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #define	DBGFLG_NONE		0x00000000
670Sstevel@tonic-gate #define	DBGFLG_NOPANIC		0x00000001
680Sstevel@tonic-gate #define	DBGFLG_LVLONLY		0x00000002
690Sstevel@tonic-gate #define	DBGFLG_FIXWOULDPANIC	0x00000004
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	DBGFLG_FLAGMASK		0x0000000F
720Sstevel@tonic-gate #define	DBGFLG_LEVELMASK	~DBGFLG_FLAGMASK
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #define	DEBUG_FLAGS	(ufs_fix_failure_dbg & DBGFLG_FLAGMASK)
750Sstevel@tonic-gate #define	DEBUG_LEVEL	(ufs_fix_failure_dbg & DBGFLG_LEVELMASK)
760Sstevel@tonic-gate 
770Sstevel@tonic-gate unsigned int ufs_fix_failure_dbg =	DBGLVL_NONE | DBGFLG_NONE;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #define	DCALL(dbg_level, call)						\
800Sstevel@tonic-gate 	{								\
810Sstevel@tonic-gate 		if (DEBUG_LEVEL != DBGLVL_NONE) {			\
820Sstevel@tonic-gate 			if (DEBUG_FLAGS & DBGFLG_LVLONLY) {		\
830Sstevel@tonic-gate 				if (DEBUG_LEVEL & dbg_level) {		\
840Sstevel@tonic-gate 					call;				\
850Sstevel@tonic-gate 				}					\
860Sstevel@tonic-gate 			} else {					\
870Sstevel@tonic-gate 				if (dbg_level <= DEBUG_LEVEL) {		\
880Sstevel@tonic-gate 					call;				\
890Sstevel@tonic-gate 				}					\
900Sstevel@tonic-gate 			}						\
910Sstevel@tonic-gate 		}							\
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #define	DPRINTF(dbg_level, msg)		DCALL(dbg_level, printf msg)
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	MAJOR(msg)			DPRINTF(DBGLVL_MAJOR, msg)
970Sstevel@tonic-gate #define	MINOR(msg)			DPRINTF(DBGLVL_MINOR, msg)
980Sstevel@tonic-gate #define	MINUTE(msg)			DPRINTF(DBGLVL_MINUTE, msg)
990Sstevel@tonic-gate #define	TRIVIA(msg)			DPRINTF(DBGLVL_TRIVIA, msg)
1000Sstevel@tonic-gate #define	HIDEOUS(msg)			DPRINTF(DBGLVL_HIDEOUS, msg)
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate #else	/* !DEBUG */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #define	DCALL(ignored_dbg_level, ignored_routine)
1050Sstevel@tonic-gate #define	MAJOR(ignored)
1060Sstevel@tonic-gate #define	MINOR(ignored)
1070Sstevel@tonic-gate #define	MINUTE(ignored)
1080Sstevel@tonic-gate #define	TRIVIA(ignored)
1090Sstevel@tonic-gate #define	HIDEOUS(ignored)
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #endif /* DEBUG */
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate #define	NULLSTR(str)	(!(str) || *(str) == '\0'? "<null>" : (str))
1140Sstevel@tonic-gate #define	NULSTRING	""
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /* somewhat arbitrary limits, in seconds */
1170Sstevel@tonic-gate /* all probably ought to be different, but these are convenient for debugging */
1180Sstevel@tonic-gate const time_t	UF_TOO_LONG		= 128;	/* max. wait for fsck start */
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /* all of these are in units of seconds used for retry period while ... */
1210Sstevel@tonic-gate const time_t	UF_FIXSTART_PERIOD	= 16;	/* awaiting fsck start */
1220Sstevel@tonic-gate const time_t	UF_FIXPOLL_PERIOD	= 256;	/* awaiting fsck finish */
1230Sstevel@tonic-gate const time_t	UF_SHORT_ERROR_PERIOD	= 4;	/* after (lockfs) error */
1240Sstevel@tonic-gate const time_t	UF_LONG_ERROR_PERIOD	= 512;	/* after (lockfs) error */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate #define	NO_ERROR		0
1270Sstevel@tonic-gate #define	LOCKFS_OLOCK		LOCKFS_MAXLOCK+1
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate const ulong_t	GB			= 1024 * 1024 * 1024;
1300Sstevel@tonic-gate const ulong_t	SecondsPerGig		= 1024;	/* ~17 minutes (overestimate) */
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate  * per filesystem flags
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate const int	UFSFX_PANIC		= (UFSMNT_ONERROR_PANIC >> 4);
1360Sstevel@tonic-gate const int	UFSFX_LCKONLY		= (UFSMNT_ONERROR_LOCK >> 4);
1370Sstevel@tonic-gate const int	UFSFX_LCKUMOUNT		= (UFSMNT_ONERROR_UMOUNT >> 4);
1380Sstevel@tonic-gate const int	UFSFX_DEFAULT		= (UFSMNT_ONERROR_DEFAULT >> 4);
1390Sstevel@tonic-gate const int	UFSFX_REPAIR_START	= 0x10000000;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate /* return protocols */
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate typedef enum triage_return_code {
1440Sstevel@tonic-gate 	TRIAGE_DEAD = -1,
1450Sstevel@tonic-gate 	TRIAGE_NO_SPIRIT,
1460Sstevel@tonic-gate 	TRIAGE_ATTEND_TO
1470Sstevel@tonic-gate } triage_t;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate typedef enum statefunc_return_code {
1500Sstevel@tonic-gate 	SFRC_SUCCESS = 1,
1510Sstevel@tonic-gate 	SFRC_FAIL = 0
1520Sstevel@tonic-gate } sfrc_t;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /* external references */
1550Sstevel@tonic-gate /* in ufs_thread.c */
1560Sstevel@tonic-gate extern int	ufs_thread_run(struct ufs_q *, callb_cpr_t *cprinfop);
1570Sstevel@tonic-gate extern int	ufs_checkaccton(vnode_t *);		/* in ufs_lockfs.c */
1580Sstevel@tonic-gate extern int	ufs_checkswapon(vnode_t *);		/* in ufs_lockfs.c */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate extern struct pollhead		ufs_pollhd;		/* in ufs_vnops.c */
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /* globals */
1630Sstevel@tonic-gate struct	ufs_q	 ufs_fix;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * patchable constants:
1670Sstevel@tonic-gate  *   These are set in ufsfx_init() [called at modload]
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate struct ufs_failure_tunable {
1700Sstevel@tonic-gate 	long	 uft_too_long;		/* limit repair startup time */
1710Sstevel@tonic-gate 	long	 uft_fixstart_period;	/* pre-repair start period */
1720Sstevel@tonic-gate 	long	 uft_fixpoll_period;	/* post-fsck start period */
1730Sstevel@tonic-gate 	long	 uft_short_err_period;	/* post-error short period */
1740Sstevel@tonic-gate 	long	 uft_long_err_period;	/* post-error long period */
1750Sstevel@tonic-gate } ufsfx_tune;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /* internal statistics of events */
1780Sstevel@tonic-gate struct uf_statistics {
1790Sstevel@tonic-gate 	ulong_t		ufst_lock_violations;
1800Sstevel@tonic-gate 	ulong_t		ufst_current_races;
1810Sstevel@tonic-gate 	ulong_t		ufst_unmount_failures;
1820Sstevel@tonic-gate 	ulong_t		ufst_num_fixed;
1830Sstevel@tonic-gate 	ulong_t		ufst_num_failed;
1840Sstevel@tonic-gate 	ulong_t		ufst_cpu_waste;
1850Sstevel@tonic-gate 	time_t		ufst_last_start_tm;
1860Sstevel@tonic-gate 	kmutex_t	ufst_mutex;
1870Sstevel@tonic-gate } uf_stats;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate typedef enum state_action {
1900Sstevel@tonic-gate 	UFA_ERROR = -1,		/* internal error */
1910Sstevel@tonic-gate 	UFA_FOUND,		/* found uf in state */
1920Sstevel@tonic-gate 	UFA_SET			/* change uf to state */
1930Sstevel@tonic-gate } ufsa_t;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate /* state definition */
1960Sstevel@tonic-gate typedef struct uf_state_desc {
1970Sstevel@tonic-gate 	int	  ud_v;					/* value */
1980Sstevel@tonic-gate 	char	 *ud_name;				/* name */
1990Sstevel@tonic-gate 	sfrc_t	(*ud_sfp)(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2000Sstevel@tonic-gate 							/* per-state actions */
2010Sstevel@tonic-gate 	ufs_failure_states_t	  ud_prev;		/* valid prev. states */
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	struct uf_state_desc_attr {
2040Sstevel@tonic-gate 		unsigned	terminal:1;	/* no action req. if found */
2050Sstevel@tonic-gate 		unsigned	at_fail:1;	/* state set by thread */
2060Sstevel@tonic-gate 						/* encountering the error */
2070Sstevel@tonic-gate 		unsigned	unused;
2080Sstevel@tonic-gate 	} ud_attr;
2090Sstevel@tonic-gate } ufsd_t;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate  * forward references
2130Sstevel@tonic-gate  */
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /* thread to watch for failures */
2160Sstevel@tonic-gate static void	ufsfx_thread_fix_failures(void *);
2170Sstevel@tonic-gate static int 	ufsfx_do_failure_q(void);
2180Sstevel@tonic-gate static void	ufsfx_kill_fix_failure_thread(void *);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /* routines called when failure occurs */
2210Sstevel@tonic-gate static int		 ufs_fault_v(vnode_t *, char *, va_list)
2220Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
2230Sstevel@tonic-gate static ufs_failure_t	*init_failure(vnode_t *, char *, va_list)
2240Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
2250Sstevel@tonic-gate static void		 queue_failure(ufs_failure_t *);
2260Sstevel@tonic-gate /*PRINTFLIKE2*/
2270Sstevel@tonic-gate static void		 real_panic(ufs_failure_t *, const char *, ...)
2280Sstevel@tonic-gate 	__KPRINTFLIKE(2);
2290Sstevel@tonic-gate static void		 real_panic_v(ufs_failure_t *, const char *, va_list)
2300Sstevel@tonic-gate 	__KVPRINTFLIKE(2);
2310Sstevel@tonic-gate static triage_t		 triage(vnode_t *);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /* routines called when failure record is acted upon */
2340Sstevel@tonic-gate static sfrc_t	set_state(ufs_failure_t *, ufs_failure_states_t);
2350Sstevel@tonic-gate static int	state_trans_valid(ufs_failure_states_t, ufs_failure_states_t);
2360Sstevel@tonic-gate static int	terminal_state(ufs_failure_states_t);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /* routines called when states entered/found */
2390Sstevel@tonic-gate static sfrc_t	sf_minimum(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2400Sstevel@tonic-gate static sfrc_t	sf_undef(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2410Sstevel@tonic-gate static sfrc_t	sf_init(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2420Sstevel@tonic-gate static sfrc_t	sf_queue(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2430Sstevel@tonic-gate static sfrc_t	sf_found_queue(ufs_failure_t *);
2440Sstevel@tonic-gate static sfrc_t	sf_nonterm_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2450Sstevel@tonic-gate static sfrc_t	sf_term_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2460Sstevel@tonic-gate static sfrc_t	sf_panic(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2470Sstevel@tonic-gate static sfrc_t	sf_set_trylck(ufs_failure_t *);
2480Sstevel@tonic-gate static sfrc_t	sf_set_locked(ufs_failure_t *);
2490Sstevel@tonic-gate static sfrc_t	sf_found_trylck(ufs_failure_t *);
2500Sstevel@tonic-gate static sfrc_t	sf_found_lock_fix_cmn(ufs_failure_t *, ufs_failure_states_t);
2510Sstevel@tonic-gate static sfrc_t	sf_found_umount(ufs_failure_t *);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /* support routines, called by sf_nonterm_cmn and sf_term_cmn */
2540Sstevel@tonic-gate static time_t 	trylock_time_exceeded(ufs_failure_t *);
2550Sstevel@tonic-gate static void 	pester_msg(ufs_failure_t *, int);
2560Sstevel@tonic-gate static int 	get_lockfs_status(ufs_failure_t *, struct lockfs *);
2570Sstevel@tonic-gate static void 	alloc_lockfs_comment(ufs_failure_t *, struct lockfs *);
2580Sstevel@tonic-gate static int 	set_lockfs(ufs_failure_t *, struct lockfs *);
2590Sstevel@tonic-gate static int 	lockfs_failure(ufs_failure_t *);
2600Sstevel@tonic-gate static int 	lockfs_success(ufs_failure_t *);
2610Sstevel@tonic-gate static int	fsck_active(ufs_failure_t *);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /* low-level support routines */
2640Sstevel@tonic-gate static ufsd_t	*get_state_desc(ufs_failure_states_t);
2650Sstevel@tonic-gate static char	*fs_name(ufs_failure_t *);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate #if defined(DEBUG)
2680Sstevel@tonic-gate static char	*state_name(ufs_failure_states_t);
2690Sstevel@tonic-gate static char	*lock_name(struct lockfs *);
2700Sstevel@tonic-gate static char	*err_name(int);
2710Sstevel@tonic-gate static char	*act_name(ufsa_t);
2720Sstevel@tonic-gate static void	 dump_uf_list(char *msg);
2730Sstevel@tonic-gate static void	 dump_uf(ufs_failure_t *, int i);
2740Sstevel@tonic-gate #endif /* DEBUG */
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  *
2770Sstevel@tonic-gate  * State Transitions:
2780Sstevel@tonic-gate  *
2790Sstevel@tonic-gate  * normally:
2800Sstevel@tonic-gate  * if flagged to be locked but not unmounted:	(UFSMNT_ONERROR_LOCK)
2810Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> FIXING -> FIXED
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * The only difference between these two is that the fsck must be started
2840Sstevel@tonic-gate  * manually.
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * if flagged to be unmounted:			(UFSMNT_ONERROR_UMOUNT)
2870Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> UMOUNT -> NOTFIX
2880Sstevel@tonic-gate  *
2890Sstevel@tonic-gate  * if flagged to panic:				(UFSMNT_ONERROR_PANIC)
2900Sstevel@tonic-gate  *	UNDEF -> INIT -> PANIC
2910Sstevel@tonic-gate  *
2920Sstevel@tonic-gate  * if a secondary panic on a file system which has an active failure
2930Sstevel@tonic-gate  * record:
2940Sstevel@tonic-gate  *	UNDEF -> INIT -> QUEUE -> REPLICA
2950Sstevel@tonic-gate  *
2960Sstevel@tonic-gate  * UNDEF, INIT, QUEUE all are set in the context of the failing thread.
2970Sstevel@tonic-gate  * All other states (except possibly PANIC) are set in by the monitor
2980Sstevel@tonic-gate  * (lock) thread.
2990Sstevel@tonic-gate  *
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate ufsd_t	state_desc[] =
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	{ UF_ILLEGAL,	"in an unknown state",	sf_minimum,	UF_ILLEGAL,
3050Sstevel@tonic-gate 								{ 0, 1, 0 } },
3060Sstevel@tonic-gate 	{ UF_UNDEF,	"undefined",		sf_undef,	UF_UNDEF,
3070Sstevel@tonic-gate 								{ 0, 1, 0 } },
3080Sstevel@tonic-gate 	{ UF_INIT,	"being initialized",	sf_init,	UF_UNDEF,
3090Sstevel@tonic-gate 								{ 0, 1, 0 } },
3100Sstevel@tonic-gate 	{ UF_QUEUE,	"queued",		sf_queue,	UF_INIT,
3110Sstevel@tonic-gate 								{ 0, 1, 0 } },
3120Sstevel@tonic-gate 	{ UF_TRYLCK,	"trying to be locked",	sf_nonterm_cmn,
3130Sstevel@tonic-gate 						UF_QUEUE,	{ 0, 0, 0 } },
3140Sstevel@tonic-gate 	{ UF_LOCKED,	"locked",		sf_nonterm_cmn,
3150Sstevel@tonic-gate 					UF_TRYLCK | UF_FIXING,	{ 0, 0, 0 } },
3160Sstevel@tonic-gate 	{ UF_UMOUNT,	"being unmounted",	sf_nonterm_cmn,
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate #if defined(DEBUG)
3190Sstevel@tonic-gate 					UF_PANIC |
3200Sstevel@tonic-gate #endif /* DEBUG */
3210Sstevel@tonic-gate 					UF_TRYLCK | UF_LOCKED, 	{ 0, 0, 0 } },
3220Sstevel@tonic-gate 	{ UF_FIXING,	"being fixed",		sf_nonterm_cmn,
3230Sstevel@tonic-gate 						UF_LOCKED,	{ 0, 0, 0 } },
3240Sstevel@tonic-gate 	{ UF_FIXED,	"fixed",		sf_term_cmn,
3250Sstevel@tonic-gate 						UF_FIXING,	{ 1, 0, 0 } },
3260Sstevel@tonic-gate 	{ UF_NOTFIX,	"not fixed",		sf_term_cmn,
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate #if defined(DEBUG)
3290Sstevel@tonic-gate 							UF_PANIC |
3300Sstevel@tonic-gate #endif /* DEBUG */
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	    UF_QUEUE | UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING,
3330Sstevel@tonic-gate 								{ 1, 0, 0 } },
3340Sstevel@tonic-gate 	{ UF_REPLICA,	"a replica",		sf_term_cmn,
3350Sstevel@tonic-gate 						UF_QUEUE,	{ 1, 0, 0 } },
3360Sstevel@tonic-gate 	{ UF_PANIC,	"panicking",		sf_panic,
3370Sstevel@tonic-gate 		/* XXX make this narrower */	UF_ALLSTATES,	{ 0, 0, 0 } },
3380Sstevel@tonic-gate 	{ UF_UNDEF,	NULL,			((sfrc_t (*)()) NULL),
3390Sstevel@tonic-gate 						UF_UNDEF, 	{ 0, 0, 0 } }
3400Sstevel@tonic-gate };
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate /* unified collection */
3430Sstevel@tonic-gate struct ufsfx_info {
3440Sstevel@tonic-gate 	struct uf_statistics		*ufi_statp;
3450Sstevel@tonic-gate 	struct ufs_failure_tunable	*ufi_tunep;
3460Sstevel@tonic-gate 	ufsd_t				*ufi_statetab;
3470Sstevel@tonic-gate } uffsinfo;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate #if defined(DEBUG)
3500Sstevel@tonic-gate struct action_description {
3510Sstevel@tonic-gate 	ufsa_t	 ad_v;
3520Sstevel@tonic-gate 	char	*ad_name;
3530Sstevel@tonic-gate };
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate #define	EUNK		(-1)
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate struct error_description {
3580Sstevel@tonic-gate 	int	 ed_errno;
3590Sstevel@tonic-gate 	char	*ed_name;
3600Sstevel@tonic-gate } err_desc[] =
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	{ EUNK,		"<unexpected errno?>"	},
3630Sstevel@tonic-gate 	{ EINVAL,	"EINVAL"		},
3640Sstevel@tonic-gate 	{ EACCES,	"EACCES"		},
3650Sstevel@tonic-gate 	{ EPERM,	"EPERM"			},
3660Sstevel@tonic-gate 	{ EIO,		"EIO"			},
3670Sstevel@tonic-gate 	{ EDEADLK,	"EDEADLK"		},
3680Sstevel@tonic-gate 	{ EBUSY,	"EBUSY"			},
3690Sstevel@tonic-gate 	{ EAGAIN,	"EAGAIN"		},
3700Sstevel@tonic-gate 	{ ERESTART,	"ERESTART"		},
3710Sstevel@tonic-gate 	{ ETIMEDOUT,	"ETIMEDOUT"		},
3720Sstevel@tonic-gate 	{ NO_ERROR,	"Ok"			},
3730Sstevel@tonic-gate 	{ EUNK,		NULL 			}
3740Sstevel@tonic-gate };
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate struct action_description act_desc[] =
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	{ UFA_ERROR,	"<unexpected action?>"	},
3790Sstevel@tonic-gate 	{ UFA_FOUND,	"\"found\""	},
3800Sstevel@tonic-gate 	{ UFA_SET,	"\"set\""	},
3810Sstevel@tonic-gate 	{ UFA_ERROR,	NULL			},
3820Sstevel@tonic-gate };
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate #define	LOCKFS_BADLOCK	(-1)
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate struct lock_description {
3870Sstevel@tonic-gate 	int	 ld_type;
3880Sstevel@tonic-gate 	char	*ld_name;
3890Sstevel@tonic-gate } lock_desc[] =
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	{ LOCKFS_BADLOCK,	"<unexpected lock?>"	},
3920Sstevel@tonic-gate 	{ LOCKFS_ULOCK,		"Unlock"		},
3930Sstevel@tonic-gate 	{ LOCKFS_ELOCK,		"Error Lock"		},
3940Sstevel@tonic-gate 	{ LOCKFS_HLOCK,		"Hard Lock"		},
3950Sstevel@tonic-gate 	{ LOCKFS_OLOCK,		"Old Lock"		},
3960Sstevel@tonic-gate 	{ LOCKFS_BADLOCK,	NULL			}
3970Sstevel@tonic-gate };
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate #endif /* DEBUG */
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * ufs_fault, ufs_fault_v
4030Sstevel@tonic-gate  *
4040Sstevel@tonic-gate  *  called instead of cmn_err(CE_PANIC, ...) by ufs routines
4050Sstevel@tonic-gate  *  when a failure is detected to put the file system into an
4060Sstevel@tonic-gate  *  error state (if possible) or to devolve to a panic otherwise
4070Sstevel@tonic-gate  *
4080Sstevel@tonic-gate  * vnode is some vnode in this file system, used to find the way
4090Sstevel@tonic-gate  * to ufsvfs, vfsp etc.  Since a panic can be called from many
4100Sstevel@tonic-gate  * levels, the vnode is the most convenient hook to pass through.
4110Sstevel@tonic-gate  *
4120Sstevel@tonic-gate  */
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*PRINTFLIKE2*/
4150Sstevel@tonic-gate int
ufs_fault(vnode_t * vp,char * fmt,...)4160Sstevel@tonic-gate ufs_fault(vnode_t *vp, char *fmt, ...)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	va_list	adx;
4190Sstevel@tonic-gate 	int	error;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	MINOR(("[ufs_fault"));
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	va_start(adx, fmt);
4240Sstevel@tonic-gate 	error = ufs_fault_v(vp, fmt, adx);
4250Sstevel@tonic-gate 	va_end(adx);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	MINOR((": %s (%d)]\n", err_name(error), error));
4280Sstevel@tonic-gate 	return (error);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate const char *nullfmt = "<null format?>";
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate static int
ufs_fault_v(vnode_t * vp,char * fmt,va_list adx)4340Sstevel@tonic-gate ufs_fault_v(vnode_t *vp, char *fmt, va_list adx)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	ufs_failure_t		*new = NULL;
4370Sstevel@tonic-gate 	ufsvfs_t		*ufsvfsp;
4380Sstevel@tonic-gate 	triage_t		 fix;
4390Sstevel@tonic-gate 	int			 err = ERESTART;
4400Sstevel@tonic-gate 	int			need_vfslock;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	MINOR(("[ufs_fault_v"));
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (fmt == NULL)
4450Sstevel@tonic-gate 		fmt = (char *)nullfmt;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	fix = triage(vp);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if (vp) {
4500Sstevel@tonic-gate 		ufsvfsp = (struct ufsvfs *)vp->v_vfsp->vfs_data;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		/*
4530Sstevel@tonic-gate 		 * Something bad has happened. That is why we are here.
4540Sstevel@tonic-gate 		 *
4550Sstevel@tonic-gate 		 * In order for the bad thing to be recorded in the superblock
4560Sstevel@tonic-gate 		 * we need to write to the superblock directly.
4570Sstevel@tonic-gate 		 * In the case that logging is enabled the logging code
4580Sstevel@tonic-gate 		 * would normally intercept our write as a delta to the log,
4590Sstevel@tonic-gate 		 * thus we mark the filesystem FSBAD in any case.
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		need_vfslock = !MUTEX_HELD(&ufsvfsp->vfs_lock);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		if (need_vfslock) {
4640Sstevel@tonic-gate 			mutex_enter(&ufsvfsp->vfs_lock);
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		ufsvfsp->vfs_fs->fs_clean = FSBAD;
4680Sstevel@tonic-gate 		ASSERT(SEMA_HELD(&ufsvfsp->vfs_bufp->b_sem));
4694662Sfrankho 		ufsvfsp->vfs_bufp->b_flags &=
4704662Sfrankho 		    ~(B_ASYNC | B_READ | B_DONE | B_ERROR | B_DELWRI);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		(void) bdev_strategy(ufsvfsp->vfs_bufp);
4730Sstevel@tonic-gate 		(void) biowait(ufsvfsp->vfs_bufp);
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 		if (need_vfslock) {
4760Sstevel@tonic-gate 			mutex_exit(&ufsvfsp->vfs_lock);
4770Sstevel@tonic-gate 		}
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	switch (fix) {
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	default:
4830Sstevel@tonic-gate 	case TRIAGE_DEAD:
4840Sstevel@tonic-gate 	case TRIAGE_NO_SPIRIT:
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 		real_panic_v(new, fmt, adx);
4870Sstevel@tonic-gate 		/* LINTED: warning: logical expression always true: op "||" */
4880Sstevel@tonic-gate 		ASSERT(DEBUG);
4890Sstevel@tonic-gate 		err = EAGAIN;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate #if defined(DEBUG)
4920Sstevel@tonic-gate 		if (!(DEBUG_FLAGS & DBGFLG_FIXWOULDPANIC)) {
4930Sstevel@tonic-gate 			break;
4940Sstevel@tonic-gate 		}
4950Sstevel@tonic-gate 		/* FALLTHROUGH */
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate #else
4980Sstevel@tonic-gate 		break;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate #endif /* DEBUG */
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	case TRIAGE_ATTEND_TO:
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		/* q thread not running yet? */
5051365Sowenr 		if (mutex_tryenter(&ufs_fix.uq_mutex)) {
5061365Sowenr 			if (!ufs_fix.uq_threadp) {
5071365Sowenr 				mutex_exit(&ufs_fix.uq_mutex);
5081365Sowenr 				ufs_thread_start(&ufs_fix,
5091365Sowenr 				    ufsfx_thread_fix_failures, NULL);
5101365Sowenr 				ufs_fix.uq_threadp->t_flag |= T_DONTBLOCK;
5111365Sowenr 				mutex_enter(&ufs_fix.uq_mutex);
5121365Sowenr 			} else {
5131365Sowenr 				/*
5141365Sowenr 				 * We got the lock but we are not the current
5151365Sowenr 				 * threadp so we have to release the lock.
5161365Sowenr 				 */
5171365Sowenr 				mutex_exit(&ufs_fix.uq_mutex);
5181365Sowenr 			}
5190Sstevel@tonic-gate 		} else {
5200Sstevel@tonic-gate 			MINOR((": fix failure thread already running "));
5211365Sowenr 			/*
5221365Sowenr 			 * No need to log another failure as one is already
5231365Sowenr 			 * being logged.
5241365Sowenr 			 */
5251365Sowenr 			break;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		if (ufs_fix.uq_threadp && ufs_fix.uq_threadp == curthread) {
5290Sstevel@tonic-gate 			mutex_exit(&ufs_fix.uq_mutex);
5300Sstevel@tonic-gate 			cmn_err(CE_WARN, "ufs_fault_v: recursive ufs_fault");
5310Sstevel@tonic-gate 		} else {
5321365Sowenr 			/*
5331365Sowenr 			 * Must check if we actually still own the lock and
5341365Sowenr 			 * if so then release the lock and move on with life.
5351365Sowenr 			 */
5361365Sowenr 			if (mutex_owner(&ufs_fix.uq_mutex) == curthread)
5371365Sowenr 				mutex_exit(&ufs_fix.uq_mutex);
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		new = init_failure(vp, fmt, adx);
5410Sstevel@tonic-gate 		if (new != NULL) {
5420Sstevel@tonic-gate 			queue_failure(new);
5430Sstevel@tonic-gate 			break;
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 		real_panic_v(new, fmt, adx);
5460Sstevel@tonic-gate 		break;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	MINOR(("] "));
5500Sstevel@tonic-gate 	return (err);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate  * triage()
5550Sstevel@tonic-gate  *
5560Sstevel@tonic-gate  *  Attempt to fix iff:
5570Sstevel@tonic-gate  *    - the system is not already panicking
5580Sstevel@tonic-gate  *    - this file system isn't explicitly marked not to be fixed
5590Sstevel@tonic-gate  *    - we can connect to the user-level daemon
5600Sstevel@tonic-gate  * These conditions are detectable later, but if we can determine
5610Sstevel@tonic-gate  * them in the failing threads context the core dump may be more
5620Sstevel@tonic-gate  * useful.
5630Sstevel@tonic-gate  *
5640Sstevel@tonic-gate  */
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate static triage_t
triage(vnode_t * vp)5670Sstevel@tonic-gate triage(vnode_t *vp)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	struct inode	 *ip;
5700Sstevel@tonic-gate 	int		  need_unlock_vfs;
5710Sstevel@tonic-gate 	int		  fs_flags;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	MINUTE(("[triage"));
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (panicstr) {
5760Sstevel@tonic-gate 		MINUTE((
5770Sstevel@tonic-gate 		": already panicking: \"%s\" => TRIAGE_DEAD]\n", panicstr));
5780Sstevel@tonic-gate 		return (TRIAGE_DEAD);
5790Sstevel@tonic-gate 	}
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs) {
5820Sstevel@tonic-gate 		MINUTE((
5830Sstevel@tonic-gate 	": vp, ip or ufsvfs is NULL; can't determine fs => TRIAGE_DEAD]\n"));
5840Sstevel@tonic-gate 		return (TRIAGE_DEAD);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/* use tryenter and continue no matter what since we're panicky */
5880Sstevel@tonic-gate 	need_unlock_vfs = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
5890Sstevel@tonic-gate 	if (need_unlock_vfs)
5900Sstevel@tonic-gate 		need_unlock_vfs = mutex_tryenter(&ip->i_ufsvfs->vfs_lock);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	fs_flags = ip->i_ufsvfs->vfs_fsfx.fx_flags;
5930Sstevel@tonic-gate 	if (need_unlock_vfs)
5940Sstevel@tonic-gate 		mutex_exit(&ip->i_ufsvfs->vfs_lock);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	if (fs_flags & UFSFX_PANIC) {
5970Sstevel@tonic-gate 		MINUTE((
5980Sstevel@tonic-gate 		": filesystem marked \"panic\" => TRIAGE_NO_SPIRIT]\n"));
5990Sstevel@tonic-gate 		return (TRIAGE_NO_SPIRIT);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (ufs_checkaccton(vp) != 0) {
6030Sstevel@tonic-gate 		MINUTE((
6040Sstevel@tonic-gate 		": filesystem would deadlock (accounting) => TRIAGE_DEAD]\n"));
6050Sstevel@tonic-gate 		return (TRIAGE_DEAD);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (ufs_checkswapon(vp) != 0) {
6090Sstevel@tonic-gate 		MINUTE((
6100Sstevel@tonic-gate 		": filesystem would deadlock (swapping) => TRIAGE_DEAD]\n"));
6110Sstevel@tonic-gate 		return (TRIAGE_DEAD);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	MINUTE((": return TRIAGE_ATTEND_TO] "));
6150Sstevel@tonic-gate 	return (TRIAGE_ATTEND_TO);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /*
6190Sstevel@tonic-gate  * init failure
6200Sstevel@tonic-gate  *
6210Sstevel@tonic-gate  * This routine allocates a failure struct and initializes
6220Sstevel@tonic-gate  * it's member elements.
6230Sstevel@tonic-gate  * Space is allocated for copies of dynamic identifying fs structures
6240Sstevel@tonic-gate  * passed in.  Without a much more segmented kernel architecture
6250Sstevel@tonic-gate  * this is as protected as we can make it (for now.)
6260Sstevel@tonic-gate  */
6270Sstevel@tonic-gate static ufs_failure_t *
init_failure(vnode_t * vp,char * fmt,va_list adx)6280Sstevel@tonic-gate init_failure(vnode_t *vp, char *fmt, va_list adx)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	ufs_failure_t	*new;
6310Sstevel@tonic-gate 	struct inode	*ip;
6320Sstevel@tonic-gate 	int		 initialization_worked = 0;
6330Sstevel@tonic-gate 	int		 need_vfs_unlock;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	MINOR(("[init_failure"));
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	new = kmem_zalloc(sizeof (ufs_failure_t), KM_NOSLEEP);
6380Sstevel@tonic-gate 	if (!new) {
6390Sstevel@tonic-gate 		MINOR((": kmem_zalloc failed]\n"));
6400Sstevel@tonic-gate 		return (NULL);
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/*
6440Sstevel@tonic-gate 	 * enough information to make a fix attempt possible?
6450Sstevel@tonic-gate 	 */
6460Sstevel@tonic-gate 	if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs || !vp->v_vfsp ||
6470Sstevel@tonic-gate 	    !ip->i_ufsvfs->vfs_bufp || !ITOF(ip) || !fmt)
6480Sstevel@tonic-gate 		goto errout;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if (vp->v_type != VREG && vp->v_type != VDIR &&
6510Sstevel@tonic-gate 	    vp->v_type != VBLK && vp->v_type != VCHR &&
6520Sstevel@tonic-gate 	    vp->v_type != VLNK && vp->v_type != VFIFO &&
6530Sstevel@tonic-gate 	    vp->v_type != VSOCK)
6540Sstevel@tonic-gate 		goto errout;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (ip->i_ufsvfs->vfs_root->v_type != VREG &&
6570Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VDIR &&
6580Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VBLK &&
6590Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VCHR &&
6600Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VLNK &&
6610Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VFIFO &&
6620Sstevel@tonic-gate 	    ip->i_ufsvfs->vfs_root->v_type != VSOCK)
6630Sstevel@tonic-gate 		goto errout;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	if ((ITOF(ip)->fs_magic != FS_MAGIC) &&
6660Sstevel@tonic-gate 	    (ITOF(ip)->fs_magic != MTB_UFS_MAGIC))
6670Sstevel@tonic-gate 		goto errout;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	/* intialize values */
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	(void) vsnprintf(new->uf_panic_str, LOCKFS_MAXCOMMENTLEN - 1, fmt, adx);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	new->uf_ufsvfsp = ip->i_ufsvfs;
6740Sstevel@tonic-gate 	new->uf_vfsp    = ip->i_vfs;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	mutex_init(&new->uf_mutex, NULL, MUTEX_DEFAULT, NULL);
6770Sstevel@tonic-gate 	need_vfs_unlock = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	if (need_vfs_unlock) {
6800Sstevel@tonic-gate 		if (!mutex_tryenter(&ip->i_ufsvfs->vfs_lock)) {
6810Sstevel@tonic-gate 			/*
6820Sstevel@tonic-gate 			 * not much alternative here, but we're panicking
6830Sstevel@tonic-gate 			 * already, it couldn't be worse - so just
6840Sstevel@tonic-gate 			 * proceed optimistically and take note.
6850Sstevel@tonic-gate 			 */
6860Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
6870Sstevel@tonic-gate 			uf_stats.ufst_lock_violations++;
6880Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
6890Sstevel@tonic-gate 			MINOR((": couldn't get vfs lock"))
6900Sstevel@tonic-gate 			need_vfs_unlock = 0;
6910Sstevel@tonic-gate 		}
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	if (mutex_tryenter(&new->uf_mutex)) {
6950Sstevel@tonic-gate 		initialization_worked = set_state(new, UF_INIT);
6960Sstevel@tonic-gate 		mutex_exit(&new->uf_mutex);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	if (need_vfs_unlock)
7000Sstevel@tonic-gate 		mutex_exit(&ip->i_ufsvfs->vfs_lock);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	if (initialization_worked) {
7030Sstevel@tonic-gate 		MINOR(("] "));
7040Sstevel@tonic-gate 		return (new);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 	/* FALLTHROUGH */
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate errout:
7090Sstevel@tonic-gate 	if (new)
7100Sstevel@tonic-gate 		kmem_free(new, sizeof (ufs_failure_t));
7110Sstevel@tonic-gate 	MINOR((": failed]\n"));
7120Sstevel@tonic-gate 	return (NULL);
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate static void
queue_failure(ufs_failure_t * new)7160Sstevel@tonic-gate queue_failure(ufs_failure_t *new)
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	MINOR(("[queue_failure"));
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	mutex_enter(&ufs_fix.uq_mutex);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	if (ufs_fix.uq_ufhead)
7230Sstevel@tonic-gate 		insque(new, &ufs_fix.uq_ufhead);
7240Sstevel@tonic-gate 	else
7250Sstevel@tonic-gate 		ufs_fix.uq_ufhead = new;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (mutex_tryenter(&new->uf_mutex)) {
7280Sstevel@tonic-gate 		(void) set_state(new, UF_QUEUE);
7290Sstevel@tonic-gate 		mutex_exit(&new->uf_mutex);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	mutex_enter(&uf_stats.ufst_mutex);		/* force wakeup */
7330Sstevel@tonic-gate 	ufs_fix.uq_ne = ufs_fix.uq_lowat = uf_stats.ufst_num_failed;
7340Sstevel@tonic-gate 	mutex_exit(&uf_stats.ufst_mutex);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	cv_broadcast(&ufs_fix.uq_cv);
7370Sstevel@tonic-gate 
7384662Sfrankho 	DCALL(DBGLVL_MAJOR, cmn_err(CE_WARN, new->uf_panic_str ?
7394662Sfrankho 	    new->uf_panic_str : "queue_failure: NULL panic str?"));
7400Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	MINOR(("] "));
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate /*PRINTFLIKE2*/
7460Sstevel@tonic-gate static void
real_panic(ufs_failure_t * f,const char * fmt,...)7470Sstevel@tonic-gate real_panic(ufs_failure_t *f, const char *fmt, ...)
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate 	va_list	adx;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	MINUTE(("[real_panic "));
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	va_start(adx, fmt);
7540Sstevel@tonic-gate 	real_panic_v(f, fmt, adx);
7550Sstevel@tonic-gate 	va_end(adx);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	MINUTE((": return?!]\n"));
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate static void
real_panic_v(ufs_failure_t * f,const char * fmt,va_list adx)7610Sstevel@tonic-gate real_panic_v(ufs_failure_t *f, const char *fmt, va_list adx)
7620Sstevel@tonic-gate {
7630Sstevel@tonic-gate 	int seriousness = CE_PANIC;
7640Sstevel@tonic-gate 	int need_unlock;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	MINUTE(("[real_panic_v "));
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if (f && f->uf_ufsvfsp)
7690Sstevel@tonic-gate 		TRANS_SETERROR(f->uf_ufsvfsp);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate #if defined(DEBUG)
7720Sstevel@tonic-gate 	if (DEBUG_FLAGS & DBGFLG_NOPANIC) {
7730Sstevel@tonic-gate 		seriousness = CE_WARN;
7740Sstevel@tonic-gate 		cmn_err(CE_WARN, "real_panic: EWOULDPANIC\n");
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate #endif /* DEBUG */
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	delay(hz >> 1);			/* allow previous warnings to get out */
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	if (!f && fmt)
7810Sstevel@tonic-gate 		vcmn_err(seriousness, fmt, adx);
7820Sstevel@tonic-gate 	else
7830Sstevel@tonic-gate 		cmn_err(seriousness, f && f->uf_panic_str? f->uf_panic_str:
7840Sstevel@tonic-gate 		    "real_panic: <unknown panic?>");
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if (f) {
7870Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
7880Sstevel@tonic-gate 		if (need_unlock) {
7890Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		f->uf_retry = -1;
7930Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		if (need_unlock) {
7960Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
7970Sstevel@tonic-gate 		}
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 	MINUTE((": return?!]\n"));
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate  * initializes ufs panic structs, locks, etc
8040Sstevel@tonic-gate  */
8050Sstevel@tonic-gate void
ufsfx_init(void)8060Sstevel@tonic-gate ufsfx_init(void)
8070Sstevel@tonic-gate {
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	MINUTE(("[ufsfx_init"));
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	/* patchable; unchanged while running, so no lock is needed */
8120Sstevel@tonic-gate 	ufsfx_tune.uft_too_long		= UF_TOO_LONG;
8130Sstevel@tonic-gate 	ufsfx_tune.uft_fixstart_period	= UF_FIXSTART_PERIOD;
8140Sstevel@tonic-gate 	ufsfx_tune.uft_fixpoll_period	= UF_FIXPOLL_PERIOD;
8150Sstevel@tonic-gate 	ufsfx_tune.uft_short_err_period	= UF_SHORT_ERROR_PERIOD;
8160Sstevel@tonic-gate 	ufsfx_tune.uft_long_err_period	= UF_LONG_ERROR_PERIOD;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	uffsinfo.ufi_statp	= &uf_stats;
8190Sstevel@tonic-gate 	uffsinfo.ufi_tunep	= &ufsfx_tune;
8200Sstevel@tonic-gate 	uffsinfo.ufi_statetab	= &state_desc[0];
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	mutex_init(&uf_stats.ufst_mutex, NULL, MUTEX_DEFAULT, NULL);
8230Sstevel@tonic-gate 	ufs_thread_init(&ufs_fix, /* maxne */ 1);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	MINUTE(("] "));
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate /*
8290Sstevel@tonic-gate  * initializes per-ufs values
8300Sstevel@tonic-gate  * returns 0 (ok) or errno
8310Sstevel@tonic-gate  */
8320Sstevel@tonic-gate int
ufsfx_mount(struct ufsvfs * ufsvfsp,int flags)8330Sstevel@tonic-gate ufsfx_mount(struct ufsvfs *ufsvfsp, int flags)
8340Sstevel@tonic-gate {
8350Sstevel@tonic-gate 	MINUTE(("[ufsfx_mount (%d)", flags));
8360Sstevel@tonic-gate 	/* don't check/need vfs_lock because it's still being initialized */
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	ufsvfsp->vfs_fsfx.fx_flags = (flags & UFSMNT_ONERROR_FLGMASK) >> 4;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	MINUTE((": %s: fx_flags:%ld,",
8414662Sfrankho 	    ufsvfsp->vfs_fs->fs_fsmnt, ufsvfsp->vfs_fsfx.fx_flags));
8420Sstevel@tonic-gate 	/*
8430Sstevel@tonic-gate 	 *	onerror={panic ^ lock only ^ unmount}
8440Sstevel@tonic-gate 	 */
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_PANIC) {
8470Sstevel@tonic-gate 		MINUTE((" PANIC"));
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	} else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKONLY) {
8500Sstevel@tonic-gate 		MINUTE((" LCKONLY"));
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	} else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKUMOUNT) {
8530Sstevel@tonic-gate 		MINUTE((" LCKUMOUNT"));
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	} else {
8560Sstevel@tonic-gate 		ufsvfsp->vfs_fsfx.fx_flags = UFSFX_DEFAULT;
8570Sstevel@tonic-gate 		ASSERT(ufsvfsp->vfs_fsfx.fx_flags &
8584662Sfrankho 		    (UFSMNT_ONERROR_FLGMASK >> 4));
8590Sstevel@tonic-gate 		MINUTE((" DEFAULT"));
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	pollwakeup(&ufs_pollhd, POLLPRI);
8630Sstevel@tonic-gate 	MINUTE(("]\n"));
8640Sstevel@tonic-gate 	return (0);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate  * ufsfx_unmount
8690Sstevel@tonic-gate  *
8700Sstevel@tonic-gate  * called during unmount
8710Sstevel@tonic-gate  */
8720Sstevel@tonic-gate void
ufsfx_unmount(struct ufsvfs * ufsvfsp)8730Sstevel@tonic-gate ufsfx_unmount(struct ufsvfs *ufsvfsp)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	ufs_failure_t	*f;
8760Sstevel@tonic-gate 	int		 must_unlock_list;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	MINUTE(("[ufsfx_unmount"));
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (!ufsvfsp) {
8810Sstevel@tonic-gate 		MINUTE((": no ufsvfsp]"));
8820Sstevel@tonic-gate 		return;
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	if ((must_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex)) != 0)
8860Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
8890Sstevel@tonic-gate 		int must_unlock_failure;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		must_unlock_failure = !MUTEX_HELD(&f->uf_mutex);
8920Sstevel@tonic-gate 		if (must_unlock_failure) {
8930Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
8940Sstevel@tonic-gate 		}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp) {
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 			/*
8990Sstevel@tonic-gate 			 * if we owned the failure record lock, then this
9000Sstevel@tonic-gate 			 * is probably a fix failure-triggered unmount, so
9010Sstevel@tonic-gate 			 * the warning is not appropriate or needed
9020Sstevel@tonic-gate 			 */
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 			/* XXX if rebooting don't print this? */
9050Sstevel@tonic-gate 			if (!terminal_state(f->uf_s) && must_unlock_failure) {
9060Sstevel@tonic-gate 				cmn_err(CE_WARN,
9074662Sfrankho 				    "Unmounting %s while error-locked",
9084662Sfrankho 				    fs_name(f));
9090Sstevel@tonic-gate 			}
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 			f->uf_ufsvfsp		= NULL;
9120Sstevel@tonic-gate 			f->uf_vfs_ufsfxp	= NULL;
9130Sstevel@tonic-gate 			f->uf_vfs_lockp		= NULL;
9140Sstevel@tonic-gate 			f->uf_bp		= NULL;
9150Sstevel@tonic-gate 			f->uf_vfsp		= NULL;
9160Sstevel@tonic-gate 			f->uf_retry		= -1;
9170Sstevel@tonic-gate 		}
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 		if (must_unlock_failure)
9200Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	if (must_unlock_list)
9230Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	pollwakeup(&ufs_pollhd, POLLPRI | POLLHUP);
9260Sstevel@tonic-gate 	MINUTE(("] "));
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate /*
9300Sstevel@tonic-gate  * ufsfx_(un)lockfs
9310Sstevel@tonic-gate  *
9320Sstevel@tonic-gate  * provides hook from lockfs code so we can recognize unlock/relock
9330Sstevel@tonic-gate  *  This is called after it is certain that the (un)lock will succeed.
9340Sstevel@tonic-gate  */
9350Sstevel@tonic-gate void
ufsfx_unlockfs(struct ufsvfs * ufsvfsp)9360Sstevel@tonic-gate ufsfx_unlockfs(struct ufsvfs *ufsvfsp)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate 	ufs_failure_t	*f;
9390Sstevel@tonic-gate 	int		 need_unlock;
9400Sstevel@tonic-gate 	int		 need_unlock_list;
9410Sstevel@tonic-gate 	int		 informed = 0;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	MINUTE(("[ufsfx_unlockfs"));
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (!ufsvfsp)
9460Sstevel@tonic-gate 		return;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	if (need_unlock_list)
9510Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
9560Sstevel@tonic-gate 		if (need_unlock)
9570Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s)) {
9600Sstevel@tonic-gate 			if (!(f->uf_s & UF_FIXING)) {
9610Sstevel@tonic-gate 				/*
9620Sstevel@tonic-gate 				 * This might happen if we don't notice that
9630Sstevel@tonic-gate 				 * the fs gets marked FSFIX before it is
9640Sstevel@tonic-gate 				 * marked FSCLEAN, as might occur if the
9650Sstevel@tonic-gate 				 * the superblock was hammered directly.
9660Sstevel@tonic-gate 				 */
9670Sstevel@tonic-gate 				if (!informed) {
9680Sstevel@tonic-gate 					informed = 1;
9690Sstevel@tonic-gate 					cmn_err(CE_NOTE,
9704662Sfrankho 					    "Unlock of %s succeeded before "
9714662Sfrankho 					    "fs_clean marked FSFIX?",
9724662Sfrankho 					    fs_name(f));
9730Sstevel@tonic-gate 				}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 				/*
9760Sstevel@tonic-gate 				 * pass through fixing state so
9770Sstevel@tonic-gate 				 * transition protocol is satisfied
9780Sstevel@tonic-gate 				 */
9790Sstevel@tonic-gate 				if (!set_state(f, UF_FIXING)) {
9800Sstevel@tonic-gate 					MINUTE((": failed] "));
9810Sstevel@tonic-gate 				}
9820Sstevel@tonic-gate 			}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 			if (!set_state(f, UF_FIXED)) {
9850Sstevel@tonic-gate 				/* it's already fixed, so don't panic now */
9860Sstevel@tonic-gate 				MINUTE((": failed] "));
9870Sstevel@tonic-gate 			}
9880Sstevel@tonic-gate 		}
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 		if (need_unlock)
9910Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 	if (need_unlock_list)
9940Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
9950Sstevel@tonic-gate 	MINUTE(("] "));
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate void
ufsfx_lockfs(struct ufsvfs * ufsvfsp)9990Sstevel@tonic-gate ufsfx_lockfs(struct ufsvfs *ufsvfsp)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	ufs_failure_t	*f;
10020Sstevel@tonic-gate 	int		 need_unlock;
10030Sstevel@tonic-gate 	int		 need_unlock_list;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	MINUTE(("[ufsfx_lockfs"));
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (!ufsvfsp)
10080Sstevel@tonic-gate 		return;
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	if (need_unlock_list)
10130Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 		need_unlock = !MUTEX_HELD(&f->uf_mutex);
10180Sstevel@tonic-gate 		if (need_unlock)
10190Sstevel@tonic-gate 			mutex_enter(&f->uf_mutex);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 		if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s) &&
10220Sstevel@tonic-gate 		    f->uf_s != UF_PANIC) {
10230Sstevel@tonic-gate 			switch (f->uf_s) {
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 			default:
10260Sstevel@tonic-gate 				cmn_err(CE_WARN,
10274662Sfrankho 				    "fs %s not in state "
10284662Sfrankho 				    "UF_TRYLCK, UF_LOCKED or UF_FIXING",
10294662Sfrankho 				    fs_name(f));
10300Sstevel@tonic-gate 				break;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 			case UF_TRYLCK:
10330Sstevel@tonic-gate 				if (!set_state(f, UF_LOCKED)) {
10340Sstevel@tonic-gate 					MINUTE((": failed] "));
10350Sstevel@tonic-gate 				}
10360Sstevel@tonic-gate 				break;
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 			case UF_LOCKED:
10390Sstevel@tonic-gate 				if (!set_state(f, UF_FIXING)) {
10400Sstevel@tonic-gate 					MINUTE((": failed] "));
10410Sstevel@tonic-gate 				}
10420Sstevel@tonic-gate 				break;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 			case UF_FIXING:
10450Sstevel@tonic-gate 				break;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 			}
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 		if (need_unlock)
10510Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 	if (need_unlock_list)
10540Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	MINUTE(("] "));
10570Sstevel@tonic-gate }
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate /*
10600Sstevel@tonic-gate  * error lock, trigger fsck and unlock those fs with failures
10610Sstevel@tonic-gate  * blatantly copied from the hlock routine, although this routine
10620Sstevel@tonic-gate  * triggers differently in order to use uq_ne as meaningful data.
10630Sstevel@tonic-gate  */
10640Sstevel@tonic-gate /* ARGSUSED */
10650Sstevel@tonic-gate void
ufsfx_thread_fix_failures(void * ignored)10660Sstevel@tonic-gate ufsfx_thread_fix_failures(void *ignored)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate 	int		retry;
10690Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ufs_fix.uq_mutex, callb_generic_cpr,
10720Sstevel@tonic-gate 	    "ufsfixfail");
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	MINUTE(("[ufsfx_thread_fix_failures] "));
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	for (;;) {
10770Sstevel@tonic-gate 		/* sleep until there is work to do */
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
10800Sstevel@tonic-gate 		(void) ufs_thread_run(&ufs_fix, &cprinfo);
10810Sstevel@tonic-gate 		ufs_fix.uq_ne = 0;
10820Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 		/* process failures on our q */
10850Sstevel@tonic-gate 		do {
10860Sstevel@tonic-gate 			retry = ufsfx_do_failure_q();
10870Sstevel@tonic-gate 			if (retry) {
10880Sstevel@tonic-gate 				mutex_enter(&ufs_fix.uq_mutex);
10890Sstevel@tonic-gate 				CALLB_CPR_SAFE_BEGIN(&cprinfo);
1090*11066Srafael.vanoni@sun.com 				(void) cv_reltimedwait(&ufs_fix.uq_cv,
1091*11066Srafael.vanoni@sun.com 				    &ufs_fix.uq_mutex, (hz * retry),
1092*11066Srafael.vanoni@sun.com 				    TR_CLOCK_TICK);
10930Sstevel@tonic-gate 				CALLB_CPR_SAFE_END(&cprinfo,
10940Sstevel@tonic-gate 				    &ufs_fix.uq_mutex);
10950Sstevel@tonic-gate 				mutex_exit(&ufs_fix.uq_mutex);
10960Sstevel@tonic-gate 			}
10970Sstevel@tonic-gate 		} while (retry);
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 	/* NOTREACHED */
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate /*
11040Sstevel@tonic-gate  * watch for fix-on-panic work
11050Sstevel@tonic-gate  *
11060Sstevel@tonic-gate  * returns # of seconds to sleep before trying again
11070Sstevel@tonic-gate  * and zero if no retry is needed
11080Sstevel@tonic-gate  */
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate int
ufsfx_do_failure_q(void)11110Sstevel@tonic-gate ufsfx_do_failure_q(void)
11120Sstevel@tonic-gate {
11130Sstevel@tonic-gate 	ufs_failure_t	*f;
11140Sstevel@tonic-gate 	long		 retry = 1;
11150Sstevel@tonic-gate 	ufsd_t		*s;
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	MAJOR(("[ufsfx_do_failure_q"));
11180Sstevel@tonic-gate 	DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	if (!mutex_tryenter(&ufs_fix.uq_mutex))
11210Sstevel@tonic-gate 		return (retry);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	retry = 0;
11240Sstevel@tonic-gate rescan_q:
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	/*
11270Sstevel@tonic-gate 	 * walk down failure list
11280Sstevel@tonic-gate 	 *  depending on state of each failure, do whatever
11290Sstevel@tonic-gate 	 *  is appropriate to move it to the next state
11300Sstevel@tonic-gate 	 *  taking note of whether retry gets set
11310Sstevel@tonic-gate 	 *
11320Sstevel@tonic-gate 	 * retry protocol:
11330Sstevel@tonic-gate 	 * wakeup in shortest required time for any failure
11340Sstevel@tonic-gate 	 *   retry == 0; nothing more to do (terminal state)
11350Sstevel@tonic-gate 	 *   retry < 0; reprocess queue immediately, retry will
11360Sstevel@tonic-gate 	 *		be abs(retry) for the next cycle
11370Sstevel@tonic-gate 	 *   retry > 0; schedule wakeup for retry seconds
11380Sstevel@tonic-gate 	 */
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex)) {
11430Sstevel@tonic-gate 			retry = 1;
11440Sstevel@tonic-gate 			continue;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 		s = get_state_desc(f->uf_s);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 		MINOR((": found%s: %s, \"%s: %s\"\n",
11494662Sfrankho 		    s->ud_attr.terminal ? " old" : "",
11504662Sfrankho 		    fs_name(f), state_name(f->uf_s), f->uf_panic_str));
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 		if (s->ud_attr.terminal) {
11530Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
11540Sstevel@tonic-gate 			continue;
11550Sstevel@tonic-gate 		}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 		if (s->ud_sfp)
11580Sstevel@tonic-gate 			(*s->ud_sfp)(f, UFA_FOUND, f->uf_s);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 		ASSERT(terminal_state(f->uf_s) || f->uf_retry != 0);
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 		if (f->uf_retry != 0) {
11630Sstevel@tonic-gate 			if (retry > f->uf_retry || retry == 0)
11640Sstevel@tonic-gate 				retry = f->uf_retry;
11650Sstevel@tonic-gate 			if (f->uf_retry < 0)
11660Sstevel@tonic-gate 				f->uf_retry = abs(f->uf_retry);
11670Sstevel@tonic-gate 		}
11680Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
11690Sstevel@tonic-gate 	}
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	if (retry < 0) {
11730Sstevel@tonic-gate 		retry = abs(retry);
11740Sstevel@tonic-gate 		goto rescan_q;
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
11800Sstevel@tonic-gate 	MAJOR((": retry=%ld, good night]\n\n", retry));
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	return (retry);
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate static void
pester_msg(ufs_failure_t * f,int seriousness)11860Sstevel@tonic-gate pester_msg(ufs_failure_t *f, int seriousness)
11870Sstevel@tonic-gate {
11880Sstevel@tonic-gate 	MINUTE(("[pester_msg"));
11890Sstevel@tonic-gate 	ASSERT(f->uf_s & (UF_LOCKED | UF_FIXING));
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	/*
11920Sstevel@tonic-gate 	 * XXX if seems too long for this fs, poke administrator
11930Sstevel@tonic-gate 	 * XXX to run fsck manually (and change retry time?)
11940Sstevel@tonic-gate 	 */
11954662Sfrankho 	cmn_err(seriousness, "Waiting for repair of %s to %s",
11964662Sfrankho 	    fs_name(f), f->uf_s & UF_LOCKED ? "start" : "finish");
11970Sstevel@tonic-gate 	MINUTE(("]"));
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate static time_t
trylock_time_exceeded(ufs_failure_t * f)12010Sstevel@tonic-gate trylock_time_exceeded(ufs_failure_t *f)
12020Sstevel@tonic-gate {
12030Sstevel@tonic-gate 	time_t		toolong;
12040Sstevel@tonic-gate 	extern time_t	time;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	MINUTE(("[trylock_time_exceeded"));
12070Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	toolong = (time_t)ufsfx_tune.uft_too_long + f->uf_entered_tm;
12100Sstevel@tonic-gate 	if (time > toolong)
12110Sstevel@tonic-gate 		cmn_err(CE_WARN, "error-lock timeout exceeded: %s", fs_name(f));
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	MINUTE(("] "));
12140Sstevel@tonic-gate 	return (time <= toolong? 0: time - toolong);
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate static int
get_lockfs_status(ufs_failure_t * f,struct lockfs * lfp)12180Sstevel@tonic-gate get_lockfs_status(ufs_failure_t *f, struct lockfs *lfp)
12190Sstevel@tonic-gate {
12200Sstevel@tonic-gate 	MINUTE(("[get_lockfs_status"));
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
12230Sstevel@tonic-gate 		MINUTE((": ufsvfsp is NULL]\n"));
12240Sstevel@tonic-gate 		return (0);
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
12280Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
12290Sstevel@tonic-gate 	ASSERT(!vfs_lock_held(f->uf_vfsp));
12300Sstevel@tonic-gate 	ASSERT(f->uf_ufsvfsp->vfs_root != NULL);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	f->uf_lf_err = ufs_fiolfss(f->uf_ufsvfsp->vfs_root, lfp);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	if (f->uf_lf_err) {
12350Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
12360Sstevel@tonic-gate 	}
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	MINUTE(("] "));
12390Sstevel@tonic-gate 	return (1);
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate static sfrc_t
set_state(ufs_failure_t * f,ufs_failure_states_t new_state)12430Sstevel@tonic-gate set_state(ufs_failure_t *f, ufs_failure_states_t new_state)
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate 	ufsd_t		*s;
12460Sstevel@tonic-gate 	sfrc_t		 sfrc = SFRC_FAIL;
12470Sstevel@tonic-gate 	int		 need_unlock;
12480Sstevel@tonic-gate 	extern time_t	 time;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	HIDEOUS(("[set_state: new state:%s", state_name(new_state)));
12510Sstevel@tonic-gate 	ASSERT(f);
12520Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	/*
12550Sstevel@tonic-gate 	 * if someone else is panicking, just let panic sync proceed
12560Sstevel@tonic-gate 	 */
12570Sstevel@tonic-gate 	if (panicstr) {
12580Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
12590Sstevel@tonic-gate 		HIDEOUS((": state reset: not fixed] "));
12600Sstevel@tonic-gate 		return (sfrc);
12610Sstevel@tonic-gate 	}
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	/*
12640Sstevel@tonic-gate 	 * bad state transition, an internal error
12650Sstevel@tonic-gate 	 */
12660Sstevel@tonic-gate 	if (!state_trans_valid(f->uf_s, new_state)) {
12670Sstevel@tonic-gate 		/* recursion */
12680Sstevel@tonic-gate 		if (!(f->uf_s & UF_PANIC) && !(new_state & UF_PANIC))
12690Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
12700Sstevel@tonic-gate 		MINOR((": state reset: transition failure (\"%s\"->\"%s\")] ",
12714662Sfrankho 		    state_name(f->uf_s), state_name(new_state)));
12720Sstevel@tonic-gate 		return (sfrc);
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	s = get_state_desc(new_state);
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	need_unlock = !MUTEX_HELD(&ufs_fix.uq_mutex);
12780Sstevel@tonic-gate 	if (need_unlock)
12790Sstevel@tonic-gate 		mutex_enter(&ufs_fix.uq_mutex);
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	if (s->ud_attr.at_fail && ufs_fix.uq_threadp &&
12820Sstevel@tonic-gate 	    curthread == ufs_fix.uq_threadp) {
12830Sstevel@tonic-gate 		cmn_err(CE_WARN, "set_state: probable recursive panic of %s",
12844662Sfrankho 		    fs_name(f));
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 	if (need_unlock)
12870Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	/* NULL state functions always succeed */
12900Sstevel@tonic-gate 	sfrc = !s->ud_sfp? SFRC_SUCCESS: (*s->ud_sfp)(f, UFA_SET, new_state);
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	if (sfrc == SFRC_SUCCESS && f->uf_s != new_state) {
12930Sstevel@tonic-gate 		f->uf_s = new_state;
12940Sstevel@tonic-gate 		f->uf_entered_tm = time;
12950Sstevel@tonic-gate 		f->uf_counter = 0;
12960Sstevel@tonic-gate 	}
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	HIDEOUS(("]\n"));
12990Sstevel@tonic-gate 	return (sfrc);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate static ufsd_t *
get_state_desc(ufs_failure_states_t state)13030Sstevel@tonic-gate get_state_desc(ufs_failure_states_t state)
13040Sstevel@tonic-gate {
13050Sstevel@tonic-gate 	ufsd_t *s;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	HIDEOUS(("[get_state_desc"));
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	for (s = &state_desc[1]; s->ud_name != NULL; s++) {
13100Sstevel@tonic-gate 		if (s->ud_v == state) {
13110Sstevel@tonic-gate 			HIDEOUS(("] "));
13120Sstevel@tonic-gate 			return (s);
13130Sstevel@tonic-gate 		}
13140Sstevel@tonic-gate 	}
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	HIDEOUS(("] "));
13170Sstevel@tonic-gate 	return (&state_desc[0]);	/* default */
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate static sfrc_t
sf_undef(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)13210Sstevel@tonic-gate sf_undef(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate 	sfrc_t rc;
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 	TRIVIA(("[sf_undef, action is %s, state is %s\n",
13264662Sfrankho 	    act_name(a), state_name(s)));
13270Sstevel@tonic-gate 	ASSERT(s == UF_UNDEF);
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	/* shouldn't find null failure records or ever set one */
13300Sstevel@tonic-gate 	rc = set_state(f, UF_NOTFIX);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	TRIVIA(("] "));
13330Sstevel@tonic-gate 	return (rc);
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate static sfrc_t
sf_init(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)13380Sstevel@tonic-gate sf_init(
13390Sstevel@tonic-gate 	ufs_failure_t	*f,
13400Sstevel@tonic-gate 	ufsa_t	 a,
13410Sstevel@tonic-gate 	ufs_failure_states_t	 s)
13420Sstevel@tonic-gate {
13430Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
13440Sstevel@tonic-gate 	extern time_t	time;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	TRIVIA(("[sf_init, action is %s", act_name(a)));
13470Sstevel@tonic-gate 	ASSERT(s & UF_INIT);
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	switch (a) {
13500Sstevel@tonic-gate 	case UFA_SET:
13510Sstevel@tonic-gate 		f->uf_begin_tm = time;
13520Sstevel@tonic-gate 		f->uf_retry = 1;
13530Sstevel@tonic-gate 		if (!f->uf_ufsvfsp) {
13540Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
13550Sstevel@tonic-gate 			TRIVIA((": NULL ufsvfsp]\n"));
13560Sstevel@tonic-gate 			return (rc);
13570Sstevel@tonic-gate 		}
13580Sstevel@tonic-gate 		/*
13590Sstevel@tonic-gate 		 * because we can call panic from many different levels,
13600Sstevel@tonic-gate 		 * we can't be sure that we've got the vfs_lock at this
13610Sstevel@tonic-gate 		 * point.  However, there's not much alternative and if
13620Sstevel@tonic-gate 		 * we don't (have the lock) the worst case is we'll just
13630Sstevel@tonic-gate 		 * panic again
13640Sstevel@tonic-gate 		 */
13650Sstevel@tonic-gate 		f->uf_vfs_lockp		= &f->uf_ufsvfsp->vfs_lock;
13660Sstevel@tonic-gate 		f->uf_vfs_ufsfxp	= &f->uf_ufsvfsp->vfs_fsfx;
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 		if (!f->uf_ufsvfsp->vfs_bufp) {
13690Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
13700Sstevel@tonic-gate 			TRIVIA((": NULL vfs_bufp]\n"));
13710Sstevel@tonic-gate 			return (rc);
13720Sstevel@tonic-gate 		}
13730Sstevel@tonic-gate 		f->uf_bp = f->uf_ufsvfsp->vfs_bufp;
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		if (!f->uf_ufsvfsp->vfs_bufp->b_un.b_fs) {
13760Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
13770Sstevel@tonic-gate 			TRIVIA((": NULL vfs_fs]\n"));
13780Sstevel@tonic-gate 			return (rc);
13790Sstevel@tonic-gate 		}
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 		/* vfs_fs = vfs_bufp->b_un.b_fs */
13820Sstevel@tonic-gate 		bcopy(f->uf_ufsvfsp->vfs_fs->fs_fsmnt, f->uf_fsname, MAXMNTLEN);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 		f->uf_lf.lf_lock  = LOCKFS_ELOCK;	/* primer */
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 		if (!f->uf_vfsp || f->uf_vfsp->vfs_dev == NODEV) {
13870Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
13880Sstevel@tonic-gate 			TRIVIA((": NULL vfsp or vfs_dev == NODEV"));
13890Sstevel@tonic-gate 			return (rc);
13900Sstevel@tonic-gate 		}
13910Sstevel@tonic-gate 		f->uf_dev = f->uf_vfsp->vfs_dev;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
13940Sstevel@tonic-gate 		break;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	case UFA_FOUND:
13970Sstevel@tonic-gate 	default:
13980Sstevel@tonic-gate 		/* failures marked init shouldn't even be on the queue yet */
13990Sstevel@tonic-gate 		rc = set_state(f, UF_QUEUE);
14000Sstevel@tonic-gate 		TRIVIA((": found failure with state init]\n"));
14010Sstevel@tonic-gate 	}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	TRIVIA(("] "));
14040Sstevel@tonic-gate 	return (rc);
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate static sfrc_t
sf_queue(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)14080Sstevel@tonic-gate sf_queue(
14090Sstevel@tonic-gate 	ufs_failure_t	*f,
14100Sstevel@tonic-gate 	ufsa_t	 a,
14110Sstevel@tonic-gate 	ufs_failure_states_t	 s)
14120Sstevel@tonic-gate {
14130Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	TRIVIA(("[sf_queue, action is %s", act_name(a)));
14160Sstevel@tonic-gate 	ASSERT(s & UF_QUEUE);
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
14190Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp]\n"));
14200Sstevel@tonic-gate 		return (rc);
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	switch (a) {
14240Sstevel@tonic-gate 	case UFA_FOUND:
14250Sstevel@tonic-gate 		rc = sf_found_queue(f);
14260Sstevel@tonic-gate 		break;
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	case UFA_SET:
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 		mutex_enter(&uf_stats.ufst_mutex);
14330Sstevel@tonic-gate 		uf_stats.ufst_num_failed++;
14340Sstevel@tonic-gate 		mutex_exit(&uf_stats.ufst_mutex);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 		/*
14370Sstevel@tonic-gate 		 * if can't get the vfs lock, just wait until
14380Sstevel@tonic-gate 		 * UF_TRYLCK to set fx_current
14390Sstevel@tonic-gate 		 */
14400Sstevel@tonic-gate 		if (mutex_tryenter(f->uf_vfs_lockp)) {
14410Sstevel@tonic-gate 			f->uf_vfs_ufsfxp->fx_current = f;
14420Sstevel@tonic-gate 			mutex_exit(f->uf_vfs_lockp);
14430Sstevel@tonic-gate 		} else {
14440Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
14450Sstevel@tonic-gate 			uf_stats.ufst_current_races++;
14460Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
14470Sstevel@tonic-gate 		}
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 		f->uf_retry = 1;
14500Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
14510Sstevel@tonic-gate 		TRIVIA(("] "));
14520Sstevel@tonic-gate 		break;
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	default:
14550Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
14560Sstevel@tonic-gate 		TRIVIA((": failed] "));
14570Sstevel@tonic-gate 	}
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	return (rc);
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate static sfrc_t
sf_found_queue(ufs_failure_t * f)14630Sstevel@tonic-gate sf_found_queue(ufs_failure_t *f)
14640Sstevel@tonic-gate {
14650Sstevel@tonic-gate 	int		replica;
14660Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	TRIVIA(("[sf_found_queue"));
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	/*
14710Sstevel@tonic-gate 	 * don't need to check for null ufsvfsp because
14720Sstevel@tonic-gate 	 * unmount must own list's ufs_fix.uq_mutex
14730Sstevel@tonic-gate 	 * to mark it null and we own that lock since
14740Sstevel@tonic-gate 	 * we got here.
14750Sstevel@tonic-gate 	 */
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
14780Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	if (!mutex_tryenter(f->uf_vfs_lockp)) {
14810Sstevel@tonic-gate 		TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
14820Sstevel@tonic-gate 		f->uf_retry = 1;
14830Sstevel@tonic-gate 		return (rc);
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	replica = f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current != NULL &&
14874662Sfrankho 	    f->uf_vfs_ufsfxp->fx_current != f &&
14884662Sfrankho 	    !terminal_state(f->uf_vfs_ufsfxp->fx_current->uf_s);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	/*
14910Sstevel@tonic-gate 	 * copy general flags to this ufs_failure so we don't
14920Sstevel@tonic-gate 	 * need to refer back to the ufsvfs, or, more importantly,
14930Sstevel@tonic-gate 	 * don't need to keep acquiring (trying to acquire) vfs_lockp
14940Sstevel@tonic-gate 	 *
14950Sstevel@tonic-gate 	 * The most restrictive option wins:
14960Sstevel@tonic-gate 	 *  panic > errlock only > errlock+unmount > repair
14970Sstevel@tonic-gate 	 * XXX panic > elock > elock > elock+umount
14980Sstevel@tonic-gate 	 */
14990Sstevel@tonic-gate 	if (f->uf_vfs_ufsfxp->fx_flags & UFSFX_PANIC) {
15000Sstevel@tonic-gate 		if (!set_state(f, UF_PANIC)) {
15010Sstevel@tonic-gate 			TRIVIA((": marked panic but was queued?"));
15020Sstevel@tonic-gate 			real_panic(f, " ");
15030Sstevel@tonic-gate 			/*NOTREACHED*/
15040Sstevel@tonic-gate 		}
15050Sstevel@tonic-gate 		mutex_exit(f->uf_vfs_lockp);
15060Sstevel@tonic-gate 		return (rc);
15070Sstevel@tonic-gate 	}
15080Sstevel@tonic-gate 	f->uf_flags = f->uf_vfs_ufsfxp->fx_flags;
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	if (replica) {
15110Sstevel@tonic-gate 		if (!set_state(f, UF_REPLICA)) {
15120Sstevel@tonic-gate 			f->uf_retry = 1;
15130Sstevel@tonic-gate 			TRIVIA((": set to replica failed] "));
15140Sstevel@tonic-gate 		} else {
15150Sstevel@tonic-gate 			TRIVIA(("] "));
15160Sstevel@tonic-gate 		}
15170Sstevel@tonic-gate 		mutex_exit(f->uf_vfs_lockp);
15180Sstevel@tonic-gate 		return (rc);
15190Sstevel@tonic-gate 	}
15200Sstevel@tonic-gate 	mutex_exit(f->uf_vfs_lockp);
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	if (!set_state(f, UF_TRYLCK)) {
15230Sstevel@tonic-gate 		TRIVIA((": failed] "));
15240Sstevel@tonic-gate 	} else {
15250Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
15260Sstevel@tonic-gate 	}
15270Sstevel@tonic-gate 	return (rc);
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate static sfrc_t
sf_nonterm_cmn(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)15310Sstevel@tonic-gate sf_nonterm_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
15320Sstevel@tonic-gate {
15330Sstevel@tonic-gate 	sfrc_t	rc = SFRC_FAIL;
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	TRIVIA(("[sf_nonterm_cmn, action: %s, %s", act_name(a), state_name(s)));
15360Sstevel@tonic-gate 	ASSERT(s & (UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING));
15370Sstevel@tonic-gate 	ASSERT(!terminal_state(s));
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	if (!f->uf_ufsvfsp && !(f->uf_s & UF_UMOUNT)) {
15400Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp (state != UMOUNT)]\n"));
15410Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
15420Sstevel@tonic-gate 		return (rc);
15430Sstevel@tonic-gate 	}
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	switch (a) {
15460Sstevel@tonic-gate 	case UFA_SET:
15470Sstevel@tonic-gate 		switch (s) {
15480Sstevel@tonic-gate 		case UF_TRYLCK:
15490Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
15500Sstevel@tonic-gate 			rc = sf_set_trylck(f);
15510Sstevel@tonic-gate 			break;
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 		case UF_LOCKED:
15540Sstevel@tonic-gate 			rc = sf_set_locked(f);
15550Sstevel@tonic-gate 			break;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		case UF_FIXING:
15580Sstevel@tonic-gate 			f->uf_flags |= UFSFX_REPAIR_START;
15590Sstevel@tonic-gate 			f->uf_retry  = ufsfx_tune.uft_fixpoll_period;
15600Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
15610Sstevel@tonic-gate 			break;
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 		case UF_UMOUNT:
15640Sstevel@tonic-gate 			f->uf_retry = -ufsfx_tune.uft_short_err_period;
15650Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
15660Sstevel@tonic-gate 			break;
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 		default:
15690Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
15700Sstevel@tonic-gate 			TRIVIA((": failed] "));
15710Sstevel@tonic-gate 		}
15720Sstevel@tonic-gate 		break;
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	case UFA_FOUND:
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 		switch (s) {
15770Sstevel@tonic-gate 		case UF_TRYLCK:
15780Sstevel@tonic-gate 			rc = sf_found_trylck(f);
15790Sstevel@tonic-gate 			break;
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 		case UF_LOCKED:
15820Sstevel@tonic-gate 		case UF_FIXING:
15830Sstevel@tonic-gate 			rc = sf_found_lock_fix_cmn(f, s);
15840Sstevel@tonic-gate 			break;
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 		case UF_UMOUNT:
15870Sstevel@tonic-gate 			rc = sf_found_umount(f);
15880Sstevel@tonic-gate 			break;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 		default:
15910Sstevel@tonic-gate 			(void) set_state(f, UF_PANIC);
15920Sstevel@tonic-gate 			TRIVIA((": failed] "));
15930Sstevel@tonic-gate 			break;
15940Sstevel@tonic-gate 		}
15950Sstevel@tonic-gate 		break;
15960Sstevel@tonic-gate 	default:
15970Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
15980Sstevel@tonic-gate 		TRIVIA((": failed] "));
15990Sstevel@tonic-gate 		break;
16000Sstevel@tonic-gate 	}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	TRIVIA(("] "));
16030Sstevel@tonic-gate 	return (rc);
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate static sfrc_t
sf_set_trylck(ufs_failure_t * f)16070Sstevel@tonic-gate sf_set_trylck(ufs_failure_t *f)
16080Sstevel@tonic-gate {
16090Sstevel@tonic-gate 	TRIVIA(("[sf_set_trylck"));
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	if (!mutex_tryenter(f->uf_vfs_lockp)) {
16120Sstevel@tonic-gate 		TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
16130Sstevel@tonic-gate 		f->uf_retry = 1;
16140Sstevel@tonic-gate 		return (SFRC_FAIL);
16150Sstevel@tonic-gate 	}
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	if (!f->uf_vfs_ufsfxp->fx_current)
16180Sstevel@tonic-gate 		f->uf_vfs_ufsfxp->fx_current = f;
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	mutex_exit(f->uf_vfs_lockp);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	f->uf_lf.lf_flags = 0;
16230Sstevel@tonic-gate 	f->uf_lf.lf_lock  = LOCKFS_ELOCK;
16240Sstevel@tonic-gate 	f->uf_retry = -ufsfx_tune.uft_fixstart_period;
16250Sstevel@tonic-gate 	TRIVIA(("] "));
16260Sstevel@tonic-gate 	return (SFRC_SUCCESS);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate static sfrc_t
sf_found_trylck(ufs_failure_t * f)16300Sstevel@tonic-gate sf_found_trylck(ufs_failure_t *f)
16310Sstevel@tonic-gate {
16320Sstevel@tonic-gate 	struct lockfs lockfs_status;
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 	TRIVIA(("[sf_found_trylck"));
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	if (trylock_time_exceeded(f) > 0) {
16370Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
16380Sstevel@tonic-gate 		TRIVIA((": failed] "));
16390Sstevel@tonic-gate 		return (SFRC_FAIL);
16400Sstevel@tonic-gate 	}
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	if (!get_lockfs_status(f, &lockfs_status)) {
16430Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
16440Sstevel@tonic-gate 		TRIVIA((": failed] "));
16450Sstevel@tonic-gate 		return (SFRC_FAIL);
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	if (f->uf_lf_err == NO_ERROR)
16490Sstevel@tonic-gate 		f->uf_lf.lf_key = lockfs_status.lf_key;
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	if (!set_lockfs(f, &lockfs_status)) {
16520Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
16530Sstevel@tonic-gate 		TRIVIA((": failed] "));
16540Sstevel@tonic-gate 		return (SFRC_FAIL);
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 	TRIVIA(("] "));
16570Sstevel@tonic-gate 	return (SFRC_SUCCESS);
16580Sstevel@tonic-gate }
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate static sfrc_t
sf_set_locked(ufs_failure_t * f)16610Sstevel@tonic-gate sf_set_locked(ufs_failure_t *f)
16620Sstevel@tonic-gate {
16630Sstevel@tonic-gate 	TRIVIA(("[sf_set_locked"));
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	f->uf_retry = -ufsfx_tune.uft_fixstart_period;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate #if defined(DEBUG)
16680Sstevel@tonic-gate 	if (f->uf_flags & UFSFX_REPAIR_START)
16690Sstevel@tonic-gate 		TRIVIA(("clearing UFSFX_REPAIR_START "));
16700Sstevel@tonic-gate #endif /* DEBUG */
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	f->uf_flags &= ~UFSFX_REPAIR_START;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	if (f->uf_s & UF_TRYLCK) {
16750Sstevel@tonic-gate 		cmn_err(CE_WARN, "Error-locked %s: \"%s\"",
16764662Sfrankho 		    fs_name(f), f->uf_panic_str);
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 		if (f->uf_flags & UFSFX_LCKONLY)
16790Sstevel@tonic-gate 			cmn_err(CE_WARN, "Manual repair of %s required",
16804662Sfrankho 			    fs_name(f));
16810Sstevel@tonic-gate 	}
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	/*
16840Sstevel@tonic-gate 	 * just reset to current state
16850Sstevel@tonic-gate 	 */
16860Sstevel@tonic-gate #if defined(DEBUG)
16870Sstevel@tonic-gate 	TRIVIA(("locked->locked "));
16880Sstevel@tonic-gate #endif /* DEBUG */
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	TRIVIA(("] "));
16910Sstevel@tonic-gate 	return (SFRC_SUCCESS);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate static sfrc_t
sf_found_lock_fix_cmn(ufs_failure_t * f,ufs_failure_states_t s)16950Sstevel@tonic-gate sf_found_lock_fix_cmn(ufs_failure_t *f, ufs_failure_states_t s)
16960Sstevel@tonic-gate {
16970Sstevel@tonic-gate 	time_t		toolong;
16980Sstevel@tonic-gate 	extern time_t	time;
16990Sstevel@tonic-gate 	struct buf	*bp			= NULL;
17000Sstevel@tonic-gate 	struct fs	*dfs;
17010Sstevel@tonic-gate 	time_t		 concerned, anxious;
17020Sstevel@tonic-gate 	sfrc_t		 rc			= SFRC_FAIL;
17030Sstevel@tonic-gate 	ulong_t		 gb_size;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	TRIVIA(("[sf_found_lock_fix_cmn (\"%s\")", state_name(s)));
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 	if (s & UF_LOCKED) {
17080Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&f->uf_mutex));
17090Sstevel@tonic-gate 
17104662Sfrankho 		toolong =
17114662Sfrankho 		    time > (ufsfx_tune.uft_too_long + f->uf_entered_tm);
17120Sstevel@tonic-gate 		TRIVIA(("%stoolong", !toolong? "not": ""));
17130Sstevel@tonic-gate 		HIDEOUS((": time:%ld, too long:%ld, entered_tm:%ld ",
17140Sstevel@tonic-gate 		    time, ufsfx_tune.uft_too_long, f->uf_entered_tm));
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 		if (f->uf_flags & UFSFX_LCKUMOUNT) {
17170Sstevel@tonic-gate 			if (set_state(f, UF_UMOUNT)) {
17180Sstevel@tonic-gate 				TRIVIA(("] "));
17190Sstevel@tonic-gate 				rc = SFRC_SUCCESS;
17200Sstevel@tonic-gate 			} else {
17210Sstevel@tonic-gate 				TRIVIA((": failed] "));
17220Sstevel@tonic-gate 				f->uf_retry = 1;
17230Sstevel@tonic-gate 			}
17240Sstevel@tonic-gate 			return (rc);
17250Sstevel@tonic-gate 		}
17260Sstevel@tonic-gate 		if (!toolong) {
17270Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
17280Sstevel@tonic-gate 		} else {
17290Sstevel@tonic-gate 			if (!(f->uf_flags & UFSFX_REPAIR_START)) {
17300Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s repair of %s not started.",
17314662Sfrankho 				    (f->uf_flags & UFSFX_LCKONLY) ?
17324662Sfrankho 				    "Manual" : "Automatic", fs_name(f));
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 				f->uf_retry = ufsfx_tune.uft_long_err_period;
17350Sstevel@tonic-gate 			} else {
17360Sstevel@tonic-gate 				f->uf_retry = ufsfx_tune.uft_long_err_period;
17374662Sfrankho 				cmn_err(CE_WARN, "Repair of %s is not timely; "
17384662Sfrankho 				    "operator attention is required.",
17394662Sfrankho 				    fs_name(f));
17400Sstevel@tonic-gate 			}
17410Sstevel@tonic-gate 			TRIVIA(("] "));
17420Sstevel@tonic-gate 			return (rc);
17430Sstevel@tonic-gate 		}
17440Sstevel@tonic-gate 	}
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate #if defined(DEBUG)
17470Sstevel@tonic-gate 	else {
17480Sstevel@tonic-gate 		ASSERT(s & UF_FIXING);
17490Sstevel@tonic-gate 	}
17500Sstevel@tonic-gate #endif /* DEBUG */
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	/*
17530Sstevel@tonic-gate 	 * get on disk superblock; force it to really
17540Sstevel@tonic-gate 	 * come from the disk
17550Sstevel@tonic-gate 	 */
17560Sstevel@tonic-gate 	(void) bfinval(f->uf_dev, 0);
17570Sstevel@tonic-gate 	bp = UFS_BREAD(f->uf_ufsvfsp, f->uf_dev, SBLOCK, SBSIZE);
17580Sstevel@tonic-gate 	if (bp) {
17590Sstevel@tonic-gate 		bp->b_flags |= (B_STALE | B_AGE);
17600Sstevel@tonic-gate 		dfs = bp->b_un.b_fs;
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	if (!bp || (bp->b_flags & B_ERROR) || ((dfs->fs_magic != FS_MAGIC) &&
17640Sstevel@tonic-gate 	    (dfs->fs_magic != MTB_UFS_MAGIC))) {
17650Sstevel@tonic-gate 		TRIVIA((": UFS_BREAD(SBLOCK) failed]\n"));
17660Sstevel@tonic-gate 		f->uf_retry = 1;
17670Sstevel@tonic-gate 		goto out;
17680Sstevel@tonic-gate 	}
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	/* fsck started but we haven't noticed yet? */
17710Sstevel@tonic-gate 	if (!(s & UF_FIXING) && dfs->fs_clean == FSFIX) {
17720Sstevel@tonic-gate 		if (!set_state(f, UF_FIXING)) {
17730Sstevel@tonic-gate 			TRIVIA((": failed]\n"));
17740Sstevel@tonic-gate 			f->uf_retry = 1;
17750Sstevel@tonic-gate 			goto out;
17760Sstevel@tonic-gate 		}
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	/* fsck started but didn't succeed? */
17800Sstevel@tonic-gate 	if ((s & UF_FIXING) && ((dfs->fs_clean == FSBAD) || !fsck_active(f))) {
17810Sstevel@tonic-gate 		TRIVIA((": fs_clean: %d", (int)dfs->fs_clean));
17820Sstevel@tonic-gate 		(void) set_state(f, UF_LOCKED);
17830Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: Manual repair is necessary.", fs_name(f));
17840Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_long_err_period;
17850Sstevel@tonic-gate 		goto out;
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	gb_size = (dfs->fs_size * dfs->fs_bshift) / GB;
17890Sstevel@tonic-gate 	toolong = (time_t)((gb_size == 0? 1: gb_size) * SecondsPerGig);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	/* fsck started but doesn't seem to be proceeding? */
17920Sstevel@tonic-gate 	if ((s & UF_FIXING) && dfs->fs_clean == FSFIX) {
17930Sstevel@tonic-gate 		if (time > f->uf_entered_tm + toolong) {
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 			cmn_err(CE_WARN,
17964662Sfrankho 			    "Repair completion timeout exceeded on %s; "
17974662Sfrankho 			    "manual fsck may be required", fs_name(f));
17980Sstevel@tonic-gate 			f->uf_retry = ufsfx_tune.uft_long_err_period;
17990Sstevel@tonic-gate 		}
18000Sstevel@tonic-gate 	}
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 	concerned = f->uf_entered_tm + (toolong / 3);
18030Sstevel@tonic-gate 	anxious = f->uf_entered_tm + ((2 * toolong) / 3);
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	if (time > concerned)
18060Sstevel@tonic-gate 		pester_msg(f, time > anxious? CE_WARN: CE_NOTE);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	TRIVIA(("] "));
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate out:
18110Sstevel@tonic-gate 	if (bp)
18120Sstevel@tonic-gate 		brelse(bp);
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	return (rc);
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate static sfrc_t
sf_found_umount(ufs_failure_t * f)18180Sstevel@tonic-gate sf_found_umount(ufs_failure_t *f)
18190Sstevel@tonic-gate {
18200Sstevel@tonic-gate 	extern time_t	 time;
18210Sstevel@tonic-gate 	sfrc_t		 rc			= SFRC_FAIL;
18220Sstevel@tonic-gate 	struct vfs	*vfsp			= f->uf_vfsp;
18230Sstevel@tonic-gate 	struct ufsvfs	*ufsvfsp		= f->uf_ufsvfsp;
18240Sstevel@tonic-gate 	int		 toolong		= 0;
18250Sstevel@tonic-gate 	int		 err			= 0;
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	TRIVIA(("[sf_found_umount"));
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	toolong = time > ufsfx_tune.uft_too_long + f->uf_entered_tm;
18300Sstevel@tonic-gate 	if (toolong) {
18310Sstevel@tonic-gate 		TRIVIA((": unmount time limit exceeded] "));
18320Sstevel@tonic-gate 		goto out;
18330Sstevel@tonic-gate 	}
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if (!vfsp || !ufsvfsp) {	/* trivial case */
18360Sstevel@tonic-gate 		TRIVIA((": NULL vfsp and/or ufsvfsp, already unmounted?] "));
18370Sstevel@tonic-gate 		goto out;
18380Sstevel@tonic-gate 	}
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 	if (!ULOCKFS_IS_ELOCK(&ufsvfsp->vfs_ulockfs)) {
18410Sstevel@tonic-gate 		TRIVIA((": !not error locked?"));
18420Sstevel@tonic-gate 		err = EINVAL;
18430Sstevel@tonic-gate 		goto out;
18440Sstevel@tonic-gate 	}
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	/* The vn_vfsunlock will be done in dounmount() [.../common/fs/vfs.c] */
1847569Sbatschul 	if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
18480Sstevel@tonic-gate 		TRIVIA((": couldn't lock coveredvp"));
18490Sstevel@tonic-gate 		err = EBUSY;
18500Sstevel@tonic-gate 		goto out;
18510Sstevel@tonic-gate 	}
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	if ((err = dounmount(vfsp, 0, kcred)) != 0) {
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		/* take note, but not many alternatives here */
18560Sstevel@tonic-gate 		mutex_enter(&uf_stats.ufst_mutex);
18570Sstevel@tonic-gate 		uf_stats.ufst_unmount_failures++;
18580Sstevel@tonic-gate 		mutex_exit(&uf_stats.ufst_mutex);
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 		TRIVIA((": unmount failed] "));
18610Sstevel@tonic-gate 	} else {
18620Sstevel@tonic-gate 		cmn_err(CE_NOTE, "unmounted error-locked %s", fs_name(f));
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate out:
18660Sstevel@tonic-gate 	if (toolong || (err != EBUSY && err != EAGAIN))
18670Sstevel@tonic-gate 		rc = set_state(f, UF_NOTFIX);
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	TRIVIA(("] "));
18700Sstevel@tonic-gate 	return (rc);
18710Sstevel@tonic-gate }
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate static sfrc_t
sf_term_cmn(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)18740Sstevel@tonic-gate sf_term_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
18750Sstevel@tonic-gate {
18760Sstevel@tonic-gate 	extern time_t	time;
18770Sstevel@tonic-gate 	sfrc_t		rc = SFRC_FAIL;
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	TRIVIA(("[sf_term_cmn, action is %s, state is %s",
18804662Sfrankho 	    act_name(a), state_name(s)));
18810Sstevel@tonic-gate 	ASSERT(s & (UF_FIXED | UF_NOTFIX | UF_REPLICA));
18820Sstevel@tonic-gate 	ASSERT(terminal_state(s));
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	if (!f->uf_ufsvfsp && !(f->uf_s & (UF_UMOUNT | UF_NOTFIX))) {
18850Sstevel@tonic-gate 		TRIVIA((": NULL ufsvfsp (state != UMOUNT | NOTFIX)]\n"));
18860Sstevel@tonic-gate 		return (rc);
18870Sstevel@tonic-gate 	}
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	switch (a) {
18900Sstevel@tonic-gate 	case UFA_SET:
18910Sstevel@tonic-gate 		switch (s) {
18920Sstevel@tonic-gate 		case UF_NOTFIX:
18930Sstevel@tonic-gate 		case UF_FIXED:
18944662Sfrankho 		{
18954662Sfrankho 			int need_lock_vfs;
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 			if (f->uf_ufsvfsp && f->uf_vfs_lockp)
18980Sstevel@tonic-gate 				need_lock_vfs = !MUTEX_HELD(f->uf_vfs_lockp);
18990Sstevel@tonic-gate 			else
19000Sstevel@tonic-gate 				need_lock_vfs = 0;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 			if (need_lock_vfs && !mutex_tryenter(f->uf_vfs_lockp)) {
19030Sstevel@tonic-gate 				TRIVIA((": tryenter(vfslockp) fail; retry]\n"));
19040Sstevel@tonic-gate 				f->uf_retry = 1;
19050Sstevel@tonic-gate 				break;
19060Sstevel@tonic-gate 			}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 			f->uf_end_tm = time;
19090Sstevel@tonic-gate 			f->uf_lf.lf_lock = LOCKFS_OLOCK;
19100Sstevel@tonic-gate 			f->uf_retry = 0;
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate 			if (f->uf_vfs_ufsfxp)
19130Sstevel@tonic-gate 				f->uf_vfs_ufsfxp->fx_current = NULL;
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 			if (need_lock_vfs)
19160Sstevel@tonic-gate 				mutex_exit(f->uf_vfs_lockp);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 			cmn_err(CE_NOTE, (s & UF_NOTFIX)? "Could not fix %s":
19194662Sfrankho 			    "%s is now accessible", fs_name(f));
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 			if (s & UF_FIXED) {
19220Sstevel@tonic-gate 				mutex_enter(&uf_stats.ufst_mutex);
19230Sstevel@tonic-gate 				uf_stats.ufst_num_fixed++;
19240Sstevel@tonic-gate 				mutex_exit(&uf_stats.ufst_mutex);
19250Sstevel@tonic-gate 			}
19260Sstevel@tonic-gate 			(void) timeout(ufsfx_kill_fix_failure_thread,
19270Sstevel@tonic-gate 			    (void *)(ufsfx_tune.uft_short_err_period * hz),
19280Sstevel@tonic-gate 			    ufsfx_tune.uft_short_err_period * hz);
19290Sstevel@tonic-gate 			rc = SFRC_SUCCESS;
19300Sstevel@tonic-gate 			break;
19310Sstevel@tonic-gate 		}
19320Sstevel@tonic-gate 		case UF_REPLICA:
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 			ASSERT(MUTEX_HELD(f->uf_vfs_lockp));
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 			/* not actually a replica? */
19370Sstevel@tonic-gate 			if (f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current &&
19380Sstevel@tonic-gate 			    f->uf_vfs_ufsfxp->fx_current != f &&
19394662Sfrankho 			    !terminal_state(
19404662Sfrankho 			    f->uf_vfs_ufsfxp->fx_current->uf_s)) {
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 				f->uf_orig = f->uf_vfs_ufsfxp->fx_current;
19430Sstevel@tonic-gate 				f->uf_retry = 0;
19440Sstevel@tonic-gate 				rc = SFRC_SUCCESS;
19450Sstevel@tonic-gate 			} else {
19460Sstevel@tonic-gate 				TRIVIA((": NULL fx_current]\n"));
19470Sstevel@tonic-gate 				f->uf_retry = 1;
19480Sstevel@tonic-gate 			}
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 			break;
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 		default:
19530Sstevel@tonic-gate 			rc = set_state(f, UF_PANIC);
19540Sstevel@tonic-gate 			TRIVIA((": failed] "));
19550Sstevel@tonic-gate 			break;
19560Sstevel@tonic-gate 		}
19570Sstevel@tonic-gate 		break;
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	case UFA_FOUND:
19600Sstevel@tonic-gate 		/*
19610Sstevel@tonic-gate 		 * XXX de-allocate these after some period?
19620Sstevel@tonic-gate 		 * XXX or move to an historical list?
19630Sstevel@tonic-gate 		 * XXX or have an ioctl which reaps them?
19640Sstevel@tonic-gate 		 */
19650Sstevel@tonic-gate 		/*
19660Sstevel@tonic-gate 		 * For now, since we don't expect lots of failures
19670Sstevel@tonic-gate 		 * to occur (to the point of memory shortages),
19680Sstevel@tonic-gate 		 * just punt
19690Sstevel@tonic-gate 		 */
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 		/* be sure we're not wasting cpu on old failures */
19720Sstevel@tonic-gate 		if (f->uf_retry != 0) {
19730Sstevel@tonic-gate 			mutex_enter(&uf_stats.ufst_mutex);
19740Sstevel@tonic-gate 			uf_stats.ufst_cpu_waste++;
19750Sstevel@tonic-gate 			mutex_exit(&uf_stats.ufst_mutex);
19760Sstevel@tonic-gate 			f->uf_retry = 0;
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
19790Sstevel@tonic-gate 		break;
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate 	default:
19820Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
19830Sstevel@tonic-gate 		TRIVIA((": failed] "));
19840Sstevel@tonic-gate 		break;
19850Sstevel@tonic-gate 	}
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	TRIVIA(("] "));
19880Sstevel@tonic-gate 	return (rc);
19890Sstevel@tonic-gate }
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate static sfrc_t
sf_panic(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)19920Sstevel@tonic-gate sf_panic(
19930Sstevel@tonic-gate 	ufs_failure_t	*f,
19940Sstevel@tonic-gate 	ufsa_t	 a,
19950Sstevel@tonic-gate 	ufs_failure_states_t	 s)
19960Sstevel@tonic-gate {
19970Sstevel@tonic-gate 	sfrc_t	rc = SFRC_FAIL;
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	TRIVIA(("[sf_panic, action is %s, prev. state is %s",
20004662Sfrankho 	    act_name(a), state_name(f->uf_s)));
20010Sstevel@tonic-gate 	ASSERT(s & UF_PANIC);
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	switch (a) {
20040Sstevel@tonic-gate 	case UFA_SET:
20050Sstevel@tonic-gate 		f->uf_retry = -ufsfx_tune.uft_short_err_period;
20060Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
20070Sstevel@tonic-gate 		break;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 	case UFA_FOUND:
20100Sstevel@tonic-gate 	default:
20110Sstevel@tonic-gate 		real_panic(f, " ");
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 		/* LINTED: warning: logical expression always true: op "||" */
20140Sstevel@tonic-gate 		ASSERT(DEBUG);
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 		(void) set_state(f, UF_UMOUNT);	/* XXX UF_NOTFIX? */
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate 		break;
20190Sstevel@tonic-gate 	}
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 	TRIVIA(("] "));
20220Sstevel@tonic-gate 	return (rc);
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate /*
20260Sstevel@tonic-gate  * minimum state function
20270Sstevel@tonic-gate  */
20280Sstevel@tonic-gate static sfrc_t
sf_minimum(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t ignored)20290Sstevel@tonic-gate sf_minimum(
20300Sstevel@tonic-gate 	ufs_failure_t	*f,
20310Sstevel@tonic-gate 	ufsa_t	 a, /* LINTED argument unused in function: ignored */
20320Sstevel@tonic-gate 	ufs_failure_states_t	 ignored)
20330Sstevel@tonic-gate {
20340Sstevel@tonic-gate 	sfrc_t rc = SFRC_FAIL;
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate 	TRIVIA(("[sf_minimum, action is %s", act_name(a)));
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	switch (a) {
20390Sstevel@tonic-gate 	case UFA_SET:
20400Sstevel@tonic-gate 		f->uf_retry = 0;
20410Sstevel@tonic-gate 		/* FALLTHROUGH */
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	case UFA_FOUND:
20440Sstevel@tonic-gate 		rc = SFRC_SUCCESS;
20450Sstevel@tonic-gate 		break;
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 	default:
20480Sstevel@tonic-gate 		(void) set_state(f, UF_PANIC);
20490Sstevel@tonic-gate 		TRIVIA((": failed] "));
20500Sstevel@tonic-gate 		break;
20510Sstevel@tonic-gate 	}
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	TRIVIA(("] "));
20540Sstevel@tonic-gate 	return (rc);
20550Sstevel@tonic-gate }
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate static int
state_trans_valid(ufs_failure_states_t from,ufs_failure_states_t to)20580Sstevel@tonic-gate state_trans_valid(ufs_failure_states_t from, ufs_failure_states_t to)
20590Sstevel@tonic-gate {
20600Sstevel@tonic-gate 	ufsd_t	*s;
20610Sstevel@tonic-gate 	int	 valid;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	HIDEOUS(("[state_trans_valid"));
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	if (from & to)
20660Sstevel@tonic-gate 		return (1);
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	s = get_state_desc(to);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	/*
20710Sstevel@tonic-gate 	 * extra test is necessary since we want UF_UNDEF = 0,
20720Sstevel@tonic-gate 	 * (to detect freshly allocated memory)
20730Sstevel@tonic-gate 	 * but can't check for that value with a bit test
20740Sstevel@tonic-gate 	 */
20750Sstevel@tonic-gate 	valid = (to & UF_INIT)? from == s->ud_prev: from & s->ud_prev;
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 	HIDEOUS((": %svalid] ", valid? "": "in"));
20780Sstevel@tonic-gate 	return (valid);
20790Sstevel@tonic-gate }
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate static int
terminal_state(ufs_failure_states_t state)20820Sstevel@tonic-gate terminal_state(ufs_failure_states_t state)
20830Sstevel@tonic-gate {
20840Sstevel@tonic-gate 	ufsd_t	*s;
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	HIDEOUS(("[terminal_state"));
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	s = get_state_desc(state);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 	HIDEOUS((": %sterminal] ", s->ud_attr.terminal? "": "not "));
20910Sstevel@tonic-gate 	return ((int)s->ud_attr.terminal);
20920Sstevel@tonic-gate }
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate static void
alloc_lockfs_comment(ufs_failure_t * f,struct lockfs * lfp)20950Sstevel@tonic-gate alloc_lockfs_comment(ufs_failure_t *f, struct lockfs *lfp)
20960Sstevel@tonic-gate {
20970Sstevel@tonic-gate 	MINUTE(("[alloc_lockfs_comment"));
20980Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	/*
21010Sstevel@tonic-gate 	 * ufs_fiolfs expects a kmem_alloc'ed comment;
21020Sstevel@tonic-gate 	 * it frees the comment if the lock fails
21030Sstevel@tonic-gate 	 * or else when the lock is unlocked.
21040Sstevel@tonic-gate 	 */
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	f->uf_lf.lf_comment = kmem_zalloc(LOCKFS_MAXCOMMENTLEN, KM_NOSLEEP);
21070Sstevel@tonic-gate 	if (f->uf_lf.lf_comment) {
21080Sstevel@tonic-gate 		char	*from;
21090Sstevel@tonic-gate 		size_t	 len;
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 		/*
21120Sstevel@tonic-gate 		 * use panic string if there's no previous comment
21130Sstevel@tonic-gate 		 * or if we're setting the error lock
21140Sstevel@tonic-gate 		 */
21150Sstevel@tonic-gate 		if ((LOCKFS_IS_ELOCK(&f->uf_lf) || !lfp->lf_comment ||
21160Sstevel@tonic-gate 		    lfp->lf_comlen <= 0)) {
21170Sstevel@tonic-gate 			from = f->uf_panic_str;
21180Sstevel@tonic-gate 			len = LOCKFS_MAXCOMMENTLEN;
21190Sstevel@tonic-gate 		} else {
21200Sstevel@tonic-gate 			from = lfp->lf_comment;
21210Sstevel@tonic-gate 			len = lfp->lf_comlen;
21220Sstevel@tonic-gate 		}
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 		bcopy(from, f->uf_lf.lf_comment, len);
21250Sstevel@tonic-gate 		f->uf_lf.lf_comlen = len;
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	} else {
21280Sstevel@tonic-gate 		f->uf_lf.lf_comlen = 0;
21290Sstevel@tonic-gate 	}
21300Sstevel@tonic-gate 	MINUTE(("] "));
21310Sstevel@tonic-gate }
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate static int
set_lockfs(ufs_failure_t * f,struct lockfs * lfp)21340Sstevel@tonic-gate set_lockfs(ufs_failure_t *f, struct lockfs *lfp)
21350Sstevel@tonic-gate {
21360Sstevel@tonic-gate 	int	(*handle_lockfs_rc)(ufs_failure_t *);
21370Sstevel@tonic-gate 	int	  rc;
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	MINUTE(("[set_lockfs"));
21400Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
21410Sstevel@tonic-gate 	ASSERT(!vfs_lock_held(f->uf_vfsp));
21420Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
21450Sstevel@tonic-gate 		MINUTE((": ufsvfsp is NULL]\n"));
21460Sstevel@tonic-gate 		return (0);
21470Sstevel@tonic-gate 	}
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&f->uf_ufsvfsp->vfs_ulockfs.ul_lock));
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	if (!f->uf_ufsvfsp->vfs_root) {
21520Sstevel@tonic-gate 		MINUTE((": vfs_root is NULL]\n"));
21530Sstevel@tonic-gate 		return (0);
21540Sstevel@tonic-gate 	}
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 	alloc_lockfs_comment(f, lfp);
21570Sstevel@tonic-gate 	f->uf_lf_err = 0;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	if (!LOCKFS_IS_ELOCK(lfp)) {
21600Sstevel@tonic-gate 		lfp->lf_lock = f->uf_lf.lf_lock = LOCKFS_ELOCK;
21610Sstevel@tonic-gate 		VN_HOLD(f->uf_ufsvfsp->vfs_root);
21624662Sfrankho 		f->uf_lf_err =
21634662Sfrankho 		    ufs__fiolfs(f->uf_ufsvfsp->vfs_root,
21644662Sfrankho 		    &f->uf_lf, /* from_user */ 0, /* from_log */ 0);
21650Sstevel@tonic-gate 		VN_RELE(f->uf_ufsvfsp->vfs_root);
21660Sstevel@tonic-gate 	}
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	handle_lockfs_rc = f->uf_lf_err != 0? lockfs_failure: lockfs_success;
21690Sstevel@tonic-gate 	rc = handle_lockfs_rc(f);
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	MINUTE(("] "));
21720Sstevel@tonic-gate 	return (rc);
21730Sstevel@tonic-gate }
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate static int
lockfs_failure(ufs_failure_t * f)21760Sstevel@tonic-gate lockfs_failure(ufs_failure_t *f)
21770Sstevel@tonic-gate {
21780Sstevel@tonic-gate 	int	error;
21790Sstevel@tonic-gate 	ufs_failure_states_t	s;
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	TRIVIA(("[lockfs_failure"));
21820Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
21850Sstevel@tonic-gate 		TRIVIA((": ufsvfsp is NULL]\n"));
21860Sstevel@tonic-gate 		return (0);
21870Sstevel@tonic-gate 	}
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	error = f->uf_lf_err;
21900Sstevel@tonic-gate 	switch (error) {
21910Sstevel@tonic-gate 			/* non-transient errors: */
21920Sstevel@tonic-gate 	case EACCES:	/* disk/in-core metadata reconciliation failed  */
21930Sstevel@tonic-gate 	case EPERM:	/* inode reconciliation failed; incore inode changed? */
21940Sstevel@tonic-gate 	case EIO:	/* device is hard-locked or not responding */
21950Sstevel@tonic-gate 	case EROFS:	/* device is write-locked */
21960Sstevel@tonic-gate 	case EDEADLK:	/* can't lockfs; deadlock would result; */
21970Sstevel@tonic-gate 			/* Swapping or saving accounting records */
21980Sstevel@tonic-gate 			/* onto this fs can cause this errno. */
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		MINOR(("ufs_fiolfs(\"%s\") of %s failed: %s (%d)",
22014662Sfrankho 		    fs_name(f), lock_name(&f->uf_lf),
22024662Sfrankho 		    err_name(error), error));
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 		/*
22050Sstevel@tonic-gate 		 * if can't get lock, then fallback to panic, unless
22060Sstevel@tonic-gate 		 * unless unmount was requested (although unmount will
22070Sstevel@tonic-gate 		 * probably fail if the lock failed, so we'll panic
22080Sstevel@tonic-gate 		 * anyway
22090Sstevel@tonic-gate 		 */
22100Sstevel@tonic-gate 
22114662Sfrankho 		s = ((f->uf_flags & UFSFX_LCKUMOUNT) && error != EDEADLK) ?
22124662Sfrankho 		    UF_UMOUNT: UF_PANIC;
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 		if (!set_state(f, s)) {
22150Sstevel@tonic-gate 			real_panic(f, " ");
22160Sstevel@tonic-gate 			/*NOTREACHED*/
22170Sstevel@tonic-gate 			break;
22180Sstevel@tonic-gate 		}
22190Sstevel@tonic-gate 		break;
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	case EBUSY:
22230Sstevel@tonic-gate 	case EAGAIN:
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
22260Sstevel@tonic-gate 		if (curthread->t_flag & T_DONTPEND) {
22270Sstevel@tonic-gate 			curthread->t_flag &= ~T_DONTPEND;
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 		} else if (!(f->uf_s & (UF_LOCKED | UF_FIXING))) {
22300Sstevel@tonic-gate 			ufs_failure_states_t state;
22310Sstevel@tonic-gate 			/*
22320Sstevel@tonic-gate 			 * if we didn't know that the fix had started,
22330Sstevel@tonic-gate 			 * take note
22340Sstevel@tonic-gate 			 */
22350Sstevel@tonic-gate 			state = error == EBUSY? UF_LOCKED: UF_FIXING;
22360Sstevel@tonic-gate 			if (!set_state(f, state)) {
22370Sstevel@tonic-gate 				TRIVIA((": failed] "));
22380Sstevel@tonic-gate 				return (0);
22390Sstevel@tonic-gate 			}
22400Sstevel@tonic-gate 		}
22410Sstevel@tonic-gate 		break;
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	default:	/* some other non-fatal error */
22440Sstevel@tonic-gate 		MINOR(("lockfs(\"%s\") of %s returned %s (%d)",
22454662Sfrankho 		    lock_name(&f->uf_lf), fs_name(f),
22464662Sfrankho 		    err_name(f->uf_lf_err), f->uf_lf_err));
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 		f->uf_retry = ufsfx_tune.uft_short_err_period;
22490Sstevel@tonic-gate 		break;
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 	case EINVAL:	/* unmounted? */
22520Sstevel@tonic-gate 		(void) set_state(f, UF_NOTFIX);
22530Sstevel@tonic-gate 		break;
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 	TRIVIA(("] "));
22560Sstevel@tonic-gate 	return (1);
22570Sstevel@tonic-gate }
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate static int
lockfs_success(ufs_failure_t * f)22600Sstevel@tonic-gate lockfs_success(ufs_failure_t *f)
22610Sstevel@tonic-gate {
22620Sstevel@tonic-gate 	TRIVIA(("[lockfs_success"));
22630Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
22640Sstevel@tonic-gate 
22650Sstevel@tonic-gate 	if (!f->uf_ufsvfsp) {
22660Sstevel@tonic-gate 		TRIVIA((": ufsvfsp is NULL]\n"));
22670Sstevel@tonic-gate 		return (0);
22680Sstevel@tonic-gate 	}
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	switch (f->uf_lf.lf_lock) {
22710Sstevel@tonic-gate 	case LOCKFS_ELOCK:	/* error lock worked */
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 		if (!set_state(f, UF_LOCKED)) {
22740Sstevel@tonic-gate 			TRIVIA((": failed] "));
22750Sstevel@tonic-gate 			return (0);
22760Sstevel@tonic-gate 		}
22770Sstevel@tonic-gate 		break;
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	case LOCKFS_ULOCK: 			/* unlock worked */
22800Sstevel@tonic-gate 		/*
22810Sstevel@tonic-gate 		 * how'd we get here?
22820Sstevel@tonic-gate 		 * This should be done from fsck's unlock,
22830Sstevel@tonic-gate 		 * not from this thread's context.
22840Sstevel@tonic-gate 		 */
22850Sstevel@tonic-gate 		cmn_err(CE_WARN, "Unlocked error-lock of %s", fs_name(f));
22860Sstevel@tonic-gate 		ufsfx_unlockfs(f->uf_ufsvfsp);
22870Sstevel@tonic-gate 		break;
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	default:
22900Sstevel@tonic-gate 		if (!set_state(f, UF_NOTFIX)) {
22910Sstevel@tonic-gate 			TRIVIA((": failed] "));
22920Sstevel@tonic-gate 			return (0);
22930Sstevel@tonic-gate 		}
22940Sstevel@tonic-gate 		break;
22950Sstevel@tonic-gate 	}
22960Sstevel@tonic-gate 	TRIVIA(("] "));
22970Sstevel@tonic-gate 	return (1);
22980Sstevel@tonic-gate }
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate /*
23010Sstevel@tonic-gate  * when fsck is running it puts its pid into the lockfs
23020Sstevel@tonic-gate  * comment structure, prefaced by PIDSTR
23030Sstevel@tonic-gate  */
23040Sstevel@tonic-gate const char *PIDSTR = "[pid:";
23050Sstevel@tonic-gate static int
fsck_active(ufs_failure_t * f)23060Sstevel@tonic-gate fsck_active(ufs_failure_t *f)
23070Sstevel@tonic-gate {
23080Sstevel@tonic-gate 	char		*cp;
23090Sstevel@tonic-gate 	int		 i, found, errlocked;
23100Sstevel@tonic-gate 	size_t		 comlen;
23110Sstevel@tonic-gate 	const int	 PIDSTRLEN = (int)strlen(PIDSTR);
23120Sstevel@tonic-gate 	struct ulockfs	*ulp = &f->uf_ufsvfsp->vfs_ulockfs;
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	TRIVIA(("[fsck_active"));
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	ASSERT(f);
23170Sstevel@tonic-gate 	ASSERT(f->uf_s & UF_FIXING);
23180Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
23190Sstevel@tonic-gate 	ASSERT(f->uf_ufsvfsp);
23200Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
23210Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&ulp->ul_lock));
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	mutex_enter(&ulp->ul_lock);
23240Sstevel@tonic-gate 	cp = ulp->ul_lockfs.lf_comment;
23250Sstevel@tonic-gate 	comlen = ulp->ul_lockfs.lf_comlen;
23260Sstevel@tonic-gate 	errlocked = (int)ULOCKFS_IS_ELOCK(ulp);
23270Sstevel@tonic-gate 	mutex_exit(&ulp->ul_lock);
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	if (!cp || comlen == 0) {
23300Sstevel@tonic-gate 		TRIVIA((": null comment or comlen <= 0, found:0]"));
23310Sstevel@tonic-gate 		return (0);
23320Sstevel@tonic-gate 	}
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 	for (found = i = 0; !found && i < (comlen - PIDSTRLEN); i++, cp++)
23350Sstevel@tonic-gate 		found = strncmp(cp, PIDSTR, PIDSTRLEN) == 0;
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 	TRIVIA(("found:%d, is_elock:%d]", found, errlocked));
23380Sstevel@tonic-gate 	return (errlocked & found);
23390Sstevel@tonic-gate }
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate static const char unknown_fs[]		= "<unknown fs>";
23420Sstevel@tonic-gate static const char null_failure[] = "<NULL ufs failure record; unknown fs>";
23430Sstevel@tonic-gate static const char mutated_vfs_bufp[]	= "<mutated vfs_bufp, unknown fs>";
23440Sstevel@tonic-gate static const char mutated_vfs_fs[]	= "<mutated vfs_fs, unknown fs>";
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate static char *
fs_name(ufs_failure_t * f)23470Sstevel@tonic-gate fs_name(ufs_failure_t *f)
23480Sstevel@tonic-gate {
23490Sstevel@tonic-gate 	HIDEOUS(("[fs_name"));
23500Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&f->uf_mutex));
23510Sstevel@tonic-gate 
23520Sstevel@tonic-gate 	if (!f) {
23530Sstevel@tonic-gate 		HIDEOUS((": failure ptr is NULL]\n"));
23540Sstevel@tonic-gate 		return ((char *)null_failure);
23550Sstevel@tonic-gate 	}
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	if (f->uf_fsname[0] != '\0') {
23580Sstevel@tonic-gate 		HIDEOUS((": return (uf_fsname)]\n"));
23590Sstevel@tonic-gate 		return (f->uf_fsname);
23600Sstevel@tonic-gate 	}
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	if (MUTEX_HELD(f->uf_vfs_lockp)) {
23630Sstevel@tonic-gate 		if (f->uf_bp != f->uf_ufsvfsp->vfs_bufp) {
23640Sstevel@tonic-gate 			HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
23650Sstevel@tonic-gate 			    (void *)f->uf_bp, (void *)f->uf_ufsvfsp->vfs_bufp));
23660Sstevel@tonic-gate 			return ((char *)mutated_vfs_bufp);
23670Sstevel@tonic-gate 		}
23680Sstevel@tonic-gate 		if (f->uf_fs != f->uf_ufsvfsp->vfs_fs) {
23690Sstevel@tonic-gate 			HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
23700Sstevel@tonic-gate 			    (void *)f->uf_fs, (void *)f->uf_ufsvfsp->vfs_fs));
23710Sstevel@tonic-gate 			return ((char *)mutated_vfs_fs);
23720Sstevel@tonic-gate 		}
23730Sstevel@tonic-gate 		if (f->uf_ufsvfsp && f->uf_bp && f->uf_fs &&
23740Sstevel@tonic-gate 		    *f->uf_fs->fs_fsmnt != '\0') {
23750Sstevel@tonic-gate 			HIDEOUS((": return (fs_fsmnt)]\n"));
23760Sstevel@tonic-gate 			return (f->uf_fs->fs_fsmnt);
23770Sstevel@tonic-gate 		}
23780Sstevel@tonic-gate 	}
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	HIDEOUS((": unknown file system]\n"));
23810Sstevel@tonic-gate 	return ((char *)unknown_fs);
23820Sstevel@tonic-gate }
23830Sstevel@tonic-gate 
23840Sstevel@tonic-gate #if defined(DEBUG)
23850Sstevel@tonic-gate static char *
lock_name(struct lockfs * lfp)23860Sstevel@tonic-gate lock_name(struct lockfs *lfp)
23870Sstevel@tonic-gate {
23880Sstevel@tonic-gate 	struct lock_description	*l;
23890Sstevel@tonic-gate 	char			*lname;
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 	HIDEOUS(("[lock_name"));
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	lname = lock_desc[0].ld_name;
23940Sstevel@tonic-gate 	for (l = &lock_desc[1]; l->ld_name != NULL; l++) {
23950Sstevel@tonic-gate 		if (lfp && lfp->lf_lock == l->ld_type) {
23960Sstevel@tonic-gate 			lname = l->ld_name;
23970Sstevel@tonic-gate 			break;
23980Sstevel@tonic-gate 		}
23990Sstevel@tonic-gate 	}
24000Sstevel@tonic-gate 	HIDEOUS(("]"));
24010Sstevel@tonic-gate 	return (lname);
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate static char *
state_name(ufs_failure_states_t state)24050Sstevel@tonic-gate state_name(ufs_failure_states_t state)
24060Sstevel@tonic-gate {
24070Sstevel@tonic-gate 	ufsd_t	*s;
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate 	HIDEOUS(("[state_name"));
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 	s = get_state_desc(state);
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 	HIDEOUS(("]"));
24140Sstevel@tonic-gate 	return (s->ud_name);
24150Sstevel@tonic-gate }
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate static char *
err_name(int error)24180Sstevel@tonic-gate err_name(int error)
24190Sstevel@tonic-gate {
24200Sstevel@tonic-gate 	struct error_description *e;
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	HIDEOUS(("[err_name"));
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	for (e = &err_desc[1]; e->ed_name != NULL; e++) {
24250Sstevel@tonic-gate 		if (error == e->ed_errno) {
24260Sstevel@tonic-gate 			HIDEOUS(("]"));
24270Sstevel@tonic-gate 			return (e->ed_name);
24280Sstevel@tonic-gate 		}
24290Sstevel@tonic-gate 	}
24300Sstevel@tonic-gate 	HIDEOUS(("]"));
24310Sstevel@tonic-gate 	return (err_desc[0].ed_name);
24320Sstevel@tonic-gate }
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate static char *
act_name(ufsa_t action)24350Sstevel@tonic-gate act_name(ufsa_t action)
24360Sstevel@tonic-gate {
24370Sstevel@tonic-gate 	struct action_description *a;
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	HIDEOUS(("[act_name"));
24400Sstevel@tonic-gate 
24410Sstevel@tonic-gate 	for (a = &act_desc[1]; a->ad_name != NULL; a++) {
24420Sstevel@tonic-gate 		if (action == a->ad_v) {
24430Sstevel@tonic-gate 			HIDEOUS(("]"));
24440Sstevel@tonic-gate 			return (a->ad_name);
24450Sstevel@tonic-gate 		}
24460Sstevel@tonic-gate 	}
24470Sstevel@tonic-gate 	HIDEOUS(("]"));
24480Sstevel@tonic-gate 	return (act_desc[0].ad_name);
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate 
24510Sstevel@tonic-gate /*
24520Sstevel@tonic-gate  * dump failure list
24530Sstevel@tonic-gate  */
24540Sstevel@tonic-gate static void
dump_uf_list(char * msg)24550Sstevel@tonic-gate dump_uf_list(char *msg)
24560Sstevel@tonic-gate {
24570Sstevel@tonic-gate 	ufs_failure_t	*f;
24580Sstevel@tonic-gate 	int		 i;
24590Sstevel@tonic-gate 	int		 list_was_locked = MUTEX_HELD(&ufs_fix.uq_mutex);
24600Sstevel@tonic-gate 
24610Sstevel@tonic-gate 	if (!list_was_locked && !mutex_tryenter(&ufs_fix.uq_mutex)) {
24620Sstevel@tonic-gate 		printf("dump_uf_list: couldn't get list lock\n");
24630Sstevel@tonic-gate 		return;
24640Sstevel@tonic-gate 	}
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	if (msg) {
24670Sstevel@tonic-gate 		printf("\n%s", msg);
24680Sstevel@tonic-gate 	}
24690Sstevel@tonic-gate 	printf("\ndump_uf_list:\n\tuq_lowat: %d, uq_ne: %d\n",
24704662Sfrankho 	    ufs_fix.uq_lowat, ufs_fix.uq_ne);
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate 	mutex_enter(&uf_stats.ufst_mutex);
24730Sstevel@tonic-gate 	printf("\tuf_stats.current_races: %ld\n", uf_stats.ufst_current_races);
24740Sstevel@tonic-gate 	printf("\tuf_stats.num_failed: %ld\n", uf_stats.ufst_num_failed);
24750Sstevel@tonic-gate 	printf("\tuf_stats.num_fixed: %ld\n", uf_stats.ufst_num_fixed);
24760Sstevel@tonic-gate 	printf("\tuf_stats.cpu_waste: %ld\n", uf_stats.ufst_cpu_waste);
24770Sstevel@tonic-gate 	printf("\tuf_stats.lock_violations: %ld, unmount_failures: %ld\n",
24784662Sfrankho 	    uf_stats.ufst_lock_violations, uf_stats.ufst_unmount_failures);
24790Sstevel@tonic-gate 	mutex_exit(&uf_stats.ufst_mutex);
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead, i = 1; f; f = f->uf_next, i++) {
24820Sstevel@tonic-gate 
24830Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex)) {
24840Sstevel@tonic-gate 			printf("%d.\t\"skipped - try enter failed\"\n", i);
24850Sstevel@tonic-gate 			continue;
24860Sstevel@tonic-gate 		}
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 		dump_uf(f, i);
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
24910Sstevel@tonic-gate 	}
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 	printf("\n");
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 	if (!list_was_locked)
24960Sstevel@tonic-gate 		mutex_exit(&ufs_fix.uq_mutex);
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate static void
dump_uf(ufs_failure_t * f,int i)25000Sstevel@tonic-gate dump_uf(ufs_failure_t *f, int i)
25010Sstevel@tonic-gate {
25020Sstevel@tonic-gate 	if (!f) {
25030Sstevel@tonic-gate 		printf("dump_uf: NULL failure record\n");
25040Sstevel@tonic-gate 		return;
25050Sstevel@tonic-gate 	}
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	printf("%d.\t\"%s\" is %s.\n",
25084662Sfrankho 	    i, fs_name(f), state_name(f->uf_s));
25090Sstevel@tonic-gate 	printf("\t\"%s\"\tAddr: 0x%p\n", f->uf_panic_str, (void *)f);
25100Sstevel@tonic-gate 	printf("\tNext: 0x%p\t\tPrev: 0x%p\n",
25114662Sfrankho 	    (void *)f->uf_next, (void *)f->uf_prev);
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	if (f->uf_orig)
25140Sstevel@tonic-gate 		printf("\tOriginal failure: 0x%p \"%s\"\n",
25150Sstevel@tonic-gate 		    (void *)f->uf_orig, f->uf_orig->uf_panic_str);
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate 	printf("\tUfsvfs: 0x%p\t\tVfs_lockp: 0x%p\n",
25184662Sfrankho 	    (void *)f->uf_ufsvfsp, (void *)f->uf_vfs_lockp);
25190Sstevel@tonic-gate 	printf("\tVfs_fsfxp: 0x%p\n", (void *)f->uf_vfs_ufsfxp);
25200Sstevel@tonic-gate 	printf("\tVfs_bufp: 0x%p", (void *)f->uf_bp);
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	if (f->uf_bp)
25230Sstevel@tonic-gate 		printf("\t\tVfs_fs: 0x%p\n", (void *)f->uf_fs);
25240Sstevel@tonic-gate 	else
25250Sstevel@tonic-gate 		printf("\n");
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 	printf("\tBegin: 0x%lx\tEntered: 0x%lx\tEnd: 0x%lx\n",
25280Sstevel@tonic-gate 	    f->uf_begin_tm, f->uf_entered_tm, f->uf_end_tm);
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 	printf("\tFlags: (%d) %s%s%s%s", f->uf_flags,
25314662Sfrankho 	    f->uf_flags & UFSFX_LCKONLY?	 "\"lock only\" "	: "",
25324662Sfrankho 	    f->uf_flags & UFSFX_LCKUMOUNT?	 "\"lock+unmount\" "	: "",
25334662Sfrankho 	    f->uf_flags & UFSFX_REPAIR_START? "\"started repair\" "	: "",
25344662Sfrankho 	    f->uf_flags == 0?                "<none>"               : "");
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 	printf("\tRetry: %ld seconds\n", f->uf_retry);
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	printf("\tLockfs:\ttype: %s\terror: %s (%d)\n",
25394662Sfrankho 	    lock_name(&f->uf_lf), err_name(f->uf_lf_err), f->uf_lf_err);
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate }
25420Sstevel@tonic-gate #endif /* DEBUG */
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate /*
25450Sstevel@tonic-gate  * returns # of ufs_failures in a non-terminal state on queue
25460Sstevel@tonic-gate  * used to coordinate with hlock thread (see ufs_thread.c)
25470Sstevel@tonic-gate  * and to determine when the error lock thread may exit
25480Sstevel@tonic-gate  */
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate int
ufsfx_get_failure_qlen(void)25510Sstevel@tonic-gate ufsfx_get_failure_qlen(void)
25520Sstevel@tonic-gate {
25530Sstevel@tonic-gate 	ufs_failure_t	*f;
25540Sstevel@tonic-gate 	ufsd_t		*s;
25550Sstevel@tonic-gate 	int		 qlen = 0;
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate 	MINUTE(("[ufsfx_get_failure_qlen"));
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	if (!mutex_tryenter(&ufs_fix.uq_mutex))
25600Sstevel@tonic-gate 		return (-1);
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	/*
25630Sstevel@tonic-gate 	 * walk down failure list
25640Sstevel@tonic-gate 	 */
25650Sstevel@tonic-gate 
25660Sstevel@tonic-gate 	for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 		if (!mutex_tryenter(&f->uf_mutex))
25690Sstevel@tonic-gate 			continue;
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 		s = get_state_desc(f->uf_s);
25720Sstevel@tonic-gate 
25730Sstevel@tonic-gate 		if (s->ud_attr.terminal) {
25740Sstevel@tonic-gate 			mutex_exit(&f->uf_mutex);
25750Sstevel@tonic-gate 			continue;
25760Sstevel@tonic-gate 		}
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 		MINUTE((": found: %s, \"%s: %s\"\n",
25794662Sfrankho 		    fs_name(f), state_name(f->uf_s), f->uf_panic_str));
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate 		qlen++;
25820Sstevel@tonic-gate 		mutex_exit(&f->uf_mutex);
25830Sstevel@tonic-gate 	}
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 	mutex_exit(&ufs_fix.uq_mutex);
25860Sstevel@tonic-gate 
25870Sstevel@tonic-gate 	MINUTE((": qlen=%d]\n", qlen));
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	return (qlen);
25900Sstevel@tonic-gate }
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate /*
25930Sstevel@tonic-gate  * timeout routine
25940Sstevel@tonic-gate  *  called to shutdown fix failure thread and server daemon
25950Sstevel@tonic-gate  */
25960Sstevel@tonic-gate static void
ufsfx_kill_fix_failure_thread(void * arg)25970Sstevel@tonic-gate ufsfx_kill_fix_failure_thread(void *arg)
25980Sstevel@tonic-gate {
25990Sstevel@tonic-gate 	clock_t odelta = (clock_t)arg;
26000Sstevel@tonic-gate 	int	qlen;
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate 	MAJOR(("[ufsfx_kill_fix_failure_thread"));
26030Sstevel@tonic-gate 
26040Sstevel@tonic-gate 	qlen = ufsfx_get_failure_qlen();
26050Sstevel@tonic-gate 
26060Sstevel@tonic-gate 	if (qlen < 0) {
26070Sstevel@tonic-gate 		clock_t delta;
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate 		delta = odelta << 1;
26100Sstevel@tonic-gate 		if (delta <= 0)
26110Sstevel@tonic-gate 			delta = INT_MAX;
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate 		(void) timeout(ufsfx_kill_fix_failure_thread,
26140Sstevel@tonic-gate 		    (void *)delta, delta);
26150Sstevel@tonic-gate 		MAJOR((": rescheduled"));
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 	} else if (qlen == 0) {
26180Sstevel@tonic-gate 		ufs_thread_exit(&ufs_fix);
26190Sstevel@tonic-gate 		MAJOR((": killed"));
26200Sstevel@tonic-gate 	}
26210Sstevel@tonic-gate 	/*
26220Sstevel@tonic-gate 	 * else
26230Sstevel@tonic-gate 	 *  let timeout expire
26240Sstevel@tonic-gate 	 */
26250Sstevel@tonic-gate 	MAJOR(("]\n"));
26260Sstevel@tonic-gate }
2627