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 + -
显示快捷键?