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