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