ldlm_lockd.c
来自「lustre 1.6.5 source code」· C语言 代码 · 共 1,721 行 · 第 1/5 页
C
1,721 行
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (C) 2002-2004 Cluster File Systems, Inc. * Author: Peter Braam <braam@clusterfs.com> * Author: Phil Schwan <phil@clusterfs.com> * * This file is part of the Lustre file system, http://www.lustre.org * Lustre is a trademark of Cluster File Systems, Inc. * * You may have signed or agreed to another license before downloading * this software. If so, you are bound by the terms and conditions * of that agreement, and the following does not apply to you. See the * LICENSE file included with this distribution for more information. * * If you did not agree to a different license, then this copy of Lustre * is open source software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * In either case, Lustre is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * license text for more details. */#ifndef EXPORT_SYMTAB# define EXPORT_SYMTAB#endif#define DEBUG_SUBSYSTEM S_LDLM#ifdef __KERNEL__# include <libcfs/libcfs.h>#else# include <liblustre.h>#endif#include <lustre_dlm.h>#include <obd_class.h>#include <libcfs/list.h>#include "ldlm_internal.h"#ifdef __KERNEL__static int ldlm_num_threads;CFS_MODULE_PARM(ldlm_num_threads, "i", int, 0444, "number of DLM service threads to start");#endifextern cfs_mem_cache_t *ldlm_resource_slab;extern cfs_mem_cache_t *ldlm_lock_slab;extern struct lustre_lock ldlm_handle_lock;static struct semaphore ldlm_ref_sem;static int ldlm_refcount;static struct ldlm_state *ldlm_state;inline cfs_time_t round_timeout(cfs_time_t timeout){ return cfs_time_seconds((int)cfs_duration_sec(cfs_time_sub(timeout, 0)) + 1);}/* timeout for initial callback (AST) reply (bz10399) */static inline unsigned int ldlm_get_rq_timeout(void){ /* Non-AT value */ unsigned int timeout = min(ldlm_timeout, obd_timeout / 3); return timeout < 1 ? 1 : timeout;}#ifdef __KERNEL__/* w_l_spinlock protects both waiting_locks_list and expired_lock_thread */static spinlock_t waiting_locks_spinlock; /* BH lock (timer) */static struct list_head waiting_locks_list;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 2struct ldlm_bl_pool { spinlock_t blp_lock; /* * blp_prio_list is used for callbacks that should be handled * as a priority. It is used for LDLM_FL_DISCARD_DATA requests. * see bug 13843 */ struct list_head blp_prio_list; /* * blp_list is used for all other callbacks which are likely * to take longer to process. */ 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);}/* This is called from within a timer interrupt and cannot schedule */static void waiting_locks_callback(unsigned long unused){ struct ldlm_lock *lock, *last = NULL; spin_lock_bh(&waiting_locks_spinlock); while (!list_empty(&waiting_locks_list)) { lock = list_entry(waiting_locks_list.next, struct ldlm_lock, l_pending_chain); if (cfs_time_after(lock->l_callback_timeout, cfs_time_current()) || (lock->l_req_mode == LCK_GROUP)) break; LDLM_ERROR(lock, "lock callback timer expired after %lds: " "evicting client at %s ", cfs_time_current_sec()- lock->l_enqueued_time.tv_sec, libcfs_nid2str( lock->l_export->exp_connection->c_peer.nid)); if (lock == last) { LDLM_ERROR(lock, "waiting on lock multiple times"); CERROR("wll %p n/p %p/%p, l_pending %p n/p %p/%p\n", &waiting_locks_list, waiting_locks_list.next, waiting_locks_list.prev, &lock->l_pending_chain, lock->l_pending_chain.next, lock->l_pending_chain.prev); CFS_INIT_LIST_HEAD(&waiting_locks_list); /* HACK */ expired_lock_thread.elt_dump = __LINE__; /* LBUG(); */ CEMERG("would be an LBUG, but isn't (bug 5653)\n"); libcfs_debug_dumpstack(NULL); /*blocks* libcfs_debug_dumplog(); */ /*blocks* libcfs_run_lbug_upcall(file, func, line); */ break; } last = lock; list_del(&lock->l_pending_chain); list_add(&lock->l_pending_chain, &expired_lock_thread.elt_expired_locks); } if (!list_empty(&expired_lock_thread.elt_expired_locks)) { if (obd_dump_on_timeout) expired_lock_thread.elt_dump = __LINE__; cfs_waitq_signal(&expired_lock_thread.elt_waitq); } /* * Make sure the timer will fire again if we have any locks * left. */ if (!list_empty(&waiting_locks_list)) { cfs_time_t timeout_rounded; lock = list_entry(waiting_locks_list.next, struct ldlm_lock, l_pending_chain); timeout_rounded = (cfs_time_t)round_timeout(lock->l_callback_timeout); cfs_timer_arm(&waiting_locks_timer, timeout_rounded); } spin_unlock_bh(&waiting_locks_spinlock);}/* * Indicate that we're waiting for a client to call us back cancelling a given * lock. We add it to the pending-callback chain, and schedule the lock-timeout * timer to fire appropriately. (We round up to the next second, to avoid * floods of timer firings during periods of high lock contention and traffic). * * Called with the namespace lock held. */static int __ldlm_add_waiting_lock(struct ldlm_lock *lock){ int timeout; cfs_time_t timeout_rounded; if (!list_empty(&lock->l_pending_chain)) return 0; timeout = ldlm_get_enq_timeout(lock); lock->l_callback_timeout = cfs_time_shift(timeout); timeout_rounded = round_timeout(lock->l_callback_timeout); if (cfs_time_before(timeout_rounded, cfs_timer_deadline(&waiting_locks_timer)) || !cfs_timer_is_armed(&waiting_locks_timer)) { cfs_timer_arm(&waiting_locks_timer, timeout_rounded); } /* if the new lock has a shorter timeout than something earlier on the list, we'll wait the longer amount of time; no big deal. */ list_add_tail(&lock->l_pending_chain, &waiting_locks_list); /* FIFO */ return 1;}static int ldlm_add_waiting_lock(struct ldlm_lock *lock){ int ret; LASSERT(!(lock->l_flags & LDLM_FL_CANCEL_ON_BLOCK)); spin_lock_bh(&waiting_locks_spinlock); if (lock->l_destroyed) { static cfs_time_t next; spin_unlock_bh(&waiting_locks_spinlock); LDLM_ERROR(lock, "not waiting on destroyed lock (bug 5653)"); if (cfs_time_after(cfs_time_current(), next)) { next = cfs_time_shift(14400); libcfs_debug_dumpstack(NULL); } return 0; } ret = __ldlm_add_waiting_lock(lock); spin_unlock_bh(&waiting_locks_spinlock); LDLM_DEBUG(lock, "%sadding to wait list", ret == 0 ? "not re-" : ""); return ret;}/* * Remove a lock from the pending list, likely because it had its cancellation * callback arrive without incident. This adjusts the lock-timeout timer if * needed. Returns 0 if the lock wasn't pending after all, 1 if it was. *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?