+static cfs_timer_t waiting_locks_timer;
+
+static struct expired_lock_thread {
+ cfs_waitq_t elt_waitq;
+ int elt_state;
+ int elt_dump;
+ struct list_head elt_expired_locks;
+} expired_lock_thread;
+#endif
+
+#define ELT_STOPPED 0
+#define ELT_READY 1
+#define ELT_TERMINATE 2
+
+struct ldlm_bl_pool {
+ spinlock_t blp_lock;
+ struct list_head blp_list;
+ cfs_waitq_t blp_waitq;
+ struct completion blp_comp;
+ atomic_t blp_num_threads;
+ atomic_t blp_busy_threads;
+ int blp_min_threads;
+ int blp_max_threads;
+};
+
+struct ldlm_bl_work_item {
+ struct list_head blwi_entry;
+ struct ldlm_namespace *blwi_ns;
+ struct ldlm_lock_desc blwi_ld;
+ struct ldlm_lock *blwi_lock;
+ struct list_head blwi_head;
+ int blwi_count;
+};
+
+#ifdef __KERNEL__
+
+static inline int have_expired_locks(void)
+{
+ int need_to_run;
+
+ ENTRY;
+ spin_lock_bh(&waiting_locks_spinlock);
+ need_to_run = !list_empty(&expired_lock_thread.elt_expired_locks);
+ spin_unlock_bh(&waiting_locks_spinlock);
+
+ RETURN(need_to_run);
+}
+
+static int expired_lock_main(void *arg)
+{
+ struct list_head *expired = &expired_lock_thread.elt_expired_locks;
+ struct l_wait_info lwi = { 0 };
+ int do_dump;
+
+ ENTRY;
+ cfs_daemonize("ldlm_elt");
+
+ expired_lock_thread.elt_state = ELT_READY;
+ cfs_waitq_signal(&expired_lock_thread.elt_waitq);
+
+ while (1) {
+ l_wait_event(expired_lock_thread.elt_waitq,
+ have_expired_locks() ||
+ expired_lock_thread.elt_state == ELT_TERMINATE,
+ &lwi);
+
+ spin_lock_bh(&waiting_locks_spinlock);
+ if (expired_lock_thread.elt_dump) {
+ spin_unlock_bh(&waiting_locks_spinlock);
+
+ /* from waiting_locks_callback, but not in timer */
+ libcfs_debug_dumplog();
+ libcfs_run_lbug_upcall(__FILE__,
+ "waiting_locks_callback",
+ expired_lock_thread.elt_dump);
+
+ spin_lock_bh(&waiting_locks_spinlock);
+ expired_lock_thread.elt_dump = 0;
+ }
+
+ do_dump = 0;
+
+ while (!list_empty(expired)) {
+ struct obd_export *export;
+ struct ldlm_lock *lock;
+
+ lock = list_entry(expired->next, struct ldlm_lock,
+ l_pending_chain);
+ if ((void *)lock < LP_POISON + CFS_PAGE_SIZE &&
+ (void *)lock >= LP_POISON) {
+ spin_unlock_bh(&waiting_locks_spinlock);
+ CERROR("free lock on elt list %p\n", lock);
+ LBUG();
+ }
+ list_del_init(&lock->l_pending_chain);
+ if ((void *)lock->l_export < LP_POISON + CFS_PAGE_SIZE &&
+ (void *)lock->l_export >= LP_POISON) {
+ CERROR("lock with free export on elt list %p\n",
+ lock->l_export);
+ lock->l_export = NULL;
+ LDLM_ERROR(lock, "free export");
+ continue;
+ }
+ export = class_export_get(lock->l_export);
+ spin_unlock_bh(&waiting_locks_spinlock);
+
+ do_dump++;
+ class_fail_export(export);
+ class_export_put(export);
+ spin_lock_bh(&waiting_locks_spinlock);
+ }
+ spin_unlock_bh(&waiting_locks_spinlock);
+
+ if (do_dump && obd_dump_on_eviction) {
+ CERROR("dump the log upon eviction\n");
+ libcfs_debug_dumplog();
+ }
+
+ if (expired_lock_thread.elt_state == ELT_TERMINATE)
+ break;
+ }
+
+ expired_lock_thread.elt_state = ELT_STOPPED;
+ cfs_waitq_signal(&expired_lock_thread.elt_waitq);
+ RETURN(0);
+}