17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
566c9f83dSowenr * Common Development and Distribution License (the "License").
666c9f83dSowenr * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/systm.h>
297c478bd9Sstevel@tonic-gate #include <sys/errno.h>
307c478bd9Sstevel@tonic-gate #include <sys/mode.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
337c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <sys/buf.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
387c478bd9Sstevel@tonic-gate #include <sys/poll.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/lockfs.h>
427c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
437c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
447c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_panic.h>
457c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_lockfs.h>
467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_trans.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_mount.h>
487c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_prot.h>
497c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
507c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
517c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
527c478bd9Sstevel@tonic-gate #include <sys/conf.h>
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate /* handy */
557c478bd9Sstevel@tonic-gate #define abs(x) ((x) < 0? -(x): (x))
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate #if defined(DEBUG)
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define DBGLVL_NONE 0x00000000
607c478bd9Sstevel@tonic-gate #define DBGLVL_MAJOR 0x00000100
617c478bd9Sstevel@tonic-gate #define DBGLVL_MINOR 0x00000200
627c478bd9Sstevel@tonic-gate #define DBGLVL_MINUTE 0x00000400
637c478bd9Sstevel@tonic-gate #define DBGLVL_TRIVIA 0x00000800
647c478bd9Sstevel@tonic-gate #define DBGLVL_HIDEOUS 0x00001000
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate #define DBGFLG_NONE 0x00000000
677c478bd9Sstevel@tonic-gate #define DBGFLG_NOPANIC 0x00000001
687c478bd9Sstevel@tonic-gate #define DBGFLG_LVLONLY 0x00000002
697c478bd9Sstevel@tonic-gate #define DBGFLG_FIXWOULDPANIC 0x00000004
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate #define DBGFLG_FLAGMASK 0x0000000F
727c478bd9Sstevel@tonic-gate #define DBGFLG_LEVELMASK ~DBGFLG_FLAGMASK
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate #define DEBUG_FLAGS (ufs_fix_failure_dbg & DBGFLG_FLAGMASK)
757c478bd9Sstevel@tonic-gate #define DEBUG_LEVEL (ufs_fix_failure_dbg & DBGFLG_LEVELMASK)
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate unsigned int ufs_fix_failure_dbg = DBGLVL_NONE | DBGFLG_NONE;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate #define DCALL(dbg_level, call) \
807c478bd9Sstevel@tonic-gate { \
817c478bd9Sstevel@tonic-gate if (DEBUG_LEVEL != DBGLVL_NONE) { \
827c478bd9Sstevel@tonic-gate if (DEBUG_FLAGS & DBGFLG_LVLONLY) { \
837c478bd9Sstevel@tonic-gate if (DEBUG_LEVEL & dbg_level) { \
847c478bd9Sstevel@tonic-gate call; \
857c478bd9Sstevel@tonic-gate } \
867c478bd9Sstevel@tonic-gate } else { \
877c478bd9Sstevel@tonic-gate if (dbg_level <= DEBUG_LEVEL) { \
887c478bd9Sstevel@tonic-gate call; \
897c478bd9Sstevel@tonic-gate } \
907c478bd9Sstevel@tonic-gate } \
917c478bd9Sstevel@tonic-gate } \
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate #define DPRINTF(dbg_level, msg) DCALL(dbg_level, printf msg)
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate #define MAJOR(msg) DPRINTF(DBGLVL_MAJOR, msg)
977c478bd9Sstevel@tonic-gate #define MINOR(msg) DPRINTF(DBGLVL_MINOR, msg)
987c478bd9Sstevel@tonic-gate #define MINUTE(msg) DPRINTF(DBGLVL_MINUTE, msg)
997c478bd9Sstevel@tonic-gate #define TRIVIA(msg) DPRINTF(DBGLVL_TRIVIA, msg)
1007c478bd9Sstevel@tonic-gate #define HIDEOUS(msg) DPRINTF(DBGLVL_HIDEOUS, msg)
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate #else /* !DEBUG */
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate #define DCALL(ignored_dbg_level, ignored_routine)
1057c478bd9Sstevel@tonic-gate #define MAJOR(ignored)
1067c478bd9Sstevel@tonic-gate #define MINOR(ignored)
1077c478bd9Sstevel@tonic-gate #define MINUTE(ignored)
1087c478bd9Sstevel@tonic-gate #define TRIVIA(ignored)
1097c478bd9Sstevel@tonic-gate #define HIDEOUS(ignored)
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate #define NULLSTR(str) (!(str) || *(str) == '\0'? "<null>" : (str))
1147c478bd9Sstevel@tonic-gate #define NULSTRING ""
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /* somewhat arbitrary limits, in seconds */
1177c478bd9Sstevel@tonic-gate /* all probably ought to be different, but these are convenient for debugging */
1187c478bd9Sstevel@tonic-gate const time_t UF_TOO_LONG = 128; /* max. wait for fsck start */
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /* all of these are in units of seconds used for retry period while ... */
1217c478bd9Sstevel@tonic-gate const time_t UF_FIXSTART_PERIOD = 16; /* awaiting fsck start */
1227c478bd9Sstevel@tonic-gate const time_t UF_FIXPOLL_PERIOD = 256; /* awaiting fsck finish */
1237c478bd9Sstevel@tonic-gate const time_t UF_SHORT_ERROR_PERIOD = 4; /* after (lockfs) error */
1247c478bd9Sstevel@tonic-gate const time_t UF_LONG_ERROR_PERIOD = 512; /* after (lockfs) error */
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate #define NO_ERROR 0
1277c478bd9Sstevel@tonic-gate #define LOCKFS_OLOCK LOCKFS_MAXLOCK+1
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate const ulong_t GB = 1024 * 1024 * 1024;
1307c478bd9Sstevel@tonic-gate const ulong_t SecondsPerGig = 1024; /* ~17 minutes (overestimate) */
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate * per filesystem flags
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate const int UFSFX_PANIC = (UFSMNT_ONERROR_PANIC >> 4);
1367c478bd9Sstevel@tonic-gate const int UFSFX_LCKONLY = (UFSMNT_ONERROR_LOCK >> 4);
1377c478bd9Sstevel@tonic-gate const int UFSFX_LCKUMOUNT = (UFSMNT_ONERROR_UMOUNT >> 4);
1387c478bd9Sstevel@tonic-gate const int UFSFX_DEFAULT = (UFSMNT_ONERROR_DEFAULT >> 4);
1397c478bd9Sstevel@tonic-gate const int UFSFX_REPAIR_START = 0x10000000;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /* return protocols */
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate typedef enum triage_return_code {
1447c478bd9Sstevel@tonic-gate TRIAGE_DEAD = -1,
1457c478bd9Sstevel@tonic-gate TRIAGE_NO_SPIRIT,
1467c478bd9Sstevel@tonic-gate TRIAGE_ATTEND_TO
1477c478bd9Sstevel@tonic-gate } triage_t;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate typedef enum statefunc_return_code {
1507c478bd9Sstevel@tonic-gate SFRC_SUCCESS = 1,
1517c478bd9Sstevel@tonic-gate SFRC_FAIL = 0
1527c478bd9Sstevel@tonic-gate } sfrc_t;
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate /* external references */
1557c478bd9Sstevel@tonic-gate /* in ufs_thread.c */
1567c478bd9Sstevel@tonic-gate extern int ufs_thread_run(struct ufs_q *, callb_cpr_t *cprinfop);
1577c478bd9Sstevel@tonic-gate extern int ufs_checkaccton(vnode_t *); /* in ufs_lockfs.c */
1587c478bd9Sstevel@tonic-gate extern int ufs_checkswapon(vnode_t *); /* in ufs_lockfs.c */
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate extern struct pollhead ufs_pollhd; /* in ufs_vnops.c */
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /* globals */
1637c478bd9Sstevel@tonic-gate struct ufs_q ufs_fix;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate * patchable constants:
1677c478bd9Sstevel@tonic-gate * These are set in ufsfx_init() [called at modload]
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate struct ufs_failure_tunable {
1707c478bd9Sstevel@tonic-gate long uft_too_long; /* limit repair startup time */
1717c478bd9Sstevel@tonic-gate long uft_fixstart_period; /* pre-repair start period */
1727c478bd9Sstevel@tonic-gate long uft_fixpoll_period; /* post-fsck start period */
1737c478bd9Sstevel@tonic-gate long uft_short_err_period; /* post-error short period */
1747c478bd9Sstevel@tonic-gate long uft_long_err_period; /* post-error long period */
1757c478bd9Sstevel@tonic-gate } ufsfx_tune;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /* internal statistics of events */
1787c478bd9Sstevel@tonic-gate struct uf_statistics {
1797c478bd9Sstevel@tonic-gate ulong_t ufst_lock_violations;
1807c478bd9Sstevel@tonic-gate ulong_t ufst_current_races;
1817c478bd9Sstevel@tonic-gate ulong_t ufst_unmount_failures;
1827c478bd9Sstevel@tonic-gate ulong_t ufst_num_fixed;
1837c478bd9Sstevel@tonic-gate ulong_t ufst_num_failed;
1847c478bd9Sstevel@tonic-gate ulong_t ufst_cpu_waste;
1857c478bd9Sstevel@tonic-gate time_t ufst_last_start_tm;
1867c478bd9Sstevel@tonic-gate kmutex_t ufst_mutex;
1877c478bd9Sstevel@tonic-gate } uf_stats;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate typedef enum state_action {
1907c478bd9Sstevel@tonic-gate UFA_ERROR = -1, /* internal error */
1917c478bd9Sstevel@tonic-gate UFA_FOUND, /* found uf in state */
1927c478bd9Sstevel@tonic-gate UFA_SET /* change uf to state */
1937c478bd9Sstevel@tonic-gate } ufsa_t;
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate /* state definition */
1967c478bd9Sstevel@tonic-gate typedef struct uf_state_desc {
1977c478bd9Sstevel@tonic-gate int ud_v; /* value */
1987c478bd9Sstevel@tonic-gate char *ud_name; /* name */
1997c478bd9Sstevel@tonic-gate sfrc_t (*ud_sfp)(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2007c478bd9Sstevel@tonic-gate /* per-state actions */
2017c478bd9Sstevel@tonic-gate ufs_failure_states_t ud_prev; /* valid prev. states */
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate struct uf_state_desc_attr {
2047c478bd9Sstevel@tonic-gate unsigned terminal:1; /* no action req. if found */
2057c478bd9Sstevel@tonic-gate unsigned at_fail:1; /* state set by thread */
2067c478bd9Sstevel@tonic-gate /* encountering the error */
2077c478bd9Sstevel@tonic-gate unsigned unused;
2087c478bd9Sstevel@tonic-gate } ud_attr;
2097c478bd9Sstevel@tonic-gate } ufsd_t;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * forward references
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate /* thread to watch for failures */
2167c478bd9Sstevel@tonic-gate static void ufsfx_thread_fix_failures(void *);
2177c478bd9Sstevel@tonic-gate static int ufsfx_do_failure_q(void);
2187c478bd9Sstevel@tonic-gate static void ufsfx_kill_fix_failure_thread(void *);
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /* routines called when failure occurs */
2217c478bd9Sstevel@tonic-gate static int ufs_fault_v(vnode_t *, char *, va_list)
2227c478bd9Sstevel@tonic-gate __KVPRINTFLIKE(2);
2237c478bd9Sstevel@tonic-gate static ufs_failure_t *init_failure(vnode_t *, char *, va_list)
2247c478bd9Sstevel@tonic-gate __KVPRINTFLIKE(2);
2257c478bd9Sstevel@tonic-gate static void queue_failure(ufs_failure_t *);
2267c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2277c478bd9Sstevel@tonic-gate static void real_panic(ufs_failure_t *, const char *, ...)
2287c478bd9Sstevel@tonic-gate __KPRINTFLIKE(2);
2297c478bd9Sstevel@tonic-gate static void real_panic_v(ufs_failure_t *, const char *, va_list)
2307c478bd9Sstevel@tonic-gate __KVPRINTFLIKE(2);
2317c478bd9Sstevel@tonic-gate static triage_t triage(vnode_t *);
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate /* routines called when failure record is acted upon */
2347c478bd9Sstevel@tonic-gate static sfrc_t set_state(ufs_failure_t *, ufs_failure_states_t);
2357c478bd9Sstevel@tonic-gate static int state_trans_valid(ufs_failure_states_t, ufs_failure_states_t);
2367c478bd9Sstevel@tonic-gate static int terminal_state(ufs_failure_states_t);
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate /* routines called when states entered/found */
2397c478bd9Sstevel@tonic-gate static sfrc_t sf_minimum(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2407c478bd9Sstevel@tonic-gate static sfrc_t sf_undef(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2417c478bd9Sstevel@tonic-gate static sfrc_t sf_init(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2427c478bd9Sstevel@tonic-gate static sfrc_t sf_queue(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2437c478bd9Sstevel@tonic-gate static sfrc_t sf_found_queue(ufs_failure_t *);
2447c478bd9Sstevel@tonic-gate static sfrc_t sf_nonterm_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2457c478bd9Sstevel@tonic-gate static sfrc_t sf_term_cmn(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2467c478bd9Sstevel@tonic-gate static sfrc_t sf_panic(ufs_failure_t *, ufsa_t, ufs_failure_states_t);
2477c478bd9Sstevel@tonic-gate static sfrc_t sf_set_trylck(ufs_failure_t *);
2487c478bd9Sstevel@tonic-gate static sfrc_t sf_set_locked(ufs_failure_t *);
2497c478bd9Sstevel@tonic-gate static sfrc_t sf_found_trylck(ufs_failure_t *);
2507c478bd9Sstevel@tonic-gate static sfrc_t sf_found_lock_fix_cmn(ufs_failure_t *, ufs_failure_states_t);
2517c478bd9Sstevel@tonic-gate static sfrc_t sf_found_umount(ufs_failure_t *);
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate /* support routines, called by sf_nonterm_cmn and sf_term_cmn */
2547c478bd9Sstevel@tonic-gate static time_t trylock_time_exceeded(ufs_failure_t *);
2557c478bd9Sstevel@tonic-gate static void pester_msg(ufs_failure_t *, int);
2567c478bd9Sstevel@tonic-gate static int get_lockfs_status(ufs_failure_t *, struct lockfs *);
2577c478bd9Sstevel@tonic-gate static void alloc_lockfs_comment(ufs_failure_t *, struct lockfs *);
2587c478bd9Sstevel@tonic-gate static int set_lockfs(ufs_failure_t *, struct lockfs *);
2597c478bd9Sstevel@tonic-gate static int lockfs_failure(ufs_failure_t *);
2607c478bd9Sstevel@tonic-gate static int lockfs_success(ufs_failure_t *);
2617c478bd9Sstevel@tonic-gate static int fsck_active(ufs_failure_t *);
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /* low-level support routines */
2647c478bd9Sstevel@tonic-gate static ufsd_t *get_state_desc(ufs_failure_states_t);
2657c478bd9Sstevel@tonic-gate static char *fs_name(ufs_failure_t *);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate #if defined(DEBUG)
2687c478bd9Sstevel@tonic-gate static char *state_name(ufs_failure_states_t);
2697c478bd9Sstevel@tonic-gate static char *lock_name(struct lockfs *);
2707c478bd9Sstevel@tonic-gate static char *err_name(int);
2717c478bd9Sstevel@tonic-gate static char *act_name(ufsa_t);
2727c478bd9Sstevel@tonic-gate static void dump_uf_list(char *msg);
2737c478bd9Sstevel@tonic-gate static void dump_uf(ufs_failure_t *, int i);
2747c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate *
2777c478bd9Sstevel@tonic-gate * State Transitions:
2787c478bd9Sstevel@tonic-gate *
2797c478bd9Sstevel@tonic-gate * normally:
2807c478bd9Sstevel@tonic-gate * if flagged to be locked but not unmounted: (UFSMNT_ONERROR_LOCK)
2817c478bd9Sstevel@tonic-gate * UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> FIXING -> FIXED
2827c478bd9Sstevel@tonic-gate *
2837c478bd9Sstevel@tonic-gate * The only difference between these two is that the fsck must be started
2847c478bd9Sstevel@tonic-gate * manually.
2857c478bd9Sstevel@tonic-gate *
2867c478bd9Sstevel@tonic-gate * if flagged to be unmounted: (UFSMNT_ONERROR_UMOUNT)
2877c478bd9Sstevel@tonic-gate * UNDEF -> INIT -> QUEUE -> TRYLCK -> LOCKED -> UMOUNT -> NOTFIX
2887c478bd9Sstevel@tonic-gate *
2897c478bd9Sstevel@tonic-gate * if flagged to panic: (UFSMNT_ONERROR_PANIC)
2907c478bd9Sstevel@tonic-gate * UNDEF -> INIT -> PANIC
2917c478bd9Sstevel@tonic-gate *
2927c478bd9Sstevel@tonic-gate * if a secondary panic on a file system which has an active failure
2937c478bd9Sstevel@tonic-gate * record:
2947c478bd9Sstevel@tonic-gate * UNDEF -> INIT -> QUEUE -> REPLICA
2957c478bd9Sstevel@tonic-gate *
2967c478bd9Sstevel@tonic-gate * UNDEF, INIT, QUEUE all are set in the context of the failing thread.
2977c478bd9Sstevel@tonic-gate * All other states (except possibly PANIC) are set in by the monitor
2987c478bd9Sstevel@tonic-gate * (lock) thread.
2997c478bd9Sstevel@tonic-gate *
3007c478bd9Sstevel@tonic-gate */
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate ufsd_t state_desc[] =
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate { UF_ILLEGAL, "in an unknown state", sf_minimum, UF_ILLEGAL,
3057c478bd9Sstevel@tonic-gate { 0, 1, 0 } },
3067c478bd9Sstevel@tonic-gate { UF_UNDEF, "undefined", sf_undef, UF_UNDEF,
3077c478bd9Sstevel@tonic-gate { 0, 1, 0 } },
3087c478bd9Sstevel@tonic-gate { UF_INIT, "being initialized", sf_init, UF_UNDEF,
3097c478bd9Sstevel@tonic-gate { 0, 1, 0 } },
3107c478bd9Sstevel@tonic-gate { UF_QUEUE, "queued", sf_queue, UF_INIT,
3117c478bd9Sstevel@tonic-gate { 0, 1, 0 } },
3127c478bd9Sstevel@tonic-gate { UF_TRYLCK, "trying to be locked", sf_nonterm_cmn,
3137c478bd9Sstevel@tonic-gate UF_QUEUE, { 0, 0, 0 } },
3147c478bd9Sstevel@tonic-gate { UF_LOCKED, "locked", sf_nonterm_cmn,
3157c478bd9Sstevel@tonic-gate UF_TRYLCK | UF_FIXING, { 0, 0, 0 } },
3167c478bd9Sstevel@tonic-gate { UF_UMOUNT, "being unmounted", sf_nonterm_cmn,
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3197c478bd9Sstevel@tonic-gate UF_PANIC |
3207c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3217c478bd9Sstevel@tonic-gate UF_TRYLCK | UF_LOCKED, { 0, 0, 0 } },
3227c478bd9Sstevel@tonic-gate { UF_FIXING, "being fixed", sf_nonterm_cmn,
3237c478bd9Sstevel@tonic-gate UF_LOCKED, { 0, 0, 0 } },
3247c478bd9Sstevel@tonic-gate { UF_FIXED, "fixed", sf_term_cmn,
3257c478bd9Sstevel@tonic-gate UF_FIXING, { 1, 0, 0 } },
3267c478bd9Sstevel@tonic-gate { UF_NOTFIX, "not fixed", sf_term_cmn,
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3297c478bd9Sstevel@tonic-gate UF_PANIC |
3307c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate UF_QUEUE | UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING,
3337c478bd9Sstevel@tonic-gate { 1, 0, 0 } },
3347c478bd9Sstevel@tonic-gate { UF_REPLICA, "a replica", sf_term_cmn,
3357c478bd9Sstevel@tonic-gate UF_QUEUE, { 1, 0, 0 } },
3367c478bd9Sstevel@tonic-gate { UF_PANIC, "panicking", sf_panic,
3377c478bd9Sstevel@tonic-gate /* XXX make this narrower */ UF_ALLSTATES, { 0, 0, 0 } },
3387c478bd9Sstevel@tonic-gate { UF_UNDEF, NULL, ((sfrc_t (*)()) NULL),
3397c478bd9Sstevel@tonic-gate UF_UNDEF, { 0, 0, 0 } }
3407c478bd9Sstevel@tonic-gate };
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /* unified collection */
3437c478bd9Sstevel@tonic-gate struct ufsfx_info {
3447c478bd9Sstevel@tonic-gate struct uf_statistics *ufi_statp;
3457c478bd9Sstevel@tonic-gate struct ufs_failure_tunable *ufi_tunep;
3467c478bd9Sstevel@tonic-gate ufsd_t *ufi_statetab;
3477c478bd9Sstevel@tonic-gate } uffsinfo;
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3507c478bd9Sstevel@tonic-gate struct action_description {
3517c478bd9Sstevel@tonic-gate ufsa_t ad_v;
3527c478bd9Sstevel@tonic-gate char *ad_name;
3537c478bd9Sstevel@tonic-gate };
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate #define EUNK (-1)
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate struct error_description {
3587c478bd9Sstevel@tonic-gate int ed_errno;
3597c478bd9Sstevel@tonic-gate char *ed_name;
3607c478bd9Sstevel@tonic-gate } err_desc[] =
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate { EUNK, "<unexpected errno?>" },
3637c478bd9Sstevel@tonic-gate { EINVAL, "EINVAL" },
3647c478bd9Sstevel@tonic-gate { EACCES, "EACCES" },
3657c478bd9Sstevel@tonic-gate { EPERM, "EPERM" },
3667c478bd9Sstevel@tonic-gate { EIO, "EIO" },
3677c478bd9Sstevel@tonic-gate { EDEADLK, "EDEADLK" },
3687c478bd9Sstevel@tonic-gate { EBUSY, "EBUSY" },
3697c478bd9Sstevel@tonic-gate { EAGAIN, "EAGAIN" },
3707c478bd9Sstevel@tonic-gate { ERESTART, "ERESTART" },
3717c478bd9Sstevel@tonic-gate { ETIMEDOUT, "ETIMEDOUT" },
3727c478bd9Sstevel@tonic-gate { NO_ERROR, "Ok" },
3737c478bd9Sstevel@tonic-gate { EUNK, NULL }
3747c478bd9Sstevel@tonic-gate };
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate struct action_description act_desc[] =
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate { UFA_ERROR, "<unexpected action?>" },
3797c478bd9Sstevel@tonic-gate { UFA_FOUND, "\"found\"" },
3807c478bd9Sstevel@tonic-gate { UFA_SET, "\"set\"" },
3817c478bd9Sstevel@tonic-gate { UFA_ERROR, NULL },
3827c478bd9Sstevel@tonic-gate };
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate #define LOCKFS_BADLOCK (-1)
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate struct lock_description {
3877c478bd9Sstevel@tonic-gate int ld_type;
3887c478bd9Sstevel@tonic-gate char *ld_name;
3897c478bd9Sstevel@tonic-gate } lock_desc[] =
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate { LOCKFS_BADLOCK, "<unexpected lock?>" },
3927c478bd9Sstevel@tonic-gate { LOCKFS_ULOCK, "Unlock" },
3937c478bd9Sstevel@tonic-gate { LOCKFS_ELOCK, "Error Lock" },
3947c478bd9Sstevel@tonic-gate { LOCKFS_HLOCK, "Hard Lock" },
3957c478bd9Sstevel@tonic-gate { LOCKFS_OLOCK, "Old Lock" },
3967c478bd9Sstevel@tonic-gate { LOCKFS_BADLOCK, NULL }
3977c478bd9Sstevel@tonic-gate };
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate * ufs_fault, ufs_fault_v
4037c478bd9Sstevel@tonic-gate *
4047c478bd9Sstevel@tonic-gate * called instead of cmn_err(CE_PANIC, ...) by ufs routines
4057c478bd9Sstevel@tonic-gate * when a failure is detected to put the file system into an
4067c478bd9Sstevel@tonic-gate * error state (if possible) or to devolve to a panic otherwise
4077c478bd9Sstevel@tonic-gate *
4087c478bd9Sstevel@tonic-gate * vnode is some vnode in this file system, used to find the way
4097c478bd9Sstevel@tonic-gate * to ufsvfs, vfsp etc. Since a panic can be called from many
4107c478bd9Sstevel@tonic-gate * levels, the vnode is the most convenient hook to pass through.
4117c478bd9Sstevel@tonic-gate *
4127c478bd9Sstevel@tonic-gate */
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
4157c478bd9Sstevel@tonic-gate int
ufs_fault(vnode_t * vp,char * fmt,...)4167c478bd9Sstevel@tonic-gate ufs_fault(vnode_t *vp, char *fmt, ...)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate va_list adx;
4197c478bd9Sstevel@tonic-gate int error;
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate MINOR(("[ufs_fault"));
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate va_start(adx, fmt);
4247c478bd9Sstevel@tonic-gate error = ufs_fault_v(vp, fmt, adx);
4257c478bd9Sstevel@tonic-gate va_end(adx);
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate MINOR((": %s (%d)]\n", err_name(error), error));
4287c478bd9Sstevel@tonic-gate return (error);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate const char *nullfmt = "<null format?>";
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate static int
ufs_fault_v(vnode_t * vp,char * fmt,va_list adx)4347c478bd9Sstevel@tonic-gate ufs_fault_v(vnode_t *vp, char *fmt, va_list adx)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate ufs_failure_t *new = NULL;
4377c478bd9Sstevel@tonic-gate ufsvfs_t *ufsvfsp;
4387c478bd9Sstevel@tonic-gate triage_t fix;
4397c478bd9Sstevel@tonic-gate int err = ERESTART;
4407c478bd9Sstevel@tonic-gate int need_vfslock;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate MINOR(("[ufs_fault_v"));
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate if (fmt == NULL)
4457c478bd9Sstevel@tonic-gate fmt = (char *)nullfmt;
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate fix = triage(vp);
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate if (vp) {
4507c478bd9Sstevel@tonic-gate ufsvfsp = (struct ufsvfs *)vp->v_vfsp->vfs_data;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate * Something bad has happened. That is why we are here.
4547c478bd9Sstevel@tonic-gate *
4557c478bd9Sstevel@tonic-gate * In order for the bad thing to be recorded in the superblock
4567c478bd9Sstevel@tonic-gate * we need to write to the superblock directly.
4577c478bd9Sstevel@tonic-gate * In the case that logging is enabled the logging code
4587c478bd9Sstevel@tonic-gate * would normally intercept our write as a delta to the log,
4597c478bd9Sstevel@tonic-gate * thus we mark the filesystem FSBAD in any case.
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate need_vfslock = !MUTEX_HELD(&ufsvfsp->vfs_lock);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate if (need_vfslock) {
4647c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate ufsvfsp->vfs_fs->fs_clean = FSBAD;
4687c478bd9Sstevel@tonic-gate ASSERT(SEMA_HELD(&ufsvfsp->vfs_bufp->b_sem));
46980d34432Sfrankho ufsvfsp->vfs_bufp->b_flags &=
47080d34432Sfrankho ~(B_ASYNC | B_READ | B_DONE | B_ERROR | B_DELWRI);
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate (void) bdev_strategy(ufsvfsp->vfs_bufp);
4737c478bd9Sstevel@tonic-gate (void) biowait(ufsvfsp->vfs_bufp);
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate if (need_vfslock) {
4767c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate switch (fix) {
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate default:
4837c478bd9Sstevel@tonic-gate case TRIAGE_DEAD:
4847c478bd9Sstevel@tonic-gate case TRIAGE_NO_SPIRIT:
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate real_panic_v(new, fmt, adx);
4877c478bd9Sstevel@tonic-gate /* LINTED: warning: logical expression always true: op "||" */
4887c478bd9Sstevel@tonic-gate ASSERT(DEBUG);
4897c478bd9Sstevel@tonic-gate err = EAGAIN;
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate #if defined(DEBUG)
4927c478bd9Sstevel@tonic-gate if (!(DEBUG_FLAGS & DBGFLG_FIXWOULDPANIC)) {
4937c478bd9Sstevel@tonic-gate break;
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate #else
4987c478bd9Sstevel@tonic-gate break;
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate case TRIAGE_ATTEND_TO:
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /* q thread not running yet? */
50566c9f83dSowenr if (mutex_tryenter(&ufs_fix.uq_mutex)) {
5067c478bd9Sstevel@tonic-gate if (!ufs_fix.uq_threadp) {
5077c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
50866c9f83dSowenr ufs_thread_start(&ufs_fix,
50966c9f83dSowenr ufsfx_thread_fix_failures, NULL);
5107c478bd9Sstevel@tonic-gate ufs_fix.uq_threadp->t_flag |= T_DONTBLOCK;
5117c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
5127c478bd9Sstevel@tonic-gate } else {
51366c9f83dSowenr /*
51466c9f83dSowenr * We got the lock but we are not the current
51566c9f83dSowenr * threadp so we have to release the lock.
51666c9f83dSowenr */
51766c9f83dSowenr mutex_exit(&ufs_fix.uq_mutex);
51866c9f83dSowenr }
51966c9f83dSowenr } else {
5207c478bd9Sstevel@tonic-gate MINOR((": fix failure thread already running "));
52166c9f83dSowenr /*
52266c9f83dSowenr * No need to log another failure as one is already
52366c9f83dSowenr * being logged.
52466c9f83dSowenr */
52566c9f83dSowenr break;
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate if (ufs_fix.uq_threadp && ufs_fix.uq_threadp == curthread) {
5297c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
5307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufs_fault_v: recursive ufs_fault");
5317c478bd9Sstevel@tonic-gate } else {
53266c9f83dSowenr /*
53366c9f83dSowenr * Must check if we actually still own the lock and
53466c9f83dSowenr * if so then release the lock and move on with life.
53566c9f83dSowenr */
53666c9f83dSowenr if (mutex_owner(&ufs_fix.uq_mutex) == curthread)
5377c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate new = init_failure(vp, fmt, adx);
5417c478bd9Sstevel@tonic-gate if (new != NULL) {
5427c478bd9Sstevel@tonic-gate queue_failure(new);
5437c478bd9Sstevel@tonic-gate break;
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate real_panic_v(new, fmt, adx);
5467c478bd9Sstevel@tonic-gate break;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate MINOR(("] "));
5507c478bd9Sstevel@tonic-gate return (err);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate * triage()
5557c478bd9Sstevel@tonic-gate *
5567c478bd9Sstevel@tonic-gate * Attempt to fix iff:
5577c478bd9Sstevel@tonic-gate * - the system is not already panicking
5587c478bd9Sstevel@tonic-gate * - this file system isn't explicitly marked not to be fixed
5597c478bd9Sstevel@tonic-gate * - we can connect to the user-level daemon
5607c478bd9Sstevel@tonic-gate * These conditions are detectable later, but if we can determine
5617c478bd9Sstevel@tonic-gate * them in the failing threads context the core dump may be more
5627c478bd9Sstevel@tonic-gate * useful.
5637c478bd9Sstevel@tonic-gate *
5647c478bd9Sstevel@tonic-gate */
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate static triage_t
triage(vnode_t * vp)5677c478bd9Sstevel@tonic-gate triage(vnode_t *vp)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate struct inode *ip;
5707c478bd9Sstevel@tonic-gate int need_unlock_vfs;
5717c478bd9Sstevel@tonic-gate int fs_flags;
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate MINUTE(("[triage"));
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate if (panicstr) {
5767c478bd9Sstevel@tonic-gate MINUTE((
5777c478bd9Sstevel@tonic-gate ": already panicking: \"%s\" => TRIAGE_DEAD]\n", panicstr));
5787c478bd9Sstevel@tonic-gate return (TRIAGE_DEAD);
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs) {
5827c478bd9Sstevel@tonic-gate MINUTE((
5837c478bd9Sstevel@tonic-gate ": vp, ip or ufsvfs is NULL; can't determine fs => TRIAGE_DEAD]\n"));
5847c478bd9Sstevel@tonic-gate return (TRIAGE_DEAD);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate /* use tryenter and continue no matter what since we're panicky */
5887c478bd9Sstevel@tonic-gate need_unlock_vfs = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
5897c478bd9Sstevel@tonic-gate if (need_unlock_vfs)
5907c478bd9Sstevel@tonic-gate need_unlock_vfs = mutex_tryenter(&ip->i_ufsvfs->vfs_lock);
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate fs_flags = ip->i_ufsvfs->vfs_fsfx.fx_flags;
5937c478bd9Sstevel@tonic-gate if (need_unlock_vfs)
5947c478bd9Sstevel@tonic-gate mutex_exit(&ip->i_ufsvfs->vfs_lock);
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate if (fs_flags & UFSFX_PANIC) {
5977c478bd9Sstevel@tonic-gate MINUTE((
5987c478bd9Sstevel@tonic-gate ": filesystem marked \"panic\" => TRIAGE_NO_SPIRIT]\n"));
5997c478bd9Sstevel@tonic-gate return (TRIAGE_NO_SPIRIT);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate if (ufs_checkaccton(vp) != 0) {
6037c478bd9Sstevel@tonic-gate MINUTE((
6047c478bd9Sstevel@tonic-gate ": filesystem would deadlock (accounting) => TRIAGE_DEAD]\n"));
6057c478bd9Sstevel@tonic-gate return (TRIAGE_DEAD);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate if (ufs_checkswapon(vp) != 0) {
6097c478bd9Sstevel@tonic-gate MINUTE((
6107c478bd9Sstevel@tonic-gate ": filesystem would deadlock (swapping) => TRIAGE_DEAD]\n"));
6117c478bd9Sstevel@tonic-gate return (TRIAGE_DEAD);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate MINUTE((": return TRIAGE_ATTEND_TO] "));
6157c478bd9Sstevel@tonic-gate return (TRIAGE_ATTEND_TO);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate * init failure
6207c478bd9Sstevel@tonic-gate *
6217c478bd9Sstevel@tonic-gate * This routine allocates a failure struct and initializes
6227c478bd9Sstevel@tonic-gate * it's member elements.
6237c478bd9Sstevel@tonic-gate * Space is allocated for copies of dynamic identifying fs structures
6247c478bd9Sstevel@tonic-gate * passed in. Without a much more segmented kernel architecture
6257c478bd9Sstevel@tonic-gate * this is as protected as we can make it (for now.)
6267c478bd9Sstevel@tonic-gate */
6277c478bd9Sstevel@tonic-gate static ufs_failure_t *
init_failure(vnode_t * vp,char * fmt,va_list adx)6287c478bd9Sstevel@tonic-gate init_failure(vnode_t *vp, char *fmt, va_list adx)
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate ufs_failure_t *new;
6317c478bd9Sstevel@tonic-gate struct inode *ip;
6327c478bd9Sstevel@tonic-gate int initialization_worked = 0;
6337c478bd9Sstevel@tonic-gate int need_vfs_unlock;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate MINOR(("[init_failure"));
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate new = kmem_zalloc(sizeof (ufs_failure_t), KM_NOSLEEP);
6387c478bd9Sstevel@tonic-gate if (!new) {
6397c478bd9Sstevel@tonic-gate MINOR((": kmem_zalloc failed]\n"));
6407c478bd9Sstevel@tonic-gate return (NULL);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * enough information to make a fix attempt possible?
6457c478bd9Sstevel@tonic-gate */
6467c478bd9Sstevel@tonic-gate if (!vp || !(ip = VTOI(vp)) || !ip->i_ufsvfs || !vp->v_vfsp ||
6477c478bd9Sstevel@tonic-gate !ip->i_ufsvfs->vfs_bufp || !ITOF(ip) || !fmt)
6487c478bd9Sstevel@tonic-gate goto errout;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate if (vp->v_type != VREG && vp->v_type != VDIR &&
6517c478bd9Sstevel@tonic-gate vp->v_type != VBLK && vp->v_type != VCHR &&
6527c478bd9Sstevel@tonic-gate vp->v_type != VLNK && vp->v_type != VFIFO &&
6537c478bd9Sstevel@tonic-gate vp->v_type != VSOCK)
6547c478bd9Sstevel@tonic-gate goto errout;
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs->vfs_root->v_type != VREG &&
6577c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VDIR &&
6587c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VBLK &&
6597c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VCHR &&
6607c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VLNK &&
6617c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VFIFO &&
6627c478bd9Sstevel@tonic-gate ip->i_ufsvfs->vfs_root->v_type != VSOCK)
6637c478bd9Sstevel@tonic-gate goto errout;
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate if ((ITOF(ip)->fs_magic != FS_MAGIC) &&
6667c478bd9Sstevel@tonic-gate (ITOF(ip)->fs_magic != MTB_UFS_MAGIC))
6677c478bd9Sstevel@tonic-gate goto errout;
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate /* intialize values */
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate (void) vsnprintf(new->uf_panic_str, LOCKFS_MAXCOMMENTLEN - 1, fmt, adx);
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate new->uf_ufsvfsp = ip->i_ufsvfs;
6747c478bd9Sstevel@tonic-gate new->uf_vfsp = ip->i_vfs;
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate mutex_init(&new->uf_mutex, NULL, MUTEX_DEFAULT, NULL);
6777c478bd9Sstevel@tonic-gate need_vfs_unlock = !MUTEX_HELD(&ip->i_ufsvfs->vfs_lock);
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate if (need_vfs_unlock) {
6807c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&ip->i_ufsvfs->vfs_lock)) {
6817c478bd9Sstevel@tonic-gate /*
6827c478bd9Sstevel@tonic-gate * not much alternative here, but we're panicking
6837c478bd9Sstevel@tonic-gate * already, it couldn't be worse - so just
6847c478bd9Sstevel@tonic-gate * proceed optimistically and take note.
6857c478bd9Sstevel@tonic-gate */
6867c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
6877c478bd9Sstevel@tonic-gate uf_stats.ufst_lock_violations++;
6887c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
6897c478bd9Sstevel@tonic-gate MINOR((": couldn't get vfs lock"))
6907c478bd9Sstevel@tonic-gate need_vfs_unlock = 0;
6917c478bd9Sstevel@tonic-gate }
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate if (mutex_tryenter(&new->uf_mutex)) {
6957c478bd9Sstevel@tonic-gate initialization_worked = set_state(new, UF_INIT);
6967c478bd9Sstevel@tonic-gate mutex_exit(&new->uf_mutex);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate if (need_vfs_unlock)
7007c478bd9Sstevel@tonic-gate mutex_exit(&ip->i_ufsvfs->vfs_lock);
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate if (initialization_worked) {
7037c478bd9Sstevel@tonic-gate MINOR(("] "));
7047c478bd9Sstevel@tonic-gate return (new);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate errout:
7097c478bd9Sstevel@tonic-gate if (new)
7107c478bd9Sstevel@tonic-gate kmem_free(new, sizeof (ufs_failure_t));
7117c478bd9Sstevel@tonic-gate MINOR((": failed]\n"));
7127c478bd9Sstevel@tonic-gate return (NULL);
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate static void
queue_failure(ufs_failure_t * new)7167c478bd9Sstevel@tonic-gate queue_failure(ufs_failure_t *new)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate MINOR(("[queue_failure"));
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate if (ufs_fix.uq_ufhead)
7237c478bd9Sstevel@tonic-gate insque(new, &ufs_fix.uq_ufhead);
7247c478bd9Sstevel@tonic-gate else
7257c478bd9Sstevel@tonic-gate ufs_fix.uq_ufhead = new;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate if (mutex_tryenter(&new->uf_mutex)) {
7287c478bd9Sstevel@tonic-gate (void) set_state(new, UF_QUEUE);
7297c478bd9Sstevel@tonic-gate mutex_exit(&new->uf_mutex);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex); /* force wakeup */
7337c478bd9Sstevel@tonic-gate ufs_fix.uq_ne = ufs_fix.uq_lowat = uf_stats.ufst_num_failed;
7347c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate cv_broadcast(&ufs_fix.uq_cv);
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate DCALL(DBGLVL_MAJOR, cmn_err(CE_WARN, new->uf_panic_str ?
73980d34432Sfrankho new->uf_panic_str : "queue_failure: NULL panic str?"));
7407c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate MINOR(("] "));
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
7467c478bd9Sstevel@tonic-gate static void
real_panic(ufs_failure_t * f,const char * fmt,...)7477c478bd9Sstevel@tonic-gate real_panic(ufs_failure_t *f, const char *fmt, ...)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate va_list adx;
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate MINUTE(("[real_panic "));
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate va_start(adx, fmt);
7547c478bd9Sstevel@tonic-gate real_panic_v(f, fmt, adx);
7557c478bd9Sstevel@tonic-gate va_end(adx);
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate MINUTE((": return?!]\n"));
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate static void
real_panic_v(ufs_failure_t * f,const char * fmt,va_list adx)7617c478bd9Sstevel@tonic-gate real_panic_v(ufs_failure_t *f, const char *fmt, va_list adx)
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate int seriousness = CE_PANIC;
7647c478bd9Sstevel@tonic-gate int need_unlock;
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate MINUTE(("[real_panic_v "));
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate if (f && f->uf_ufsvfsp)
7697c478bd9Sstevel@tonic-gate TRANS_SETERROR(f->uf_ufsvfsp);
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate #if defined(DEBUG)
7727c478bd9Sstevel@tonic-gate if (DEBUG_FLAGS & DBGFLG_NOPANIC) {
7737c478bd9Sstevel@tonic-gate seriousness = CE_WARN;
7747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "real_panic: EWOULDPANIC\n");
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate delay(hz >> 1); /* allow previous warnings to get out */
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate if (!f && fmt)
7817c478bd9Sstevel@tonic-gate vcmn_err(seriousness, fmt, adx);
7827c478bd9Sstevel@tonic-gate else
7837c478bd9Sstevel@tonic-gate cmn_err(seriousness, f && f->uf_panic_str? f->uf_panic_str:
7847c478bd9Sstevel@tonic-gate "real_panic: <unknown panic?>");
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate if (f) {
7877c478bd9Sstevel@tonic-gate need_unlock = !MUTEX_HELD(&f->uf_mutex);
7887c478bd9Sstevel@tonic-gate if (need_unlock) {
7897c478bd9Sstevel@tonic-gate mutex_enter(&f->uf_mutex);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate f->uf_retry = -1;
7937c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate if (need_unlock) {
7967c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate MINUTE((": return?!]\n"));
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate * initializes ufs panic structs, locks, etc
8047c478bd9Sstevel@tonic-gate */
8057c478bd9Sstevel@tonic-gate void
ufsfx_init(void)8067c478bd9Sstevel@tonic-gate ufsfx_init(void)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_init"));
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate /* patchable; unchanged while running, so no lock is needed */
8127c478bd9Sstevel@tonic-gate ufsfx_tune.uft_too_long = UF_TOO_LONG;
8137c478bd9Sstevel@tonic-gate ufsfx_tune.uft_fixstart_period = UF_FIXSTART_PERIOD;
8147c478bd9Sstevel@tonic-gate ufsfx_tune.uft_fixpoll_period = UF_FIXPOLL_PERIOD;
8157c478bd9Sstevel@tonic-gate ufsfx_tune.uft_short_err_period = UF_SHORT_ERROR_PERIOD;
8167c478bd9Sstevel@tonic-gate ufsfx_tune.uft_long_err_period = UF_LONG_ERROR_PERIOD;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate uffsinfo.ufi_statp = &uf_stats;
8197c478bd9Sstevel@tonic-gate uffsinfo.ufi_tunep = &ufsfx_tune;
8207c478bd9Sstevel@tonic-gate uffsinfo.ufi_statetab = &state_desc[0];
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate mutex_init(&uf_stats.ufst_mutex, NULL, MUTEX_DEFAULT, NULL);
8237c478bd9Sstevel@tonic-gate ufs_thread_init(&ufs_fix, /* maxne */ 1);
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate MINUTE(("] "));
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate
8287c478bd9Sstevel@tonic-gate /*
8297c478bd9Sstevel@tonic-gate * initializes per-ufs values
8307c478bd9Sstevel@tonic-gate * returns 0 (ok) or errno
8317c478bd9Sstevel@tonic-gate */
8327c478bd9Sstevel@tonic-gate int
ufsfx_mount(struct ufsvfs * ufsvfsp,int flags)8337c478bd9Sstevel@tonic-gate ufsfx_mount(struct ufsvfs *ufsvfsp, int flags)
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_mount (%d)", flags));
8367c478bd9Sstevel@tonic-gate /* don't check/need vfs_lock because it's still being initialized */
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate ufsvfsp->vfs_fsfx.fx_flags = (flags & UFSMNT_ONERROR_FLGMASK) >> 4;
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate MINUTE((": %s: fx_flags:%ld,",
8417c478bd9Sstevel@tonic-gate ufsvfsp->vfs_fs->fs_fsmnt, ufsvfsp->vfs_fsfx.fx_flags));
8427c478bd9Sstevel@tonic-gate /*
8437c478bd9Sstevel@tonic-gate * onerror={panic ^ lock only ^ unmount}
8447c478bd9Sstevel@tonic-gate */
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_PANIC) {
8477c478bd9Sstevel@tonic-gate MINUTE((" PANIC"));
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate } else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKONLY) {
8507c478bd9Sstevel@tonic-gate MINUTE((" LCKONLY"));
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate } else if (ufsvfsp->vfs_fsfx.fx_flags & UFSFX_LCKUMOUNT) {
8537c478bd9Sstevel@tonic-gate MINUTE((" LCKUMOUNT"));
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate } else {
8567c478bd9Sstevel@tonic-gate ufsvfsp->vfs_fsfx.fx_flags = UFSFX_DEFAULT;
8577c478bd9Sstevel@tonic-gate ASSERT(ufsvfsp->vfs_fsfx.fx_flags &
8587c478bd9Sstevel@tonic-gate (UFSMNT_ONERROR_FLGMASK >> 4));
8597c478bd9Sstevel@tonic-gate MINUTE((" DEFAULT"));
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate pollwakeup(&ufs_pollhd, POLLPRI);
8637c478bd9Sstevel@tonic-gate MINUTE(("]\n"));
8647c478bd9Sstevel@tonic-gate return (0);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate /*
8687c478bd9Sstevel@tonic-gate * ufsfx_unmount
8697c478bd9Sstevel@tonic-gate *
8707c478bd9Sstevel@tonic-gate * called during unmount
8717c478bd9Sstevel@tonic-gate */
8727c478bd9Sstevel@tonic-gate void
ufsfx_unmount(struct ufsvfs * ufsvfsp)8737c478bd9Sstevel@tonic-gate ufsfx_unmount(struct ufsvfs *ufsvfsp)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate ufs_failure_t *f;
8767c478bd9Sstevel@tonic-gate int must_unlock_list;
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_unmount"));
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate if (!ufsvfsp) {
8817c478bd9Sstevel@tonic-gate MINUTE((": no ufsvfsp]"));
8827c478bd9Sstevel@tonic-gate return;
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate if ((must_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex)) != 0)
8867c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
8897c478bd9Sstevel@tonic-gate int must_unlock_failure;
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate must_unlock_failure = !MUTEX_HELD(&f->uf_mutex);
8927c478bd9Sstevel@tonic-gate if (must_unlock_failure) {
8937c478bd9Sstevel@tonic-gate mutex_enter(&f->uf_mutex);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate if (f->uf_ufsvfsp == ufsvfsp) {
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate * if we owned the failure record lock, then this
9007c478bd9Sstevel@tonic-gate * is probably a fix failure-triggered unmount, so
9017c478bd9Sstevel@tonic-gate * the warning is not appropriate or needed
9027c478bd9Sstevel@tonic-gate */
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* XXX if rebooting don't print this? */
9057c478bd9Sstevel@tonic-gate if (!terminal_state(f->uf_s) && must_unlock_failure) {
9067c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
9077c478bd9Sstevel@tonic-gate "Unmounting %s while error-locked",
9087c478bd9Sstevel@tonic-gate fs_name(f));
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate f->uf_ufsvfsp = NULL;
9127c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp = NULL;
9137c478bd9Sstevel@tonic-gate f->uf_vfs_lockp = NULL;
9147c478bd9Sstevel@tonic-gate f->uf_bp = NULL;
9157c478bd9Sstevel@tonic-gate f->uf_vfsp = NULL;
9167c478bd9Sstevel@tonic-gate f->uf_retry = -1;
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate if (must_unlock_failure)
9207c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate if (must_unlock_list)
9237c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate pollwakeup(&ufs_pollhd, POLLPRI | POLLHUP);
9267c478bd9Sstevel@tonic-gate MINUTE(("] "));
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate * ufsfx_(un)lockfs
9317c478bd9Sstevel@tonic-gate *
9327c478bd9Sstevel@tonic-gate * provides hook from lockfs code so we can recognize unlock/relock
9337c478bd9Sstevel@tonic-gate * This is called after it is certain that the (un)lock will succeed.
9347c478bd9Sstevel@tonic-gate */
9357c478bd9Sstevel@tonic-gate void
ufsfx_unlockfs(struct ufsvfs * ufsvfsp)9367c478bd9Sstevel@tonic-gate ufsfx_unlockfs(struct ufsvfs *ufsvfsp)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate ufs_failure_t *f;
9397c478bd9Sstevel@tonic-gate int need_unlock;
9407c478bd9Sstevel@tonic-gate int need_unlock_list;
9417c478bd9Sstevel@tonic-gate int informed = 0;
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_unlockfs"));
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate if (!ufsvfsp)
9467c478bd9Sstevel@tonic-gate return;
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate if (need_unlock_list)
9517c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate need_unlock = !MUTEX_HELD(&f->uf_mutex);
9567c478bd9Sstevel@tonic-gate if (need_unlock)
9577c478bd9Sstevel@tonic-gate mutex_enter(&f->uf_mutex);
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s)) {
9607c478bd9Sstevel@tonic-gate if (!(f->uf_s & UF_FIXING)) {
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate * This might happen if we don't notice that
9637c478bd9Sstevel@tonic-gate * the fs gets marked FSFIX before it is
9647c478bd9Sstevel@tonic-gate * marked FSCLEAN, as might occur if the
9657c478bd9Sstevel@tonic-gate * the superblock was hammered directly.
9667c478bd9Sstevel@tonic-gate */
9677c478bd9Sstevel@tonic-gate if (!informed) {
9687c478bd9Sstevel@tonic-gate informed = 1;
9697c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
97080d34432Sfrankho "Unlock of %s succeeded before "
97180d34432Sfrankho "fs_clean marked FSFIX?",
9727c478bd9Sstevel@tonic-gate fs_name(f));
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate * pass through fixing state so
9777c478bd9Sstevel@tonic-gate * transition protocol is satisfied
9787c478bd9Sstevel@tonic-gate */
9797c478bd9Sstevel@tonic-gate if (!set_state(f, UF_FIXING)) {
9807c478bd9Sstevel@tonic-gate MINUTE((": failed] "));
9817c478bd9Sstevel@tonic-gate }
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate if (!set_state(f, UF_FIXED)) {
9857c478bd9Sstevel@tonic-gate /* it's already fixed, so don't panic now */
9867c478bd9Sstevel@tonic-gate MINUTE((": failed] "));
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate if (need_unlock)
9917c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate if (need_unlock_list)
9947c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
9957c478bd9Sstevel@tonic-gate MINUTE(("] "));
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate void
ufsfx_lockfs(struct ufsvfs * ufsvfsp)9997c478bd9Sstevel@tonic-gate ufsfx_lockfs(struct ufsvfs *ufsvfsp)
10007c478bd9Sstevel@tonic-gate {
10017c478bd9Sstevel@tonic-gate ufs_failure_t *f;
10027c478bd9Sstevel@tonic-gate int need_unlock;
10037c478bd9Sstevel@tonic-gate int need_unlock_list;
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_lockfs"));
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate if (!ufsvfsp)
10087c478bd9Sstevel@tonic-gate return;
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate need_unlock_list = !MUTEX_HELD(&ufs_fix.uq_mutex);
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate if (need_unlock_list)
10137c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
10147c478bd9Sstevel@tonic-gate
10157c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
10167c478bd9Sstevel@tonic-gate
10177c478bd9Sstevel@tonic-gate need_unlock = !MUTEX_HELD(&f->uf_mutex);
10187c478bd9Sstevel@tonic-gate if (need_unlock)
10197c478bd9Sstevel@tonic-gate mutex_enter(&f->uf_mutex);
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate if (f->uf_ufsvfsp == ufsvfsp && !terminal_state(f->uf_s) &&
10227c478bd9Sstevel@tonic-gate f->uf_s != UF_PANIC) {
10237c478bd9Sstevel@tonic-gate switch (f->uf_s) {
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate default:
10267c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
102780d34432Sfrankho "fs %s not in state "
102880d34432Sfrankho "UF_TRYLCK, UF_LOCKED or UF_FIXING",
10297c478bd9Sstevel@tonic-gate fs_name(f));
10307c478bd9Sstevel@tonic-gate break;
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate case UF_TRYLCK:
10337c478bd9Sstevel@tonic-gate if (!set_state(f, UF_LOCKED)) {
10347c478bd9Sstevel@tonic-gate MINUTE((": failed] "));
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate break;
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate case UF_LOCKED:
10397c478bd9Sstevel@tonic-gate if (!set_state(f, UF_FIXING)) {
10407c478bd9Sstevel@tonic-gate MINUTE((": failed] "));
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate break;
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate case UF_FIXING:
10457c478bd9Sstevel@tonic-gate break;
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate if (need_unlock)
10517c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate if (need_unlock_list)
10547c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate MINUTE(("] "));
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate /*
10607c478bd9Sstevel@tonic-gate * error lock, trigger fsck and unlock those fs with failures
10617c478bd9Sstevel@tonic-gate * blatantly copied from the hlock routine, although this routine
10627c478bd9Sstevel@tonic-gate * triggers differently in order to use uq_ne as meaningful data.
10637c478bd9Sstevel@tonic-gate */
10647c478bd9Sstevel@tonic-gate /* ARGSUSED */
10657c478bd9Sstevel@tonic-gate void
ufsfx_thread_fix_failures(void * ignored)10667c478bd9Sstevel@tonic-gate ufsfx_thread_fix_failures(void *ignored)
10677c478bd9Sstevel@tonic-gate {
10687c478bd9Sstevel@tonic-gate int retry;
10697c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo;
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &ufs_fix.uq_mutex, callb_generic_cpr,
10727c478bd9Sstevel@tonic-gate "ufsfixfail");
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_thread_fix_failures] "));
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate for (;;) {
10777c478bd9Sstevel@tonic-gate /* sleep until there is work to do */
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
10807c478bd9Sstevel@tonic-gate (void) ufs_thread_run(&ufs_fix, &cprinfo);
10817c478bd9Sstevel@tonic-gate ufs_fix.uq_ne = 0;
10827c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate /* process failures on our q */
10857c478bd9Sstevel@tonic-gate do {
10867c478bd9Sstevel@tonic-gate retry = ufsfx_do_failure_q();
10877c478bd9Sstevel@tonic-gate if (retry) {
10887c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
10897c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo);
1090*d3d50737SRafael Vanoni (void) cv_reltimedwait(&ufs_fix.uq_cv,
1091*d3d50737SRafael Vanoni &ufs_fix.uq_mutex, (hz * retry),
1092*d3d50737SRafael Vanoni TR_CLOCK_TICK);
10937c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo,
10947c478bd9Sstevel@tonic-gate &ufs_fix.uq_mutex);
10957c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate } while (retry);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate /* NOTREACHED */
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate /*
11047c478bd9Sstevel@tonic-gate * watch for fix-on-panic work
11057c478bd9Sstevel@tonic-gate *
11067c478bd9Sstevel@tonic-gate * returns # of seconds to sleep before trying again
11077c478bd9Sstevel@tonic-gate * and zero if no retry is needed
11087c478bd9Sstevel@tonic-gate */
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate int
ufsfx_do_failure_q(void)11117c478bd9Sstevel@tonic-gate ufsfx_do_failure_q(void)
11127c478bd9Sstevel@tonic-gate {
11137c478bd9Sstevel@tonic-gate ufs_failure_t *f;
11147c478bd9Sstevel@tonic-gate long retry = 1;
11157c478bd9Sstevel@tonic-gate ufsd_t *s;
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate MAJOR(("[ufsfx_do_failure_q"));
11187c478bd9Sstevel@tonic-gate DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&ufs_fix.uq_mutex))
11217c478bd9Sstevel@tonic-gate return (retry);
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate retry = 0;
11247c478bd9Sstevel@tonic-gate rescan_q:
11257c478bd9Sstevel@tonic-gate
11267c478bd9Sstevel@tonic-gate /*
11277c478bd9Sstevel@tonic-gate * walk down failure list
11287c478bd9Sstevel@tonic-gate * depending on state of each failure, do whatever
11297c478bd9Sstevel@tonic-gate * is appropriate to move it to the next state
11307c478bd9Sstevel@tonic-gate * taking note of whether retry gets set
11317c478bd9Sstevel@tonic-gate *
11327c478bd9Sstevel@tonic-gate * retry protocol:
11337c478bd9Sstevel@tonic-gate * wakeup in shortest required time for any failure
11347c478bd9Sstevel@tonic-gate * retry == 0; nothing more to do (terminal state)
11357c478bd9Sstevel@tonic-gate * retry < 0; reprocess queue immediately, retry will
11367c478bd9Sstevel@tonic-gate * be abs(retry) for the next cycle
11377c478bd9Sstevel@tonic-gate * retry > 0; schedule wakeup for retry seconds
11387c478bd9Sstevel@tonic-gate */
11397c478bd9Sstevel@tonic-gate
11407c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&f->uf_mutex)) {
11437c478bd9Sstevel@tonic-gate retry = 1;
11447c478bd9Sstevel@tonic-gate continue;
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate s = get_state_desc(f->uf_s);
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate MINOR((": found%s: %s, \"%s: %s\"\n",
11497c478bd9Sstevel@tonic-gate s->ud_attr.terminal ? " old" : "",
11507c478bd9Sstevel@tonic-gate fs_name(f), state_name(f->uf_s), f->uf_panic_str));
11517c478bd9Sstevel@tonic-gate
11527c478bd9Sstevel@tonic-gate if (s->ud_attr.terminal) {
11537c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
11547c478bd9Sstevel@tonic-gate continue;
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate if (s->ud_sfp)
11587c478bd9Sstevel@tonic-gate (*s->ud_sfp)(f, UFA_FOUND, f->uf_s);
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate ASSERT(terminal_state(f->uf_s) || f->uf_retry != 0);
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gate if (f->uf_retry != 0) {
11637c478bd9Sstevel@tonic-gate if (retry > f->uf_retry || retry == 0)
11647c478bd9Sstevel@tonic-gate retry = f->uf_retry;
11657c478bd9Sstevel@tonic-gate if (f->uf_retry < 0)
11667c478bd9Sstevel@tonic-gate f->uf_retry = abs(f->uf_retry);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate if (retry < 0) {
11737c478bd9Sstevel@tonic-gate retry = abs(retry);
11747c478bd9Sstevel@tonic-gate goto rescan_q;
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate DCALL(DBGLVL_HIDEOUS, dump_uf_list(NULL));
11807c478bd9Sstevel@tonic-gate MAJOR((": retry=%ld, good night]\n\n", retry));
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate return (retry);
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate static void
pester_msg(ufs_failure_t * f,int seriousness)11867c478bd9Sstevel@tonic-gate pester_msg(ufs_failure_t *f, int seriousness)
11877c478bd9Sstevel@tonic-gate {
11887c478bd9Sstevel@tonic-gate MINUTE(("[pester_msg"));
11897c478bd9Sstevel@tonic-gate ASSERT(f->uf_s & (UF_LOCKED | UF_FIXING));
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate /*
11927c478bd9Sstevel@tonic-gate * XXX if seems too long for this fs, poke administrator
11937c478bd9Sstevel@tonic-gate * XXX to run fsck manually (and change retry time?)
11947c478bd9Sstevel@tonic-gate */
119580d34432Sfrankho cmn_err(seriousness, "Waiting for repair of %s to %s",
119680d34432Sfrankho fs_name(f), f->uf_s & UF_LOCKED ? "start" : "finish");
11977c478bd9Sstevel@tonic-gate MINUTE(("]"));
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate
12007c478bd9Sstevel@tonic-gate static time_t
trylock_time_exceeded(ufs_failure_t * f)12017c478bd9Sstevel@tonic-gate trylock_time_exceeded(ufs_failure_t *f)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate time_t toolong;
12047c478bd9Sstevel@tonic-gate extern time_t time;
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate MINUTE(("[trylock_time_exceeded"));
12077c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate toolong = (time_t)ufsfx_tune.uft_too_long + f->uf_entered_tm;
12107c478bd9Sstevel@tonic-gate if (time > toolong)
12117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "error-lock timeout exceeded: %s", fs_name(f));
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate MINUTE(("] "));
12147c478bd9Sstevel@tonic-gate return (time <= toolong? 0: time - toolong);
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate static int
get_lockfs_status(ufs_failure_t * f,struct lockfs * lfp)12187c478bd9Sstevel@tonic-gate get_lockfs_status(ufs_failure_t *f, struct lockfs *lfp)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate MINUTE(("[get_lockfs_status"));
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
12237c478bd9Sstevel@tonic-gate MINUTE((": ufsvfsp is NULL]\n"));
12247c478bd9Sstevel@tonic-gate return (0);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
12287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
12297c478bd9Sstevel@tonic-gate ASSERT(!vfs_lock_held(f->uf_vfsp));
12307c478bd9Sstevel@tonic-gate ASSERT(f->uf_ufsvfsp->vfs_root != NULL);
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate f->uf_lf_err = ufs_fiolfss(f->uf_ufsvfsp->vfs_root, lfp);
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate if (f->uf_lf_err) {
12357c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_short_err_period;
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate MINUTE(("] "));
12397c478bd9Sstevel@tonic-gate return (1);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate static sfrc_t
set_state(ufs_failure_t * f,ufs_failure_states_t new_state)12437c478bd9Sstevel@tonic-gate set_state(ufs_failure_t *f, ufs_failure_states_t new_state)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate ufsd_t *s;
12467c478bd9Sstevel@tonic-gate sfrc_t sfrc = SFRC_FAIL;
12477c478bd9Sstevel@tonic-gate int need_unlock;
12487c478bd9Sstevel@tonic-gate extern time_t time;
12497c478bd9Sstevel@tonic-gate
12507c478bd9Sstevel@tonic-gate HIDEOUS(("[set_state: new state:%s", state_name(new_state)));
12517c478bd9Sstevel@tonic-gate ASSERT(f);
12527c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate /*
12557c478bd9Sstevel@tonic-gate * if someone else is panicking, just let panic sync proceed
12567c478bd9Sstevel@tonic-gate */
12577c478bd9Sstevel@tonic-gate if (panicstr) {
12587c478bd9Sstevel@tonic-gate (void) set_state(f, UF_NOTFIX);
12597c478bd9Sstevel@tonic-gate HIDEOUS((": state reset: not fixed] "));
12607c478bd9Sstevel@tonic-gate return (sfrc);
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate /*
12647c478bd9Sstevel@tonic-gate * bad state transition, an internal error
12657c478bd9Sstevel@tonic-gate */
12667c478bd9Sstevel@tonic-gate if (!state_trans_valid(f->uf_s, new_state)) {
12677c478bd9Sstevel@tonic-gate /* recursion */
12687c478bd9Sstevel@tonic-gate if (!(f->uf_s & UF_PANIC) && !(new_state & UF_PANIC))
12697c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
12707c478bd9Sstevel@tonic-gate MINOR((": state reset: transition failure (\"%s\"->\"%s\")] ",
12717c478bd9Sstevel@tonic-gate state_name(f->uf_s), state_name(new_state)));
12727c478bd9Sstevel@tonic-gate return (sfrc);
12737c478bd9Sstevel@tonic-gate }
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate s = get_state_desc(new_state);
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate need_unlock = !MUTEX_HELD(&ufs_fix.uq_mutex);
12787c478bd9Sstevel@tonic-gate if (need_unlock)
12797c478bd9Sstevel@tonic-gate mutex_enter(&ufs_fix.uq_mutex);
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate if (s->ud_attr.at_fail && ufs_fix.uq_threadp &&
12827c478bd9Sstevel@tonic-gate curthread == ufs_fix.uq_threadp) {
12837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "set_state: probable recursive panic of %s",
12847c478bd9Sstevel@tonic-gate fs_name(f));
12857c478bd9Sstevel@tonic-gate }
12867c478bd9Sstevel@tonic-gate if (need_unlock)
12877c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate /* NULL state functions always succeed */
12907c478bd9Sstevel@tonic-gate sfrc = !s->ud_sfp? SFRC_SUCCESS: (*s->ud_sfp)(f, UFA_SET, new_state);
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate if (sfrc == SFRC_SUCCESS && f->uf_s != new_state) {
12937c478bd9Sstevel@tonic-gate f->uf_s = new_state;
12947c478bd9Sstevel@tonic-gate f->uf_entered_tm = time;
12957c478bd9Sstevel@tonic-gate f->uf_counter = 0;
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate
12987c478bd9Sstevel@tonic-gate HIDEOUS(("]\n"));
12997c478bd9Sstevel@tonic-gate return (sfrc);
13007c478bd9Sstevel@tonic-gate }
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate static ufsd_t *
get_state_desc(ufs_failure_states_t state)13037c478bd9Sstevel@tonic-gate get_state_desc(ufs_failure_states_t state)
13047c478bd9Sstevel@tonic-gate {
13057c478bd9Sstevel@tonic-gate ufsd_t *s;
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate HIDEOUS(("[get_state_desc"));
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate for (s = &state_desc[1]; s->ud_name != NULL; s++) {
13107c478bd9Sstevel@tonic-gate if (s->ud_v == state) {
13117c478bd9Sstevel@tonic-gate HIDEOUS(("] "));
13127c478bd9Sstevel@tonic-gate return (s);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate HIDEOUS(("] "));
13177c478bd9Sstevel@tonic-gate return (&state_desc[0]); /* default */
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate static sfrc_t
sf_undef(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)13217c478bd9Sstevel@tonic-gate sf_undef(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
13227c478bd9Sstevel@tonic-gate {
13237c478bd9Sstevel@tonic-gate sfrc_t rc;
13247c478bd9Sstevel@tonic-gate
13257c478bd9Sstevel@tonic-gate TRIVIA(("[sf_undef, action is %s, state is %s\n",
13267c478bd9Sstevel@tonic-gate act_name(a), state_name(s)));
13277c478bd9Sstevel@tonic-gate ASSERT(s == UF_UNDEF);
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate /* shouldn't find null failure records or ever set one */
13307c478bd9Sstevel@tonic-gate rc = set_state(f, UF_NOTFIX);
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate TRIVIA(("] "));
13337c478bd9Sstevel@tonic-gate return (rc);
13347c478bd9Sstevel@tonic-gate }
13357c478bd9Sstevel@tonic-gate
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate static sfrc_t
sf_init(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)13387c478bd9Sstevel@tonic-gate sf_init(
13397c478bd9Sstevel@tonic-gate ufs_failure_t *f,
13407c478bd9Sstevel@tonic-gate ufsa_t a,
13417c478bd9Sstevel@tonic-gate ufs_failure_states_t s)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
13447c478bd9Sstevel@tonic-gate extern time_t time;
13457c478bd9Sstevel@tonic-gate
13467c478bd9Sstevel@tonic-gate TRIVIA(("[sf_init, action is %s", act_name(a)));
13477c478bd9Sstevel@tonic-gate ASSERT(s & UF_INIT);
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate switch (a) {
13507c478bd9Sstevel@tonic-gate case UFA_SET:
13517c478bd9Sstevel@tonic-gate f->uf_begin_tm = time;
13527c478bd9Sstevel@tonic-gate f->uf_retry = 1;
13537c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
13547c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
13557c478bd9Sstevel@tonic-gate TRIVIA((": NULL ufsvfsp]\n"));
13567c478bd9Sstevel@tonic-gate return (rc);
13577c478bd9Sstevel@tonic-gate }
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate * because we can call panic from many different levels,
13607c478bd9Sstevel@tonic-gate * we can't be sure that we've got the vfs_lock at this
13617c478bd9Sstevel@tonic-gate * point. However, there's not much alternative and if
13627c478bd9Sstevel@tonic-gate * we don't (have the lock) the worst case is we'll just
13637c478bd9Sstevel@tonic-gate * panic again
13647c478bd9Sstevel@tonic-gate */
13657c478bd9Sstevel@tonic-gate f->uf_vfs_lockp = &f->uf_ufsvfsp->vfs_lock;
13667c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp = &f->uf_ufsvfsp->vfs_fsfx;
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp->vfs_bufp) {
13697c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
13707c478bd9Sstevel@tonic-gate TRIVIA((": NULL vfs_bufp]\n"));
13717c478bd9Sstevel@tonic-gate return (rc);
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate f->uf_bp = f->uf_ufsvfsp->vfs_bufp;
13747c478bd9Sstevel@tonic-gate
13757c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp->vfs_bufp->b_un.b_fs) {
13767c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
13777c478bd9Sstevel@tonic-gate TRIVIA((": NULL vfs_fs]\n"));
13787c478bd9Sstevel@tonic-gate return (rc);
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate /* vfs_fs = vfs_bufp->b_un.b_fs */
13827c478bd9Sstevel@tonic-gate bcopy(f->uf_ufsvfsp->vfs_fs->fs_fsmnt, f->uf_fsname, MAXMNTLEN);
13837c478bd9Sstevel@tonic-gate
13847c478bd9Sstevel@tonic-gate f->uf_lf.lf_lock = LOCKFS_ELOCK; /* primer */
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate if (!f->uf_vfsp || f->uf_vfsp->vfs_dev == NODEV) {
13877c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
13887c478bd9Sstevel@tonic-gate TRIVIA((": NULL vfsp or vfs_dev == NODEV"));
13897c478bd9Sstevel@tonic-gate return (rc);
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate f->uf_dev = f->uf_vfsp->vfs_dev;
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
13947c478bd9Sstevel@tonic-gate break;
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate case UFA_FOUND:
13977c478bd9Sstevel@tonic-gate default:
13987c478bd9Sstevel@tonic-gate /* failures marked init shouldn't even be on the queue yet */
13997c478bd9Sstevel@tonic-gate rc = set_state(f, UF_QUEUE);
14007c478bd9Sstevel@tonic-gate TRIVIA((": found failure with state init]\n"));
14017c478bd9Sstevel@tonic-gate }
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate TRIVIA(("] "));
14047c478bd9Sstevel@tonic-gate return (rc);
14057c478bd9Sstevel@tonic-gate }
14067c478bd9Sstevel@tonic-gate
14077c478bd9Sstevel@tonic-gate static sfrc_t
sf_queue(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)14087c478bd9Sstevel@tonic-gate sf_queue(
14097c478bd9Sstevel@tonic-gate ufs_failure_t *f,
14107c478bd9Sstevel@tonic-gate ufsa_t a,
14117c478bd9Sstevel@tonic-gate ufs_failure_states_t s)
14127c478bd9Sstevel@tonic-gate {
14137c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate TRIVIA(("[sf_queue, action is %s", act_name(a)));
14167c478bd9Sstevel@tonic-gate ASSERT(s & UF_QUEUE);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
14197c478bd9Sstevel@tonic-gate TRIVIA((": NULL ufsvfsp]\n"));
14207c478bd9Sstevel@tonic-gate return (rc);
14217c478bd9Sstevel@tonic-gate }
14227c478bd9Sstevel@tonic-gate
14237c478bd9Sstevel@tonic-gate switch (a) {
14247c478bd9Sstevel@tonic-gate case UFA_FOUND:
14257c478bd9Sstevel@tonic-gate rc = sf_found_queue(f);
14267c478bd9Sstevel@tonic-gate break;
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate case UFA_SET:
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
14337c478bd9Sstevel@tonic-gate uf_stats.ufst_num_failed++;
14347c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /*
14377c478bd9Sstevel@tonic-gate * if can't get the vfs lock, just wait until
14387c478bd9Sstevel@tonic-gate * UF_TRYLCK to set fx_current
14397c478bd9Sstevel@tonic-gate */
14407c478bd9Sstevel@tonic-gate if (mutex_tryenter(f->uf_vfs_lockp)) {
14417c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp->fx_current = f;
14427c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
14437c478bd9Sstevel@tonic-gate } else {
14447c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
14457c478bd9Sstevel@tonic-gate uf_stats.ufst_current_races++;
14467c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate f->uf_retry = 1;
14507c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
14517c478bd9Sstevel@tonic-gate TRIVIA(("] "));
14527c478bd9Sstevel@tonic-gate break;
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate default:
14557c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
14567c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate
14597c478bd9Sstevel@tonic-gate return (rc);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate static sfrc_t
sf_found_queue(ufs_failure_t * f)14637c478bd9Sstevel@tonic-gate sf_found_queue(ufs_failure_t *f)
14647c478bd9Sstevel@tonic-gate {
14657c478bd9Sstevel@tonic-gate int replica;
14667c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate TRIVIA(("[sf_found_queue"));
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate * don't need to check for null ufsvfsp because
14727c478bd9Sstevel@tonic-gate * unmount must own list's ufs_fix.uq_mutex
14737c478bd9Sstevel@tonic-gate * to mark it null and we own that lock since
14747c478bd9Sstevel@tonic-gate * we got here.
14757c478bd9Sstevel@tonic-gate */
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ufs_fix.uq_mutex));
14787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate if (!mutex_tryenter(f->uf_vfs_lockp)) {
14817c478bd9Sstevel@tonic-gate TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
14827c478bd9Sstevel@tonic-gate f->uf_retry = 1;
14837c478bd9Sstevel@tonic-gate return (rc);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate
14867c478bd9Sstevel@tonic-gate replica = f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current != NULL &&
14877c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp->fx_current != f &&
14887c478bd9Sstevel@tonic-gate !terminal_state(f->uf_vfs_ufsfxp->fx_current->uf_s);
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * copy general flags to this ufs_failure so we don't
14927c478bd9Sstevel@tonic-gate * need to refer back to the ufsvfs, or, more importantly,
14937c478bd9Sstevel@tonic-gate * don't need to keep acquiring (trying to acquire) vfs_lockp
14947c478bd9Sstevel@tonic-gate *
14957c478bd9Sstevel@tonic-gate * The most restrictive option wins:
14967c478bd9Sstevel@tonic-gate * panic > errlock only > errlock+unmount > repair
14977c478bd9Sstevel@tonic-gate * XXX panic > elock > elock > elock+umount
14987c478bd9Sstevel@tonic-gate */
14997c478bd9Sstevel@tonic-gate if (f->uf_vfs_ufsfxp->fx_flags & UFSFX_PANIC) {
15007c478bd9Sstevel@tonic-gate if (!set_state(f, UF_PANIC)) {
15017c478bd9Sstevel@tonic-gate TRIVIA((": marked panic but was queued?"));
15027c478bd9Sstevel@tonic-gate real_panic(f, " ");
15037c478bd9Sstevel@tonic-gate /*NOTREACHED*/
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
15067c478bd9Sstevel@tonic-gate return (rc);
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate f->uf_flags = f->uf_vfs_ufsfxp->fx_flags;
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate if (replica) {
15117c478bd9Sstevel@tonic-gate if (!set_state(f, UF_REPLICA)) {
15127c478bd9Sstevel@tonic-gate f->uf_retry = 1;
15137c478bd9Sstevel@tonic-gate TRIVIA((": set to replica failed] "));
15147c478bd9Sstevel@tonic-gate } else {
15157c478bd9Sstevel@tonic-gate TRIVIA(("] "));
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
15187c478bd9Sstevel@tonic-gate return (rc);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
15217c478bd9Sstevel@tonic-gate
15227c478bd9Sstevel@tonic-gate if (!set_state(f, UF_TRYLCK)) {
15237c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
15247c478bd9Sstevel@tonic-gate } else {
15257c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate return (rc);
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate static sfrc_t
sf_nonterm_cmn(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)15317c478bd9Sstevel@tonic-gate sf_nonterm_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
15327c478bd9Sstevel@tonic-gate {
15337c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate TRIVIA(("[sf_nonterm_cmn, action: %s, %s", act_name(a), state_name(s)));
15367c478bd9Sstevel@tonic-gate ASSERT(s & (UF_TRYLCK | UF_LOCKED | UF_UMOUNT | UF_FIXING));
15377c478bd9Sstevel@tonic-gate ASSERT(!terminal_state(s));
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp && !(f->uf_s & UF_UMOUNT)) {
15407c478bd9Sstevel@tonic-gate TRIVIA((": NULL ufsvfsp (state != UMOUNT)]\n"));
15417c478bd9Sstevel@tonic-gate (void) set_state(f, UF_NOTFIX);
15427c478bd9Sstevel@tonic-gate return (rc);
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate
15457c478bd9Sstevel@tonic-gate switch (a) {
15467c478bd9Sstevel@tonic-gate case UFA_SET:
15477c478bd9Sstevel@tonic-gate switch (s) {
15487c478bd9Sstevel@tonic-gate case UF_TRYLCK:
15497c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
15507c478bd9Sstevel@tonic-gate rc = sf_set_trylck(f);
15517c478bd9Sstevel@tonic-gate break;
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate case UF_LOCKED:
15547c478bd9Sstevel@tonic-gate rc = sf_set_locked(f);
15557c478bd9Sstevel@tonic-gate break;
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate case UF_FIXING:
15587c478bd9Sstevel@tonic-gate f->uf_flags |= UFSFX_REPAIR_START;
15597c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_fixpoll_period;
15607c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
15617c478bd9Sstevel@tonic-gate break;
15627c478bd9Sstevel@tonic-gate
15637c478bd9Sstevel@tonic-gate case UF_UMOUNT:
15647c478bd9Sstevel@tonic-gate f->uf_retry = -ufsfx_tune.uft_short_err_period;
15657c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
15667c478bd9Sstevel@tonic-gate break;
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate default:
15697c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
15707c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
15717c478bd9Sstevel@tonic-gate }
15727c478bd9Sstevel@tonic-gate break;
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate case UFA_FOUND:
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate switch (s) {
15777c478bd9Sstevel@tonic-gate case UF_TRYLCK:
15787c478bd9Sstevel@tonic-gate rc = sf_found_trylck(f);
15797c478bd9Sstevel@tonic-gate break;
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate case UF_LOCKED:
15827c478bd9Sstevel@tonic-gate case UF_FIXING:
15837c478bd9Sstevel@tonic-gate rc = sf_found_lock_fix_cmn(f, s);
15847c478bd9Sstevel@tonic-gate break;
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate case UF_UMOUNT:
15877c478bd9Sstevel@tonic-gate rc = sf_found_umount(f);
15887c478bd9Sstevel@tonic-gate break;
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate default:
15917c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
15927c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
15937c478bd9Sstevel@tonic-gate break;
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate break;
15967c478bd9Sstevel@tonic-gate default:
15977c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
15987c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
15997c478bd9Sstevel@tonic-gate break;
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate TRIVIA(("] "));
16037c478bd9Sstevel@tonic-gate return (rc);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate static sfrc_t
sf_set_trylck(ufs_failure_t * f)16077c478bd9Sstevel@tonic-gate sf_set_trylck(ufs_failure_t *f)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate TRIVIA(("[sf_set_trylck"));
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate if (!mutex_tryenter(f->uf_vfs_lockp)) {
16127c478bd9Sstevel@tonic-gate TRIVIA((": tryenter(vfslockp) failed; retry]\n"));
16137c478bd9Sstevel@tonic-gate f->uf_retry = 1;
16147c478bd9Sstevel@tonic-gate return (SFRC_FAIL);
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate if (!f->uf_vfs_ufsfxp->fx_current)
16187c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp->fx_current = f;
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
16217c478bd9Sstevel@tonic-gate
16227c478bd9Sstevel@tonic-gate f->uf_lf.lf_flags = 0;
16237c478bd9Sstevel@tonic-gate f->uf_lf.lf_lock = LOCKFS_ELOCK;
16247c478bd9Sstevel@tonic-gate f->uf_retry = -ufsfx_tune.uft_fixstart_period;
16257c478bd9Sstevel@tonic-gate TRIVIA(("] "));
16267c478bd9Sstevel@tonic-gate return (SFRC_SUCCESS);
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate static sfrc_t
sf_found_trylck(ufs_failure_t * f)16307c478bd9Sstevel@tonic-gate sf_found_trylck(ufs_failure_t *f)
16317c478bd9Sstevel@tonic-gate {
16327c478bd9Sstevel@tonic-gate struct lockfs lockfs_status;
16337c478bd9Sstevel@tonic-gate
16347c478bd9Sstevel@tonic-gate TRIVIA(("[sf_found_trylck"));
16357c478bd9Sstevel@tonic-gate
16367c478bd9Sstevel@tonic-gate if (trylock_time_exceeded(f) > 0) {
16377c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
16387c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
16397c478bd9Sstevel@tonic-gate return (SFRC_FAIL);
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate if (!get_lockfs_status(f, &lockfs_status)) {
16437c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
16447c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
16457c478bd9Sstevel@tonic-gate return (SFRC_FAIL);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate if (f->uf_lf_err == NO_ERROR)
16497c478bd9Sstevel@tonic-gate f->uf_lf.lf_key = lockfs_status.lf_key;
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate if (!set_lockfs(f, &lockfs_status)) {
16527c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
16537c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
16547c478bd9Sstevel@tonic-gate return (SFRC_FAIL);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate TRIVIA(("] "));
16577c478bd9Sstevel@tonic-gate return (SFRC_SUCCESS);
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate
16607c478bd9Sstevel@tonic-gate static sfrc_t
sf_set_locked(ufs_failure_t * f)16617c478bd9Sstevel@tonic-gate sf_set_locked(ufs_failure_t *f)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate TRIVIA(("[sf_set_locked"));
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate f->uf_retry = -ufsfx_tune.uft_fixstart_period;
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate #if defined(DEBUG)
16687c478bd9Sstevel@tonic-gate if (f->uf_flags & UFSFX_REPAIR_START)
16697c478bd9Sstevel@tonic-gate TRIVIA(("clearing UFSFX_REPAIR_START "));
16707c478bd9Sstevel@tonic-gate #endif /* DEBUG */
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate f->uf_flags &= ~UFSFX_REPAIR_START;
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate if (f->uf_s & UF_TRYLCK) {
16757c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Error-locked %s: \"%s\"",
16767c478bd9Sstevel@tonic-gate fs_name(f), f->uf_panic_str);
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate if (f->uf_flags & UFSFX_LCKONLY)
16797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Manual repair of %s required",
16807c478bd9Sstevel@tonic-gate fs_name(f));
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /*
16847c478bd9Sstevel@tonic-gate * just reset to current state
16857c478bd9Sstevel@tonic-gate */
16867c478bd9Sstevel@tonic-gate #if defined(DEBUG)
16877c478bd9Sstevel@tonic-gate TRIVIA(("locked->locked "));
16887c478bd9Sstevel@tonic-gate #endif /* DEBUG */
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate TRIVIA(("] "));
16917c478bd9Sstevel@tonic-gate return (SFRC_SUCCESS);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate static sfrc_t
sf_found_lock_fix_cmn(ufs_failure_t * f,ufs_failure_states_t s)16957c478bd9Sstevel@tonic-gate sf_found_lock_fix_cmn(ufs_failure_t *f, ufs_failure_states_t s)
16967c478bd9Sstevel@tonic-gate {
16977c478bd9Sstevel@tonic-gate time_t toolong;
16987c478bd9Sstevel@tonic-gate extern time_t time;
16997c478bd9Sstevel@tonic-gate struct buf *bp = NULL;
17007c478bd9Sstevel@tonic-gate struct fs *dfs;
17017c478bd9Sstevel@tonic-gate time_t concerned, anxious;
17027c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
17037c478bd9Sstevel@tonic-gate ulong_t gb_size;
17047c478bd9Sstevel@tonic-gate
17057c478bd9Sstevel@tonic-gate TRIVIA(("[sf_found_lock_fix_cmn (\"%s\")", state_name(s)));
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate if (s & UF_LOCKED) {
17087c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
17097c478bd9Sstevel@tonic-gate
171080d34432Sfrankho toolong =
171180d34432Sfrankho time > (ufsfx_tune.uft_too_long + f->uf_entered_tm);
17127c478bd9Sstevel@tonic-gate TRIVIA(("%stoolong", !toolong? "not": ""));
17137c478bd9Sstevel@tonic-gate HIDEOUS((": time:%ld, too long:%ld, entered_tm:%ld ",
17147c478bd9Sstevel@tonic-gate time, ufsfx_tune.uft_too_long, f->uf_entered_tm));
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate if (f->uf_flags & UFSFX_LCKUMOUNT) {
17177c478bd9Sstevel@tonic-gate if (set_state(f, UF_UMOUNT)) {
17187c478bd9Sstevel@tonic-gate TRIVIA(("] "));
17197c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
17207c478bd9Sstevel@tonic-gate } else {
17217c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
17227c478bd9Sstevel@tonic-gate f->uf_retry = 1;
17237c478bd9Sstevel@tonic-gate }
17247c478bd9Sstevel@tonic-gate return (rc);
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate if (!toolong) {
17277c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
17287c478bd9Sstevel@tonic-gate } else {
17297c478bd9Sstevel@tonic-gate if (!(f->uf_flags & UFSFX_REPAIR_START)) {
17307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s repair of %s not started.",
17317c478bd9Sstevel@tonic-gate (f->uf_flags & UFSFX_LCKONLY) ?
173280d34432Sfrankho "Manual" : "Automatic", fs_name(f));
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_long_err_period;
17357c478bd9Sstevel@tonic-gate } else {
17367c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_long_err_period;
173780d34432Sfrankho cmn_err(CE_WARN, "Repair of %s is not timely; "
173880d34432Sfrankho "operator attention is required.",
17397c478bd9Sstevel@tonic-gate fs_name(f));
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate TRIVIA(("] "));
17427c478bd9Sstevel@tonic-gate return (rc);
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate
17467c478bd9Sstevel@tonic-gate #if defined(DEBUG)
17477c478bd9Sstevel@tonic-gate else {
17487c478bd9Sstevel@tonic-gate ASSERT(s & UF_FIXING);
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate #endif /* DEBUG */
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate /*
17537c478bd9Sstevel@tonic-gate * get on disk superblock; force it to really
17547c478bd9Sstevel@tonic-gate * come from the disk
17557c478bd9Sstevel@tonic-gate */
17567c478bd9Sstevel@tonic-gate (void) bfinval(f->uf_dev, 0);
17577c478bd9Sstevel@tonic-gate bp = UFS_BREAD(f->uf_ufsvfsp, f->uf_dev, SBLOCK, SBSIZE);
17587c478bd9Sstevel@tonic-gate if (bp) {
17597c478bd9Sstevel@tonic-gate bp->b_flags |= (B_STALE | B_AGE);
17607c478bd9Sstevel@tonic-gate dfs = bp->b_un.b_fs;
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate if (!bp || (bp->b_flags & B_ERROR) || ((dfs->fs_magic != FS_MAGIC) &&
17647c478bd9Sstevel@tonic-gate (dfs->fs_magic != MTB_UFS_MAGIC))) {
17657c478bd9Sstevel@tonic-gate TRIVIA((": UFS_BREAD(SBLOCK) failed]\n"));
17667c478bd9Sstevel@tonic-gate f->uf_retry = 1;
17677c478bd9Sstevel@tonic-gate goto out;
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate
17707c478bd9Sstevel@tonic-gate /* fsck started but we haven't noticed yet? */
17717c478bd9Sstevel@tonic-gate if (!(s & UF_FIXING) && dfs->fs_clean == FSFIX) {
17727c478bd9Sstevel@tonic-gate if (!set_state(f, UF_FIXING)) {
17737c478bd9Sstevel@tonic-gate TRIVIA((": failed]\n"));
17747c478bd9Sstevel@tonic-gate f->uf_retry = 1;
17757c478bd9Sstevel@tonic-gate goto out;
17767c478bd9Sstevel@tonic-gate }
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate /* fsck started but didn't succeed? */
17807c478bd9Sstevel@tonic-gate if ((s & UF_FIXING) && ((dfs->fs_clean == FSBAD) || !fsck_active(f))) {
17817c478bd9Sstevel@tonic-gate TRIVIA((": fs_clean: %d", (int)dfs->fs_clean));
17827c478bd9Sstevel@tonic-gate (void) set_state(f, UF_LOCKED);
17837c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: Manual repair is necessary.", fs_name(f));
17847c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_long_err_period;
17857c478bd9Sstevel@tonic-gate goto out;
17867c478bd9Sstevel@tonic-gate }
17877c478bd9Sstevel@tonic-gate
17887c478bd9Sstevel@tonic-gate gb_size = (dfs->fs_size * dfs->fs_bshift) / GB;
17897c478bd9Sstevel@tonic-gate toolong = (time_t)((gb_size == 0? 1: gb_size) * SecondsPerGig);
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate /* fsck started but doesn't seem to be proceeding? */
17927c478bd9Sstevel@tonic-gate if ((s & UF_FIXING) && dfs->fs_clean == FSFIX) {
17937c478bd9Sstevel@tonic-gate if (time > f->uf_entered_tm + toolong) {
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
179680d34432Sfrankho "Repair completion timeout exceeded on %s; "
179780d34432Sfrankho "manual fsck may be required", fs_name(f));
17987c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_long_err_period;
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate
18027c478bd9Sstevel@tonic-gate concerned = f->uf_entered_tm + (toolong / 3);
18037c478bd9Sstevel@tonic-gate anxious = f->uf_entered_tm + ((2 * toolong) / 3);
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate if (time > concerned)
18067c478bd9Sstevel@tonic-gate pester_msg(f, time > anxious? CE_WARN: CE_NOTE);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate TRIVIA(("] "));
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate out:
18117c478bd9Sstevel@tonic-gate if (bp)
18127c478bd9Sstevel@tonic-gate brelse(bp);
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate return (rc);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate
18177c478bd9Sstevel@tonic-gate static sfrc_t
sf_found_umount(ufs_failure_t * f)18187c478bd9Sstevel@tonic-gate sf_found_umount(ufs_failure_t *f)
18197c478bd9Sstevel@tonic-gate {
18207c478bd9Sstevel@tonic-gate extern time_t time;
18217c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
18227c478bd9Sstevel@tonic-gate struct vfs *vfsp = f->uf_vfsp;
18237c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = f->uf_ufsvfsp;
18247c478bd9Sstevel@tonic-gate int toolong = 0;
18257c478bd9Sstevel@tonic-gate int err = 0;
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate TRIVIA(("[sf_found_umount"));
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate toolong = time > ufsfx_tune.uft_too_long + f->uf_entered_tm;
18307c478bd9Sstevel@tonic-gate if (toolong) {
18317c478bd9Sstevel@tonic-gate TRIVIA((": unmount time limit exceeded] "));
18327c478bd9Sstevel@tonic-gate goto out;
18337c478bd9Sstevel@tonic-gate }
18347c478bd9Sstevel@tonic-gate
18357c478bd9Sstevel@tonic-gate if (!vfsp || !ufsvfsp) { /* trivial case */
18367c478bd9Sstevel@tonic-gate TRIVIA((": NULL vfsp and/or ufsvfsp, already unmounted?] "));
18377c478bd9Sstevel@tonic-gate goto out;
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate
18407c478bd9Sstevel@tonic-gate if (!ULOCKFS_IS_ELOCK(&ufsvfsp->vfs_ulockfs)) {
18417c478bd9Sstevel@tonic-gate TRIVIA((": !not error locked?"));
18427c478bd9Sstevel@tonic-gate err = EINVAL;
18437c478bd9Sstevel@tonic-gate goto out;
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate
18467c478bd9Sstevel@tonic-gate /* The vn_vfsunlock will be done in dounmount() [.../common/fs/vfs.c] */
1847d5dbd18dSbatschul if (vn_vfswlock(vfsp->vfs_vnodecovered)) {
18487c478bd9Sstevel@tonic-gate TRIVIA((": couldn't lock coveredvp"));
18497c478bd9Sstevel@tonic-gate err = EBUSY;
18507c478bd9Sstevel@tonic-gate goto out;
18517c478bd9Sstevel@tonic-gate }
18527c478bd9Sstevel@tonic-gate
18537c478bd9Sstevel@tonic-gate if ((err = dounmount(vfsp, 0, kcred)) != 0) {
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate /* take note, but not many alternatives here */
18567c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
18577c478bd9Sstevel@tonic-gate uf_stats.ufst_unmount_failures++;
18587c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
18597c478bd9Sstevel@tonic-gate
18607c478bd9Sstevel@tonic-gate TRIVIA((": unmount failed] "));
18617c478bd9Sstevel@tonic-gate } else {
18627c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "unmounted error-locked %s", fs_name(f));
18637c478bd9Sstevel@tonic-gate }
18647c478bd9Sstevel@tonic-gate
18657c478bd9Sstevel@tonic-gate out:
18667c478bd9Sstevel@tonic-gate if (toolong || (err != EBUSY && err != EAGAIN))
18677c478bd9Sstevel@tonic-gate rc = set_state(f, UF_NOTFIX);
18687c478bd9Sstevel@tonic-gate
18697c478bd9Sstevel@tonic-gate TRIVIA(("] "));
18707c478bd9Sstevel@tonic-gate return (rc);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate
18737c478bd9Sstevel@tonic-gate static sfrc_t
sf_term_cmn(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)18747c478bd9Sstevel@tonic-gate sf_term_cmn(ufs_failure_t *f, ufsa_t a, ufs_failure_states_t s)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate extern time_t time;
18777c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate TRIVIA(("[sf_term_cmn, action is %s, state is %s",
18807c478bd9Sstevel@tonic-gate act_name(a), state_name(s)));
18817c478bd9Sstevel@tonic-gate ASSERT(s & (UF_FIXED | UF_NOTFIX | UF_REPLICA));
18827c478bd9Sstevel@tonic-gate ASSERT(terminal_state(s));
18837c478bd9Sstevel@tonic-gate
18847c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp && !(f->uf_s & (UF_UMOUNT | UF_NOTFIX))) {
18857c478bd9Sstevel@tonic-gate TRIVIA((": NULL ufsvfsp (state != UMOUNT | NOTFIX)]\n"));
18867c478bd9Sstevel@tonic-gate return (rc);
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate
18897c478bd9Sstevel@tonic-gate switch (a) {
18907c478bd9Sstevel@tonic-gate case UFA_SET:
18917c478bd9Sstevel@tonic-gate switch (s) {
18927c478bd9Sstevel@tonic-gate case UF_NOTFIX:
18937c478bd9Sstevel@tonic-gate case UF_FIXED:
189480d34432Sfrankho {
189580d34432Sfrankho int need_lock_vfs;
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate if (f->uf_ufsvfsp && f->uf_vfs_lockp)
18987c478bd9Sstevel@tonic-gate need_lock_vfs = !MUTEX_HELD(f->uf_vfs_lockp);
18997c478bd9Sstevel@tonic-gate else
19007c478bd9Sstevel@tonic-gate need_lock_vfs = 0;
19017c478bd9Sstevel@tonic-gate
19027c478bd9Sstevel@tonic-gate if (need_lock_vfs && !mutex_tryenter(f->uf_vfs_lockp)) {
19037c478bd9Sstevel@tonic-gate TRIVIA((": tryenter(vfslockp) fail; retry]\n"));
19047c478bd9Sstevel@tonic-gate f->uf_retry = 1;
19057c478bd9Sstevel@tonic-gate break;
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate
19087c478bd9Sstevel@tonic-gate f->uf_end_tm = time;
19097c478bd9Sstevel@tonic-gate f->uf_lf.lf_lock = LOCKFS_OLOCK;
19107c478bd9Sstevel@tonic-gate f->uf_retry = 0;
19117c478bd9Sstevel@tonic-gate
19127c478bd9Sstevel@tonic-gate if (f->uf_vfs_ufsfxp)
19137c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp->fx_current = NULL;
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate if (need_lock_vfs)
19167c478bd9Sstevel@tonic-gate mutex_exit(f->uf_vfs_lockp);
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, (s & UF_NOTFIX)? "Could not fix %s":
19197c478bd9Sstevel@tonic-gate "%s is now accessible", fs_name(f));
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate if (s & UF_FIXED) {
19227c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
19237c478bd9Sstevel@tonic-gate uf_stats.ufst_num_fixed++;
19247c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
19257c478bd9Sstevel@tonic-gate }
19267c478bd9Sstevel@tonic-gate (void) timeout(ufsfx_kill_fix_failure_thread,
19277c478bd9Sstevel@tonic-gate (void *)(ufsfx_tune.uft_short_err_period * hz),
19287c478bd9Sstevel@tonic-gate ufsfx_tune.uft_short_err_period * hz);
19297c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
19307c478bd9Sstevel@tonic-gate break;
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate case UF_REPLICA:
19337c478bd9Sstevel@tonic-gate
19347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(f->uf_vfs_lockp));
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate /* not actually a replica? */
19377c478bd9Sstevel@tonic-gate if (f->uf_vfs_ufsfxp && f->uf_vfs_ufsfxp->fx_current &&
19387c478bd9Sstevel@tonic-gate f->uf_vfs_ufsfxp->fx_current != f &&
193980d34432Sfrankho !terminal_state(
194080d34432Sfrankho f->uf_vfs_ufsfxp->fx_current->uf_s)) {
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate f->uf_orig = f->uf_vfs_ufsfxp->fx_current;
19437c478bd9Sstevel@tonic-gate f->uf_retry = 0;
19447c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
19457c478bd9Sstevel@tonic-gate } else {
19467c478bd9Sstevel@tonic-gate TRIVIA((": NULL fx_current]\n"));
19477c478bd9Sstevel@tonic-gate f->uf_retry = 1;
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate
19507c478bd9Sstevel@tonic-gate break;
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate default:
19537c478bd9Sstevel@tonic-gate rc = set_state(f, UF_PANIC);
19547c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
19557c478bd9Sstevel@tonic-gate break;
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate break;
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate case UFA_FOUND:
19607c478bd9Sstevel@tonic-gate /*
19617c478bd9Sstevel@tonic-gate * XXX de-allocate these after some period?
19627c478bd9Sstevel@tonic-gate * XXX or move to an historical list?
19637c478bd9Sstevel@tonic-gate * XXX or have an ioctl which reaps them?
19647c478bd9Sstevel@tonic-gate */
19657c478bd9Sstevel@tonic-gate /*
19667c478bd9Sstevel@tonic-gate * For now, since we don't expect lots of failures
19677c478bd9Sstevel@tonic-gate * to occur (to the point of memory shortages),
19687c478bd9Sstevel@tonic-gate * just punt
19697c478bd9Sstevel@tonic-gate */
19707c478bd9Sstevel@tonic-gate
19717c478bd9Sstevel@tonic-gate /* be sure we're not wasting cpu on old failures */
19727c478bd9Sstevel@tonic-gate if (f->uf_retry != 0) {
19737c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
19747c478bd9Sstevel@tonic-gate uf_stats.ufst_cpu_waste++;
19757c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
19767c478bd9Sstevel@tonic-gate f->uf_retry = 0;
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
19797c478bd9Sstevel@tonic-gate break;
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate default:
19827c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
19837c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
19847c478bd9Sstevel@tonic-gate break;
19857c478bd9Sstevel@tonic-gate }
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate TRIVIA(("] "));
19887c478bd9Sstevel@tonic-gate return (rc);
19897c478bd9Sstevel@tonic-gate }
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate static sfrc_t
sf_panic(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t s)19927c478bd9Sstevel@tonic-gate sf_panic(
19937c478bd9Sstevel@tonic-gate ufs_failure_t *f,
19947c478bd9Sstevel@tonic-gate ufsa_t a,
19957c478bd9Sstevel@tonic-gate ufs_failure_states_t s)
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
19987c478bd9Sstevel@tonic-gate
19997c478bd9Sstevel@tonic-gate TRIVIA(("[sf_panic, action is %s, prev. state is %s",
20007c478bd9Sstevel@tonic-gate act_name(a), state_name(f->uf_s)));
20017c478bd9Sstevel@tonic-gate ASSERT(s & UF_PANIC);
20027c478bd9Sstevel@tonic-gate
20037c478bd9Sstevel@tonic-gate switch (a) {
20047c478bd9Sstevel@tonic-gate case UFA_SET:
20057c478bd9Sstevel@tonic-gate f->uf_retry = -ufsfx_tune.uft_short_err_period;
20067c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
20077c478bd9Sstevel@tonic-gate break;
20087c478bd9Sstevel@tonic-gate
20097c478bd9Sstevel@tonic-gate case UFA_FOUND:
20107c478bd9Sstevel@tonic-gate default:
20117c478bd9Sstevel@tonic-gate real_panic(f, " ");
20127c478bd9Sstevel@tonic-gate
20137c478bd9Sstevel@tonic-gate /* LINTED: warning: logical expression always true: op "||" */
20147c478bd9Sstevel@tonic-gate ASSERT(DEBUG);
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate (void) set_state(f, UF_UMOUNT); /* XXX UF_NOTFIX? */
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate break;
20197c478bd9Sstevel@tonic-gate }
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate TRIVIA(("] "));
20227c478bd9Sstevel@tonic-gate return (rc);
20237c478bd9Sstevel@tonic-gate }
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate /*
20267c478bd9Sstevel@tonic-gate * minimum state function
20277c478bd9Sstevel@tonic-gate */
20287c478bd9Sstevel@tonic-gate static sfrc_t
sf_minimum(ufs_failure_t * f,ufsa_t a,ufs_failure_states_t ignored)20297c478bd9Sstevel@tonic-gate sf_minimum(
20307c478bd9Sstevel@tonic-gate ufs_failure_t *f,
20317c478bd9Sstevel@tonic-gate ufsa_t a, /* LINTED argument unused in function: ignored */
20327c478bd9Sstevel@tonic-gate ufs_failure_states_t ignored)
20337c478bd9Sstevel@tonic-gate {
20347c478bd9Sstevel@tonic-gate sfrc_t rc = SFRC_FAIL;
20357c478bd9Sstevel@tonic-gate
20367c478bd9Sstevel@tonic-gate TRIVIA(("[sf_minimum, action is %s", act_name(a)));
20377c478bd9Sstevel@tonic-gate
20387c478bd9Sstevel@tonic-gate switch (a) {
20397c478bd9Sstevel@tonic-gate case UFA_SET:
20407c478bd9Sstevel@tonic-gate f->uf_retry = 0;
20417c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate case UFA_FOUND:
20447c478bd9Sstevel@tonic-gate rc = SFRC_SUCCESS;
20457c478bd9Sstevel@tonic-gate break;
20467c478bd9Sstevel@tonic-gate
20477c478bd9Sstevel@tonic-gate default:
20487c478bd9Sstevel@tonic-gate (void) set_state(f, UF_PANIC);
20497c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
20507c478bd9Sstevel@tonic-gate break;
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate
20537c478bd9Sstevel@tonic-gate TRIVIA(("] "));
20547c478bd9Sstevel@tonic-gate return (rc);
20557c478bd9Sstevel@tonic-gate }
20567c478bd9Sstevel@tonic-gate
20577c478bd9Sstevel@tonic-gate static int
state_trans_valid(ufs_failure_states_t from,ufs_failure_states_t to)20587c478bd9Sstevel@tonic-gate state_trans_valid(ufs_failure_states_t from, ufs_failure_states_t to)
20597c478bd9Sstevel@tonic-gate {
20607c478bd9Sstevel@tonic-gate ufsd_t *s;
20617c478bd9Sstevel@tonic-gate int valid;
20627c478bd9Sstevel@tonic-gate
20637c478bd9Sstevel@tonic-gate HIDEOUS(("[state_trans_valid"));
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate if (from & to)
20667c478bd9Sstevel@tonic-gate return (1);
20677c478bd9Sstevel@tonic-gate
20687c478bd9Sstevel@tonic-gate s = get_state_desc(to);
20697c478bd9Sstevel@tonic-gate
20707c478bd9Sstevel@tonic-gate /*
20717c478bd9Sstevel@tonic-gate * extra test is necessary since we want UF_UNDEF = 0,
20727c478bd9Sstevel@tonic-gate * (to detect freshly allocated memory)
20737c478bd9Sstevel@tonic-gate * but can't check for that value with a bit test
20747c478bd9Sstevel@tonic-gate */
20757c478bd9Sstevel@tonic-gate valid = (to & UF_INIT)? from == s->ud_prev: from & s->ud_prev;
20767c478bd9Sstevel@tonic-gate
20777c478bd9Sstevel@tonic-gate HIDEOUS((": %svalid] ", valid? "": "in"));
20787c478bd9Sstevel@tonic-gate return (valid);
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate static int
terminal_state(ufs_failure_states_t state)20827c478bd9Sstevel@tonic-gate terminal_state(ufs_failure_states_t state)
20837c478bd9Sstevel@tonic-gate {
20847c478bd9Sstevel@tonic-gate ufsd_t *s;
20857c478bd9Sstevel@tonic-gate
20867c478bd9Sstevel@tonic-gate HIDEOUS(("[terminal_state"));
20877c478bd9Sstevel@tonic-gate
20887c478bd9Sstevel@tonic-gate s = get_state_desc(state);
20897c478bd9Sstevel@tonic-gate
20907c478bd9Sstevel@tonic-gate HIDEOUS((": %sterminal] ", s->ud_attr.terminal? "": "not "));
20917c478bd9Sstevel@tonic-gate return ((int)s->ud_attr.terminal);
20927c478bd9Sstevel@tonic-gate }
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate static void
alloc_lockfs_comment(ufs_failure_t * f,struct lockfs * lfp)20957c478bd9Sstevel@tonic-gate alloc_lockfs_comment(ufs_failure_t *f, struct lockfs *lfp)
20967c478bd9Sstevel@tonic-gate {
20977c478bd9Sstevel@tonic-gate MINUTE(("[alloc_lockfs_comment"));
20987c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
20997c478bd9Sstevel@tonic-gate
21007c478bd9Sstevel@tonic-gate /*
21017c478bd9Sstevel@tonic-gate * ufs_fiolfs expects a kmem_alloc'ed comment;
21027c478bd9Sstevel@tonic-gate * it frees the comment if the lock fails
21037c478bd9Sstevel@tonic-gate * or else when the lock is unlocked.
21047c478bd9Sstevel@tonic-gate */
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate f->uf_lf.lf_comment = kmem_zalloc(LOCKFS_MAXCOMMENTLEN, KM_NOSLEEP);
21077c478bd9Sstevel@tonic-gate if (f->uf_lf.lf_comment) {
21087c478bd9Sstevel@tonic-gate char *from;
21097c478bd9Sstevel@tonic-gate size_t len;
21107c478bd9Sstevel@tonic-gate
21117c478bd9Sstevel@tonic-gate /*
21127c478bd9Sstevel@tonic-gate * use panic string if there's no previous comment
21137c478bd9Sstevel@tonic-gate * or if we're setting the error lock
21147c478bd9Sstevel@tonic-gate */
21157c478bd9Sstevel@tonic-gate if ((LOCKFS_IS_ELOCK(&f->uf_lf) || !lfp->lf_comment ||
21167c478bd9Sstevel@tonic-gate lfp->lf_comlen <= 0)) {
21177c478bd9Sstevel@tonic-gate from = f->uf_panic_str;
21187c478bd9Sstevel@tonic-gate len = LOCKFS_MAXCOMMENTLEN;
21197c478bd9Sstevel@tonic-gate } else {
21207c478bd9Sstevel@tonic-gate from = lfp->lf_comment;
21217c478bd9Sstevel@tonic-gate len = lfp->lf_comlen;
21227c478bd9Sstevel@tonic-gate }
21237c478bd9Sstevel@tonic-gate
21247c478bd9Sstevel@tonic-gate bcopy(from, f->uf_lf.lf_comment, len);
21257c478bd9Sstevel@tonic-gate f->uf_lf.lf_comlen = len;
21267c478bd9Sstevel@tonic-gate
21277c478bd9Sstevel@tonic-gate } else {
21287c478bd9Sstevel@tonic-gate f->uf_lf.lf_comlen = 0;
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate MINUTE(("] "));
21317c478bd9Sstevel@tonic-gate }
21327c478bd9Sstevel@tonic-gate
21337c478bd9Sstevel@tonic-gate static int
set_lockfs(ufs_failure_t * f,struct lockfs * lfp)21347c478bd9Sstevel@tonic-gate set_lockfs(ufs_failure_t *f, struct lockfs *lfp)
21357c478bd9Sstevel@tonic-gate {
21367c478bd9Sstevel@tonic-gate int (*handle_lockfs_rc)(ufs_failure_t *);
21377c478bd9Sstevel@tonic-gate int rc;
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate MINUTE(("[set_lockfs"));
21407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
21417c478bd9Sstevel@tonic-gate ASSERT(!vfs_lock_held(f->uf_vfsp));
21427c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
21457c478bd9Sstevel@tonic-gate MINUTE((": ufsvfsp is NULL]\n"));
21467c478bd9Sstevel@tonic-gate return (0);
21477c478bd9Sstevel@tonic-gate }
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&f->uf_ufsvfsp->vfs_ulockfs.ul_lock));
21507c478bd9Sstevel@tonic-gate
21517c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp->vfs_root) {
21527c478bd9Sstevel@tonic-gate MINUTE((": vfs_root is NULL]\n"));
21537c478bd9Sstevel@tonic-gate return (0);
21547c478bd9Sstevel@tonic-gate }
21557c478bd9Sstevel@tonic-gate
21567c478bd9Sstevel@tonic-gate alloc_lockfs_comment(f, lfp);
21577c478bd9Sstevel@tonic-gate f->uf_lf_err = 0;
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate if (!LOCKFS_IS_ELOCK(lfp)) {
21607c478bd9Sstevel@tonic-gate lfp->lf_lock = f->uf_lf.lf_lock = LOCKFS_ELOCK;
21617c478bd9Sstevel@tonic-gate VN_HOLD(f->uf_ufsvfsp->vfs_root);
216280d34432Sfrankho f->uf_lf_err =
216380d34432Sfrankho ufs__fiolfs(f->uf_ufsvfsp->vfs_root,
216480d34432Sfrankho &f->uf_lf, /* from_user */ 0, /* from_log */ 0);
21657c478bd9Sstevel@tonic-gate VN_RELE(f->uf_ufsvfsp->vfs_root);
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate handle_lockfs_rc = f->uf_lf_err != 0? lockfs_failure: lockfs_success;
21697c478bd9Sstevel@tonic-gate rc = handle_lockfs_rc(f);
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate MINUTE(("] "));
21727c478bd9Sstevel@tonic-gate return (rc);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate static int
lockfs_failure(ufs_failure_t * f)21767c478bd9Sstevel@tonic-gate lockfs_failure(ufs_failure_t *f)
21777c478bd9Sstevel@tonic-gate {
21787c478bd9Sstevel@tonic-gate int error;
21797c478bd9Sstevel@tonic-gate ufs_failure_states_t s;
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate TRIVIA(("[lockfs_failure"));
21827c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
21857c478bd9Sstevel@tonic-gate TRIVIA((": ufsvfsp is NULL]\n"));
21867c478bd9Sstevel@tonic-gate return (0);
21877c478bd9Sstevel@tonic-gate }
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate error = f->uf_lf_err;
21907c478bd9Sstevel@tonic-gate switch (error) {
21917c478bd9Sstevel@tonic-gate /* non-transient errors: */
21927c478bd9Sstevel@tonic-gate case EACCES: /* disk/in-core metadata reconciliation failed */
21937c478bd9Sstevel@tonic-gate case EPERM: /* inode reconciliation failed; incore inode changed? */
21947c478bd9Sstevel@tonic-gate case EIO: /* device is hard-locked or not responding */
21957c478bd9Sstevel@tonic-gate case EROFS: /* device is write-locked */
21967c478bd9Sstevel@tonic-gate case EDEADLK: /* can't lockfs; deadlock would result; */
21977c478bd9Sstevel@tonic-gate /* Swapping or saving accounting records */
21987c478bd9Sstevel@tonic-gate /* onto this fs can cause this errno. */
21997c478bd9Sstevel@tonic-gate
22007c478bd9Sstevel@tonic-gate MINOR(("ufs_fiolfs(\"%s\") of %s failed: %s (%d)",
220180d34432Sfrankho fs_name(f), lock_name(&f->uf_lf),
220280d34432Sfrankho err_name(error), error));
22037c478bd9Sstevel@tonic-gate
22047c478bd9Sstevel@tonic-gate /*
22057c478bd9Sstevel@tonic-gate * if can't get lock, then fallback to panic, unless
22067c478bd9Sstevel@tonic-gate * unless unmount was requested (although unmount will
22077c478bd9Sstevel@tonic-gate * probably fail if the lock failed, so we'll panic
22087c478bd9Sstevel@tonic-gate * anyway
22097c478bd9Sstevel@tonic-gate */
22107c478bd9Sstevel@tonic-gate
22117c478bd9Sstevel@tonic-gate s = ((f->uf_flags & UFSFX_LCKUMOUNT) && error != EDEADLK) ?
22127c478bd9Sstevel@tonic-gate UF_UMOUNT: UF_PANIC;
22137c478bd9Sstevel@tonic-gate
22147c478bd9Sstevel@tonic-gate if (!set_state(f, s)) {
22157c478bd9Sstevel@tonic-gate real_panic(f, " ");
22167c478bd9Sstevel@tonic-gate /*NOTREACHED*/
22177c478bd9Sstevel@tonic-gate break;
22187c478bd9Sstevel@tonic-gate }
22197c478bd9Sstevel@tonic-gate break;
22207c478bd9Sstevel@tonic-gate
22217c478bd9Sstevel@tonic-gate
22227c478bd9Sstevel@tonic-gate case EBUSY:
22237c478bd9Sstevel@tonic-gate case EAGAIN:
22247c478bd9Sstevel@tonic-gate
22257c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_short_err_period;
22267c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_DONTPEND) {
22277c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTPEND;
22287c478bd9Sstevel@tonic-gate
22297c478bd9Sstevel@tonic-gate } else if (!(f->uf_s & (UF_LOCKED | UF_FIXING))) {
22307c478bd9Sstevel@tonic-gate ufs_failure_states_t state;
22317c478bd9Sstevel@tonic-gate /*
22327c478bd9Sstevel@tonic-gate * if we didn't know that the fix had started,
22337c478bd9Sstevel@tonic-gate * take note
22347c478bd9Sstevel@tonic-gate */
22357c478bd9Sstevel@tonic-gate state = error == EBUSY? UF_LOCKED: UF_FIXING;
22367c478bd9Sstevel@tonic-gate if (!set_state(f, state)) {
22377c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
22387c478bd9Sstevel@tonic-gate return (0);
22397c478bd9Sstevel@tonic-gate }
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate break;
22427c478bd9Sstevel@tonic-gate
22437c478bd9Sstevel@tonic-gate default: /* some other non-fatal error */
22447c478bd9Sstevel@tonic-gate MINOR(("lockfs(\"%s\") of %s returned %s (%d)",
224580d34432Sfrankho lock_name(&f->uf_lf), fs_name(f),
224680d34432Sfrankho err_name(f->uf_lf_err), f->uf_lf_err));
22477c478bd9Sstevel@tonic-gate
22487c478bd9Sstevel@tonic-gate f->uf_retry = ufsfx_tune.uft_short_err_period;
22497c478bd9Sstevel@tonic-gate break;
22507c478bd9Sstevel@tonic-gate
22517c478bd9Sstevel@tonic-gate case EINVAL: /* unmounted? */
22527c478bd9Sstevel@tonic-gate (void) set_state(f, UF_NOTFIX);
22537c478bd9Sstevel@tonic-gate break;
22547c478bd9Sstevel@tonic-gate }
22557c478bd9Sstevel@tonic-gate TRIVIA(("] "));
22567c478bd9Sstevel@tonic-gate return (1);
22577c478bd9Sstevel@tonic-gate }
22587c478bd9Sstevel@tonic-gate
22597c478bd9Sstevel@tonic-gate static int
lockfs_success(ufs_failure_t * f)22607c478bd9Sstevel@tonic-gate lockfs_success(ufs_failure_t *f)
22617c478bd9Sstevel@tonic-gate {
22627c478bd9Sstevel@tonic-gate TRIVIA(("[lockfs_success"));
22637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
22647c478bd9Sstevel@tonic-gate
22657c478bd9Sstevel@tonic-gate if (!f->uf_ufsvfsp) {
22667c478bd9Sstevel@tonic-gate TRIVIA((": ufsvfsp is NULL]\n"));
22677c478bd9Sstevel@tonic-gate return (0);
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate switch (f->uf_lf.lf_lock) {
22717c478bd9Sstevel@tonic-gate case LOCKFS_ELOCK: /* error lock worked */
22727c478bd9Sstevel@tonic-gate
22737c478bd9Sstevel@tonic-gate if (!set_state(f, UF_LOCKED)) {
22747c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
22757c478bd9Sstevel@tonic-gate return (0);
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate break;
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate case LOCKFS_ULOCK: /* unlock worked */
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate * how'd we get here?
22827c478bd9Sstevel@tonic-gate * This should be done from fsck's unlock,
22837c478bd9Sstevel@tonic-gate * not from this thread's context.
22847c478bd9Sstevel@tonic-gate */
22857c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Unlocked error-lock of %s", fs_name(f));
22867c478bd9Sstevel@tonic-gate ufsfx_unlockfs(f->uf_ufsvfsp);
22877c478bd9Sstevel@tonic-gate break;
22887c478bd9Sstevel@tonic-gate
22897c478bd9Sstevel@tonic-gate default:
22907c478bd9Sstevel@tonic-gate if (!set_state(f, UF_NOTFIX)) {
22917c478bd9Sstevel@tonic-gate TRIVIA((": failed] "));
22927c478bd9Sstevel@tonic-gate return (0);
22937c478bd9Sstevel@tonic-gate }
22947c478bd9Sstevel@tonic-gate break;
22957c478bd9Sstevel@tonic-gate }
22967c478bd9Sstevel@tonic-gate TRIVIA(("] "));
22977c478bd9Sstevel@tonic-gate return (1);
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate
23007c478bd9Sstevel@tonic-gate /*
23017c478bd9Sstevel@tonic-gate * when fsck is running it puts its pid into the lockfs
23027c478bd9Sstevel@tonic-gate * comment structure, prefaced by PIDSTR
23037c478bd9Sstevel@tonic-gate */
23047c478bd9Sstevel@tonic-gate const char *PIDSTR = "[pid:";
23057c478bd9Sstevel@tonic-gate static int
fsck_active(ufs_failure_t * f)23067c478bd9Sstevel@tonic-gate fsck_active(ufs_failure_t *f)
23077c478bd9Sstevel@tonic-gate {
23087c478bd9Sstevel@tonic-gate char *cp;
23097c478bd9Sstevel@tonic-gate int i, found, errlocked;
23107c478bd9Sstevel@tonic-gate size_t comlen;
23117c478bd9Sstevel@tonic-gate const int PIDSTRLEN = (int)strlen(PIDSTR);
23127c478bd9Sstevel@tonic-gate struct ulockfs *ulp = &f->uf_ufsvfsp->vfs_ulockfs;
23137c478bd9Sstevel@tonic-gate
23147c478bd9Sstevel@tonic-gate TRIVIA(("[fsck_active"));
23157c478bd9Sstevel@tonic-gate
23167c478bd9Sstevel@tonic-gate ASSERT(f);
23177c478bd9Sstevel@tonic-gate ASSERT(f->uf_s & UF_FIXING);
23187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
23197c478bd9Sstevel@tonic-gate ASSERT(f->uf_ufsvfsp);
23207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(f->uf_vfs_lockp));
23217c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&ulp->ul_lock));
23227c478bd9Sstevel@tonic-gate
23237c478bd9Sstevel@tonic-gate mutex_enter(&ulp->ul_lock);
23247c478bd9Sstevel@tonic-gate cp = ulp->ul_lockfs.lf_comment;
23257c478bd9Sstevel@tonic-gate comlen = ulp->ul_lockfs.lf_comlen;
23267c478bd9Sstevel@tonic-gate errlocked = (int)ULOCKFS_IS_ELOCK(ulp);
23277c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock);
23287c478bd9Sstevel@tonic-gate
23297c478bd9Sstevel@tonic-gate if (!cp || comlen == 0) {
23307c478bd9Sstevel@tonic-gate TRIVIA((": null comment or comlen <= 0, found:0]"));
23317c478bd9Sstevel@tonic-gate return (0);
23327c478bd9Sstevel@tonic-gate }
23337c478bd9Sstevel@tonic-gate
23347c478bd9Sstevel@tonic-gate for (found = i = 0; !found && i < (comlen - PIDSTRLEN); i++, cp++)
23357c478bd9Sstevel@tonic-gate found = strncmp(cp, PIDSTR, PIDSTRLEN) == 0;
23367c478bd9Sstevel@tonic-gate
23377c478bd9Sstevel@tonic-gate TRIVIA(("found:%d, is_elock:%d]", found, errlocked));
23387c478bd9Sstevel@tonic-gate return (errlocked & found);
23397c478bd9Sstevel@tonic-gate }
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate static const char unknown_fs[] = "<unknown fs>";
23427c478bd9Sstevel@tonic-gate static const char null_failure[] = "<NULL ufs failure record; unknown fs>";
23437c478bd9Sstevel@tonic-gate static const char mutated_vfs_bufp[] = "<mutated vfs_bufp, unknown fs>";
23447c478bd9Sstevel@tonic-gate static const char mutated_vfs_fs[] = "<mutated vfs_fs, unknown fs>";
23457c478bd9Sstevel@tonic-gate
23467c478bd9Sstevel@tonic-gate static char *
fs_name(ufs_failure_t * f)23477c478bd9Sstevel@tonic-gate fs_name(ufs_failure_t *f)
23487c478bd9Sstevel@tonic-gate {
23497c478bd9Sstevel@tonic-gate HIDEOUS(("[fs_name"));
23507c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&f->uf_mutex));
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate if (!f) {
23537c478bd9Sstevel@tonic-gate HIDEOUS((": failure ptr is NULL]\n"));
23547c478bd9Sstevel@tonic-gate return ((char *)null_failure);
23557c478bd9Sstevel@tonic-gate }
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate if (f->uf_fsname[0] != '\0') {
23587c478bd9Sstevel@tonic-gate HIDEOUS((": return (uf_fsname)]\n"));
23597c478bd9Sstevel@tonic-gate return (f->uf_fsname);
23607c478bd9Sstevel@tonic-gate }
23617c478bd9Sstevel@tonic-gate
23627c478bd9Sstevel@tonic-gate if (MUTEX_HELD(f->uf_vfs_lockp)) {
23637c478bd9Sstevel@tonic-gate if (f->uf_bp != f->uf_ufsvfsp->vfs_bufp) {
23647c478bd9Sstevel@tonic-gate HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
23657c478bd9Sstevel@tonic-gate (void *)f->uf_bp, (void *)f->uf_ufsvfsp->vfs_bufp));
23667c478bd9Sstevel@tonic-gate return ((char *)mutated_vfs_bufp);
23677c478bd9Sstevel@tonic-gate }
23687c478bd9Sstevel@tonic-gate if (f->uf_fs != f->uf_ufsvfsp->vfs_fs) {
23697c478bd9Sstevel@tonic-gate HIDEOUS((": vfs_bufp mutated from 0x%p to 0x%p\n",
23707c478bd9Sstevel@tonic-gate (void *)f->uf_fs, (void *)f->uf_ufsvfsp->vfs_fs));
23717c478bd9Sstevel@tonic-gate return ((char *)mutated_vfs_fs);
23727c478bd9Sstevel@tonic-gate }
23737c478bd9Sstevel@tonic-gate if (f->uf_ufsvfsp && f->uf_bp && f->uf_fs &&
23747c478bd9Sstevel@tonic-gate *f->uf_fs->fs_fsmnt != '\0') {
23757c478bd9Sstevel@tonic-gate HIDEOUS((": return (fs_fsmnt)]\n"));
23767c478bd9Sstevel@tonic-gate return (f->uf_fs->fs_fsmnt);
23777c478bd9Sstevel@tonic-gate }
23787c478bd9Sstevel@tonic-gate }
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate HIDEOUS((": unknown file system]\n"));
23817c478bd9Sstevel@tonic-gate return ((char *)unknown_fs);
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate
23847c478bd9Sstevel@tonic-gate #if defined(DEBUG)
23857c478bd9Sstevel@tonic-gate static char *
lock_name(struct lockfs * lfp)23867c478bd9Sstevel@tonic-gate lock_name(struct lockfs *lfp)
23877c478bd9Sstevel@tonic-gate {
23887c478bd9Sstevel@tonic-gate struct lock_description *l;
23897c478bd9Sstevel@tonic-gate char *lname;
23907c478bd9Sstevel@tonic-gate
23917c478bd9Sstevel@tonic-gate HIDEOUS(("[lock_name"));
23927c478bd9Sstevel@tonic-gate
23937c478bd9Sstevel@tonic-gate lname = lock_desc[0].ld_name;
23947c478bd9Sstevel@tonic-gate for (l = &lock_desc[1]; l->ld_name != NULL; l++) {
23957c478bd9Sstevel@tonic-gate if (lfp && lfp->lf_lock == l->ld_type) {
23967c478bd9Sstevel@tonic-gate lname = l->ld_name;
23977c478bd9Sstevel@tonic-gate break;
23987c478bd9Sstevel@tonic-gate }
23997c478bd9Sstevel@tonic-gate }
24007c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24017c478bd9Sstevel@tonic-gate return (lname);
24027c478bd9Sstevel@tonic-gate }
24037c478bd9Sstevel@tonic-gate
24047c478bd9Sstevel@tonic-gate static char *
state_name(ufs_failure_states_t state)24057c478bd9Sstevel@tonic-gate state_name(ufs_failure_states_t state)
24067c478bd9Sstevel@tonic-gate {
24077c478bd9Sstevel@tonic-gate ufsd_t *s;
24087c478bd9Sstevel@tonic-gate
24097c478bd9Sstevel@tonic-gate HIDEOUS(("[state_name"));
24107c478bd9Sstevel@tonic-gate
24117c478bd9Sstevel@tonic-gate s = get_state_desc(state);
24127c478bd9Sstevel@tonic-gate
24137c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24147c478bd9Sstevel@tonic-gate return (s->ud_name);
24157c478bd9Sstevel@tonic-gate }
24167c478bd9Sstevel@tonic-gate
24177c478bd9Sstevel@tonic-gate static char *
err_name(int error)24187c478bd9Sstevel@tonic-gate err_name(int error)
24197c478bd9Sstevel@tonic-gate {
24207c478bd9Sstevel@tonic-gate struct error_description *e;
24217c478bd9Sstevel@tonic-gate
24227c478bd9Sstevel@tonic-gate HIDEOUS(("[err_name"));
24237c478bd9Sstevel@tonic-gate
24247c478bd9Sstevel@tonic-gate for (e = &err_desc[1]; e->ed_name != NULL; e++) {
24257c478bd9Sstevel@tonic-gate if (error == e->ed_errno) {
24267c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24277c478bd9Sstevel@tonic-gate return (e->ed_name);
24287c478bd9Sstevel@tonic-gate }
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24317c478bd9Sstevel@tonic-gate return (err_desc[0].ed_name);
24327c478bd9Sstevel@tonic-gate }
24337c478bd9Sstevel@tonic-gate
24347c478bd9Sstevel@tonic-gate static char *
act_name(ufsa_t action)24357c478bd9Sstevel@tonic-gate act_name(ufsa_t action)
24367c478bd9Sstevel@tonic-gate {
24377c478bd9Sstevel@tonic-gate struct action_description *a;
24387c478bd9Sstevel@tonic-gate
24397c478bd9Sstevel@tonic-gate HIDEOUS(("[act_name"));
24407c478bd9Sstevel@tonic-gate
24417c478bd9Sstevel@tonic-gate for (a = &act_desc[1]; a->ad_name != NULL; a++) {
24427c478bd9Sstevel@tonic-gate if (action == a->ad_v) {
24437c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24447c478bd9Sstevel@tonic-gate return (a->ad_name);
24457c478bd9Sstevel@tonic-gate }
24467c478bd9Sstevel@tonic-gate }
24477c478bd9Sstevel@tonic-gate HIDEOUS(("]"));
24487c478bd9Sstevel@tonic-gate return (act_desc[0].ad_name);
24497c478bd9Sstevel@tonic-gate }
24507c478bd9Sstevel@tonic-gate
24517c478bd9Sstevel@tonic-gate /*
24527c478bd9Sstevel@tonic-gate * dump failure list
24537c478bd9Sstevel@tonic-gate */
24547c478bd9Sstevel@tonic-gate static void
dump_uf_list(char * msg)24557c478bd9Sstevel@tonic-gate dump_uf_list(char *msg)
24567c478bd9Sstevel@tonic-gate {
24577c478bd9Sstevel@tonic-gate ufs_failure_t *f;
24587c478bd9Sstevel@tonic-gate int i;
24597c478bd9Sstevel@tonic-gate int list_was_locked = MUTEX_HELD(&ufs_fix.uq_mutex);
24607c478bd9Sstevel@tonic-gate
24617c478bd9Sstevel@tonic-gate if (!list_was_locked && !mutex_tryenter(&ufs_fix.uq_mutex)) {
24627c478bd9Sstevel@tonic-gate printf("dump_uf_list: couldn't get list lock\n");
24637c478bd9Sstevel@tonic-gate return;
24647c478bd9Sstevel@tonic-gate }
24657c478bd9Sstevel@tonic-gate
24667c478bd9Sstevel@tonic-gate if (msg) {
24677c478bd9Sstevel@tonic-gate printf("\n%s", msg);
24687c478bd9Sstevel@tonic-gate }
24697c478bd9Sstevel@tonic-gate printf("\ndump_uf_list:\n\tuq_lowat: %d, uq_ne: %d\n",
24707c478bd9Sstevel@tonic-gate ufs_fix.uq_lowat, ufs_fix.uq_ne);
24717c478bd9Sstevel@tonic-gate
24727c478bd9Sstevel@tonic-gate mutex_enter(&uf_stats.ufst_mutex);
24737c478bd9Sstevel@tonic-gate printf("\tuf_stats.current_races: %ld\n", uf_stats.ufst_current_races);
24747c478bd9Sstevel@tonic-gate printf("\tuf_stats.num_failed: %ld\n", uf_stats.ufst_num_failed);
24757c478bd9Sstevel@tonic-gate printf("\tuf_stats.num_fixed: %ld\n", uf_stats.ufst_num_fixed);
24767c478bd9Sstevel@tonic-gate printf("\tuf_stats.cpu_waste: %ld\n", uf_stats.ufst_cpu_waste);
24777c478bd9Sstevel@tonic-gate printf("\tuf_stats.lock_violations: %ld, unmount_failures: %ld\n",
24787c478bd9Sstevel@tonic-gate uf_stats.ufst_lock_violations, uf_stats.ufst_unmount_failures);
24797c478bd9Sstevel@tonic-gate mutex_exit(&uf_stats.ufst_mutex);
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead, i = 1; f; f = f->uf_next, i++) {
24827c478bd9Sstevel@tonic-gate
24837c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&f->uf_mutex)) {
24847c478bd9Sstevel@tonic-gate printf("%d.\t\"skipped - try enter failed\"\n", i);
24857c478bd9Sstevel@tonic-gate continue;
24867c478bd9Sstevel@tonic-gate }
24877c478bd9Sstevel@tonic-gate
24887c478bd9Sstevel@tonic-gate dump_uf(f, i);
24897c478bd9Sstevel@tonic-gate
24907c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
24917c478bd9Sstevel@tonic-gate }
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate printf("\n");
24947c478bd9Sstevel@tonic-gate
24957c478bd9Sstevel@tonic-gate if (!list_was_locked)
24967c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
24977c478bd9Sstevel@tonic-gate }
24987c478bd9Sstevel@tonic-gate
24997c478bd9Sstevel@tonic-gate static void
dump_uf(ufs_failure_t * f,int i)25007c478bd9Sstevel@tonic-gate dump_uf(ufs_failure_t *f, int i)
25017c478bd9Sstevel@tonic-gate {
25027c478bd9Sstevel@tonic-gate if (!f) {
25037c478bd9Sstevel@tonic-gate printf("dump_uf: NULL failure record\n");
25047c478bd9Sstevel@tonic-gate return;
25057c478bd9Sstevel@tonic-gate }
25067c478bd9Sstevel@tonic-gate
25077c478bd9Sstevel@tonic-gate printf("%d.\t\"%s\" is %s.\n",
25087c478bd9Sstevel@tonic-gate i, fs_name(f), state_name(f->uf_s));
25097c478bd9Sstevel@tonic-gate printf("\t\"%s\"\tAddr: 0x%p\n", f->uf_panic_str, (void *)f);
25107c478bd9Sstevel@tonic-gate printf("\tNext: 0x%p\t\tPrev: 0x%p\n",
25117c478bd9Sstevel@tonic-gate (void *)f->uf_next, (void *)f->uf_prev);
25127c478bd9Sstevel@tonic-gate
25137c478bd9Sstevel@tonic-gate if (f->uf_orig)
25147c478bd9Sstevel@tonic-gate printf("\tOriginal failure: 0x%p \"%s\"\n",
25157c478bd9Sstevel@tonic-gate (void *)f->uf_orig, f->uf_orig->uf_panic_str);
25167c478bd9Sstevel@tonic-gate
25177c478bd9Sstevel@tonic-gate printf("\tUfsvfs: 0x%p\t\tVfs_lockp: 0x%p\n",
25187c478bd9Sstevel@tonic-gate (void *)f->uf_ufsvfsp, (void *)f->uf_vfs_lockp);
25197c478bd9Sstevel@tonic-gate printf("\tVfs_fsfxp: 0x%p\n", (void *)f->uf_vfs_ufsfxp);
25207c478bd9Sstevel@tonic-gate printf("\tVfs_bufp: 0x%p", (void *)f->uf_bp);
25217c478bd9Sstevel@tonic-gate
25227c478bd9Sstevel@tonic-gate if (f->uf_bp)
25237c478bd9Sstevel@tonic-gate printf("\t\tVfs_fs: 0x%p\n", (void *)f->uf_fs);
25247c478bd9Sstevel@tonic-gate else
25257c478bd9Sstevel@tonic-gate printf("\n");
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate printf("\tBegin: 0x%lx\tEntered: 0x%lx\tEnd: 0x%lx\n",
25287c478bd9Sstevel@tonic-gate f->uf_begin_tm, f->uf_entered_tm, f->uf_end_tm);
25297c478bd9Sstevel@tonic-gate
25307c478bd9Sstevel@tonic-gate printf("\tFlags: (%d) %s%s%s%s", f->uf_flags,
25317c478bd9Sstevel@tonic-gate f->uf_flags & UFSFX_LCKONLY? "\"lock only\" " : "",
25327c478bd9Sstevel@tonic-gate f->uf_flags & UFSFX_LCKUMOUNT? "\"lock+unmount\" " : "",
25337c478bd9Sstevel@tonic-gate f->uf_flags & UFSFX_REPAIR_START? "\"started repair\" " : "",
25347c478bd9Sstevel@tonic-gate f->uf_flags == 0? "<none>" : "");
25357c478bd9Sstevel@tonic-gate
25367c478bd9Sstevel@tonic-gate printf("\tRetry: %ld seconds\n", f->uf_retry);
25377c478bd9Sstevel@tonic-gate
25387c478bd9Sstevel@tonic-gate printf("\tLockfs:\ttype: %s\terror: %s (%d)\n",
253980d34432Sfrankho lock_name(&f->uf_lf), err_name(f->uf_lf_err), f->uf_lf_err);
25407c478bd9Sstevel@tonic-gate
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate #endif /* DEBUG */
25437c478bd9Sstevel@tonic-gate
25447c478bd9Sstevel@tonic-gate /*
25457c478bd9Sstevel@tonic-gate * returns # of ufs_failures in a non-terminal state on queue
25467c478bd9Sstevel@tonic-gate * used to coordinate with hlock thread (see ufs_thread.c)
25477c478bd9Sstevel@tonic-gate * and to determine when the error lock thread may exit
25487c478bd9Sstevel@tonic-gate */
25497c478bd9Sstevel@tonic-gate
25507c478bd9Sstevel@tonic-gate int
ufsfx_get_failure_qlen(void)25517c478bd9Sstevel@tonic-gate ufsfx_get_failure_qlen(void)
25527c478bd9Sstevel@tonic-gate {
25537c478bd9Sstevel@tonic-gate ufs_failure_t *f;
25547c478bd9Sstevel@tonic-gate ufsd_t *s;
25557c478bd9Sstevel@tonic-gate int qlen = 0;
25567c478bd9Sstevel@tonic-gate
25577c478bd9Sstevel@tonic-gate MINUTE(("[ufsfx_get_failure_qlen"));
25587c478bd9Sstevel@tonic-gate
25597c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&ufs_fix.uq_mutex))
25607c478bd9Sstevel@tonic-gate return (-1);
25617c478bd9Sstevel@tonic-gate
25627c478bd9Sstevel@tonic-gate /*
25637c478bd9Sstevel@tonic-gate * walk down failure list
25647c478bd9Sstevel@tonic-gate */
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gate for (f = ufs_fix.uq_ufhead; f; f = f->uf_next) {
25677c478bd9Sstevel@tonic-gate
25687c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&f->uf_mutex))
25697c478bd9Sstevel@tonic-gate continue;
25707c478bd9Sstevel@tonic-gate
25717c478bd9Sstevel@tonic-gate s = get_state_desc(f->uf_s);
25727c478bd9Sstevel@tonic-gate
25737c478bd9Sstevel@tonic-gate if (s->ud_attr.terminal) {
25747c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
25757c478bd9Sstevel@tonic-gate continue;
25767c478bd9Sstevel@tonic-gate }
25777c478bd9Sstevel@tonic-gate
25787c478bd9Sstevel@tonic-gate MINUTE((": found: %s, \"%s: %s\"\n",
25797c478bd9Sstevel@tonic-gate fs_name(f), state_name(f->uf_s), f->uf_panic_str));
25807c478bd9Sstevel@tonic-gate
25817c478bd9Sstevel@tonic-gate qlen++;
25827c478bd9Sstevel@tonic-gate mutex_exit(&f->uf_mutex);
25837c478bd9Sstevel@tonic-gate }
25847c478bd9Sstevel@tonic-gate
25857c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex);
25867c478bd9Sstevel@tonic-gate
25877c478bd9Sstevel@tonic-gate MINUTE((": qlen=%d]\n", qlen));
25887c478bd9Sstevel@tonic-gate
25897c478bd9Sstevel@tonic-gate return (qlen);
25907c478bd9Sstevel@tonic-gate }
25917c478bd9Sstevel@tonic-gate
25927c478bd9Sstevel@tonic-gate /*
25937c478bd9Sstevel@tonic-gate * timeout routine
25947c478bd9Sstevel@tonic-gate * called to shutdown fix failure thread and server daemon
25957c478bd9Sstevel@tonic-gate */
25967c478bd9Sstevel@tonic-gate static void
ufsfx_kill_fix_failure_thread(void * arg)25977c478bd9Sstevel@tonic-gate ufsfx_kill_fix_failure_thread(void *arg)
25987c478bd9Sstevel@tonic-gate {
25997c478bd9Sstevel@tonic-gate clock_t odelta = (clock_t)arg;
26007c478bd9Sstevel@tonic-gate int qlen;
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate MAJOR(("[ufsfx_kill_fix_failure_thread"));
26037c478bd9Sstevel@tonic-gate
26047c478bd9Sstevel@tonic-gate qlen = ufsfx_get_failure_qlen();
26057c478bd9Sstevel@tonic-gate
26067c478bd9Sstevel@tonic-gate if (qlen < 0) {
26077c478bd9Sstevel@tonic-gate clock_t delta;
26087c478bd9Sstevel@tonic-gate
26097c478bd9Sstevel@tonic-gate delta = odelta << 1;
26107c478bd9Sstevel@tonic-gate if (delta <= 0)
26117c478bd9Sstevel@tonic-gate delta = INT_MAX;
26127c478bd9Sstevel@tonic-gate
26137c478bd9Sstevel@tonic-gate (void) timeout(ufsfx_kill_fix_failure_thread,
26147c478bd9Sstevel@tonic-gate (void *)delta, delta);
26157c478bd9Sstevel@tonic-gate MAJOR((": rescheduled"));
26167c478bd9Sstevel@tonic-gate
26177c478bd9Sstevel@tonic-gate } else if (qlen == 0) {
26187c478bd9Sstevel@tonic-gate ufs_thread_exit(&ufs_fix);
26197c478bd9Sstevel@tonic-gate MAJOR((": killed"));
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate /*
26227c478bd9Sstevel@tonic-gate * else
26237c478bd9Sstevel@tonic-gate * let timeout expire
26247c478bd9Sstevel@tonic-gate */
26257c478bd9Sstevel@tonic-gate MAJOR(("]\n"));
26267c478bd9Sstevel@tonic-gate }
2627