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