static int lcw_dispatch_main(void *data) { int rc = 0; unsigned long flags; struct lc_watchdog *lcw; CFS_LIST_HEAD (zombies); ENTRY; cfs_daemonize("lc_watchdogd"); SIGNAL_MASK_LOCK(current, flags); sigfillset(¤t->blocked); RECALC_SIGPENDING; SIGNAL_MASK_UNLOCK(current, flags); cfs_complete(&lcw_start_completion); while (1) { int dumplog = 1; cfs_wait_event_interruptible(lcw_event_waitq, is_watchdog_fired(), rc); CDEBUG(D_INFO, "Watchdog got woken up...\n"); if (cfs_test_bit(LCW_FLAG_STOP, &lcw_flags)) { CDEBUG(D_INFO, "LCW_FLAG_STOP was set, shutting down...\n"); cfs_spin_lock_bh(&lcw_pending_timers_lock); rc = !cfs_list_empty(&lcw_pending_timers); cfs_spin_unlock_bh(&lcw_pending_timers_lock); if (rc) { CERROR("pending timers list was not empty at " "time of watchdog dispatch shutdown\n"); } break; } cfs_spin_lock_bh(&lcw_pending_timers_lock); while (!cfs_list_empty(&lcw_pending_timers)) { int is_dumplog; lcw = cfs_list_entry(lcw_pending_timers.next, struct lc_watchdog, lcw_list); /* +1 ref for callback to make sure lwc wouldn't be * deleted after releasing lcw_pending_timers_lock */ lcw->lcw_refcount++; cfs_spin_unlock_bh(&lcw_pending_timers_lock); /* lock ordering */ cfs_spin_lock_bh(&lcw->lcw_lock); cfs_spin_lock_bh(&lcw_pending_timers_lock); if (cfs_list_empty(&lcw->lcw_list)) { /* already removed from pending list */ lcw->lcw_refcount--; /* -1 ref for callback */ if (lcw->lcw_refcount == 0) cfs_list_add(&lcw->lcw_list, &zombies); cfs_spin_unlock_bh(&lcw->lcw_lock); /* still hold lcw_pending_timers_lock */ continue; } cfs_list_del_init(&lcw->lcw_list); lcw->lcw_refcount--; /* -1 ref for pending list */ cfs_spin_unlock_bh(&lcw_pending_timers_lock); cfs_spin_unlock_bh(&lcw->lcw_lock); CDEBUG(D_INFO, "found lcw for pid " LPPID "\n", lcw->lcw_pid); lcw_dump_stack(lcw); is_dumplog = lcw->lcw_callback == lc_watchdog_dumplog; if (lcw->lcw_state != LC_WATCHDOG_DISABLED && (dumplog || !is_dumplog)) { lcw->lcw_callback(lcw->lcw_pid, lcw->lcw_data); if (dumplog && is_dumplog) dumplog = 0; } cfs_spin_lock_bh(&lcw_pending_timers_lock); lcw->lcw_refcount--; /* -1 ref for callback */ if (lcw->lcw_refcount == 0) cfs_list_add(&lcw->lcw_list, &zombies); } cfs_spin_unlock_bh(&lcw_pending_timers_lock); while (!cfs_list_empty(&zombies)) { lcw = cfs_list_entry(lcw_pending_timers.next, struct lc_watchdog, lcw_list); cfs_list_del(&lcw->lcw_list); LIBCFS_FREE(lcw, sizeof(*lcw)); } } cfs_complete(&lcw_stop_completion); RETURN(rc); }
static int lcw_dispatch_main(void *data) { int rc = 0; struct lc_watchdog *lcw; struct list_head zombies = LIST_HEAD_INIT(zombies); ENTRY; complete(&lcw_start_completion); while (1) { int dumplog = 1; rc = wait_event_interruptible(lcw_event_waitq, is_watchdog_fired()); CDEBUG(D_INFO, "Watchdog got woken up...\n"); if (test_bit(LCW_FLAG_STOP, &lcw_flags)) { CDEBUG(D_INFO, "LCW_FLAG_STOP set, shutting down...\n"); spin_lock_bh(&lcw_pending_timers_lock); rc = !list_empty(&lcw_pending_timers); spin_unlock_bh(&lcw_pending_timers_lock); if (rc) { CERROR("pending timers list was not empty at " "time of watchdog dispatch shutdown\n"); } break; } spin_lock_bh(&lcw_pending_timers_lock); while (!list_empty(&lcw_pending_timers)) { int is_dumplog; lcw = list_entry(lcw_pending_timers.next, struct lc_watchdog, lcw_list); /* +1 ref for callback to make sure lwc wouldn't be * deleted after releasing lcw_pending_timers_lock */ lcw->lcw_refcount++; spin_unlock_bh(&lcw_pending_timers_lock); /* lock ordering */ spin_lock_bh(&lcw->lcw_lock); spin_lock_bh(&lcw_pending_timers_lock); if (list_empty(&lcw->lcw_list)) { /* already removed from pending list */ lcw->lcw_refcount--; /* -1 ref for callback */ if (lcw->lcw_refcount == 0) list_add(&lcw->lcw_list, &zombies); spin_unlock_bh(&lcw->lcw_lock); /* still hold lcw_pending_timers_lock */ continue; } list_del_init(&lcw->lcw_list); lcw->lcw_refcount--; /* -1 ref for pending list */ spin_unlock_bh(&lcw_pending_timers_lock); spin_unlock_bh(&lcw->lcw_lock); CDEBUG(D_INFO, "found lcw for pid " LPPID "\n", lcw->lcw_pid); lcw_dump_stack(lcw); is_dumplog = lcw->lcw_callback == lc_watchdog_dumplog; if (lcw->lcw_state != LC_WATCHDOG_DISABLED && (dumplog || !is_dumplog)) { lcw->lcw_callback(lcw->lcw_pid, lcw->lcw_data); if (dumplog && is_dumplog) dumplog = 0; } spin_lock_bh(&lcw_pending_timers_lock); lcw->lcw_refcount--; /* -1 ref for callback */ if (lcw->lcw_refcount == 0) list_add(&lcw->lcw_list, &zombies); } spin_unlock_bh(&lcw_pending_timers_lock); while (!list_empty(&zombies)) { lcw = list_entry(zombies.next, struct lc_watchdog, lcw_list); list_del_init(&lcw->lcw_list); LIBCFS_FREE(lcw, sizeof(*lcw)); } } complete(&lcw_stop_completion); RETURN(rc); }