ldlm_extent.c
来自「lustre 1.6.5 source code」· C语言 代码 · 共 882 行 · 第 1/3 页
C
882 行
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (c) 2002, 2003 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. */#define DEBUG_SUBSYSTEM S_LDLM#ifndef __KERNEL__# include <liblustre.h>#endif#include <lustre_dlm.h>#include <obd_support.h>#include <obd.h>#include <lustre_lib.h>#include "ldlm_internal.h"#define LDLM_MAX_GROWN_EXTENT (32 * 1024 * 1024 - 1)/* fixup the ldlm_extent after expanding */static void ldlm_extent_internal_policy_fixup(struct ldlm_lock *req, struct ldlm_extent *new_ex, int conflicting){ ldlm_mode_t req_mode = req->l_req_mode; __u64 req_start = req->l_req_extent.start; __u64 req_end = req->l_req_extent.end; __u64 req_align, mask; if (conflicting > 32 && (req_mode == LCK_PW || req_mode == LCK_CW)) { if (req_end < req_start + LDLM_MAX_GROWN_EXTENT) new_ex->end = min(req_start + LDLM_MAX_GROWN_EXTENT, new_ex->end); } if (new_ex->start == 0 && new_ex->end == OBD_OBJECT_EOF) { EXIT; return; } /* we need to ensure that the lock extent is properly aligned to what * the client requested. We align it to the lowest-common denominator * of the clients requested lock start and end alignment. */ mask = 0x1000ULL; req_align = (req_end + 1) | req_start; if (req_align != 0) { while ((req_align & mask) == 0) mask <<= 1; } mask -= 1; /* We can only shrink the lock, not grow it. * This should never cause lock to be smaller than requested, * since requested lock was already aligned on these boundaries. */ new_ex->start = ((new_ex->start - 1) | mask) + 1; new_ex->end = ((new_ex->end + 1) & ~mask) - 1; LASSERTF(new_ex->start <= req_start, "mask "LPX64" grant start "LPU64" req start "LPU64"\n", mask, new_ex->start, req_start); LASSERTF(new_ex->end >= req_end, "mask "LPX64" grant end "LPU64" req end "LPU64"\n", mask, new_ex->end, req_end);}/* The purpose of this function is to return: * - the maximum extent * - containing the requested extent * - and not overlapping existing conflicting extents outside the requested one * * Use interval tree to expand the lock extent for granted lock. */static void ldlm_extent_internal_policy_granted(struct ldlm_lock *req, struct ldlm_extent *new_ex){ struct ldlm_resource *res = req->l_resource; ldlm_mode_t req_mode = req->l_req_mode; __u64 req_start = req->l_req_extent.start; __u64 req_end = req->l_req_extent.end; struct ldlm_interval_tree *tree; struct interval_node_extent limiter = { new_ex->start, new_ex->end }; int conflicting = 0; int idx; ENTRY; lockmode_verify(req_mode); /* using interval tree to handle the ldlm extent granted locks */ for (idx = 0; idx < LCK_MODE_NUM; idx++) { struct interval_node_extent ext = { req_start, req_end }; tree = &res->lr_itree[idx]; if (lockmode_compat(tree->lit_mode, req_mode)) continue; conflicting += tree->lit_size; if (conflicting > 4) limiter.start = req_start; if (interval_is_overlapped(tree->lit_root, &ext)) printk("req_mode = %d, tree->lit_mode = %d, tree->lit_size = %d\n", req_mode, tree->lit_mode, tree->lit_size); interval_expand(tree->lit_root, &ext, &limiter); limiter.start = max(limiter.start, ext.start); limiter.end = min(limiter.end, ext.end); if (limiter.start == req_start && limiter.end == req_end) break; } new_ex->start = limiter.start; new_ex->end = limiter.end; LASSERT(new_ex->start <= req_start); LASSERT(new_ex->end >= req_end); ldlm_extent_internal_policy_fixup(req, new_ex, conflicting); EXIT;}/* The purpose of this function is to return: * - the maximum extent * - containing the requested extent * - and not overlapping existing conflicting extents outside the requested one */static voidldlm_extent_internal_policy_waiting(struct ldlm_lock *req, struct ldlm_extent *new_ex){ struct list_head *tmp; struct ldlm_resource *res = req->l_resource; ldlm_mode_t req_mode = req->l_req_mode; __u64 req_start = req->l_req_extent.start; __u64 req_end = req->l_req_extent.end; int conflicting = 0; ENTRY; lockmode_verify(req_mode); /* for waiting locks */ list_for_each(tmp, &res->lr_waiting) { struct ldlm_lock *lock; struct ldlm_extent *l_extent; lock = list_entry(tmp, struct ldlm_lock, l_res_link); l_extent = &lock->l_policy_data.l_extent; /* We already hit the minimum requested size, search no more */ if (new_ex->start == req_start && new_ex->end == req_end) { EXIT; return; } /* Don't conflict with ourselves */ if (req == lock) continue; /* Locks are compatible, overlap doesn't matter */ /* Until bug 20 is fixed, try to avoid granting overlapping * locks on one client (they take a long time to cancel) */ if (lockmode_compat(lock->l_req_mode, req_mode) && lock->l_export != req->l_export) continue; /* If this is a high-traffic lock, don't grow downwards at all * or grow upwards too much */ ++conflicting; if (conflicting > 4) new_ex->start = req_start; /* If lock doesn't overlap new_ex, skip it. */ if (!ldlm_extent_overlap(l_extent, new_ex)) continue; /* Locks conflicting in requested extents and we can't satisfy * both locks, so ignore it. Either we will ping-pong this * extent (we would regardless of what extent we granted) or * lock is unused and it shouldn't limit our extent growth. */ if (ldlm_extent_overlap(&lock->l_req_extent,&req->l_req_extent)) continue; /* We grow extents downwards only as far as they don't overlap * with already-granted locks, on the assumtion that clients * will be writing beyond the initial requested end and would * then need to enqueue a new lock beyond previous request. * l_req_extent->end strictly < req_start, checked above. */ if (l_extent->start < req_start && new_ex->start != req_start) { if (l_extent->end >= req_start) new_ex->start = req_start; else new_ex->start = min(l_extent->end+1, req_start); } /* If we need to cancel this lock anyways because our request * overlaps the granted lock, we grow up to its requested * extent start instead of limiting this extent, assuming that * clients are writing forwards and the lock had over grown * its extent downwards before we enqueued our request. */ if (l_extent->end > req_end) { if (l_extent->start <= req_end) new_ex->end = max(lock->l_req_extent.start - 1, req_end); else new_ex->end = max(l_extent->start - 1, req_end); } } ldlm_extent_internal_policy_fixup(req, new_ex, conflicting); EXIT;}/* In order to determine the largest possible extent we can grant, we need * to scan all of the queues. */static void ldlm_extent_policy(struct ldlm_resource *res, struct ldlm_lock *lock, int *flags){ struct ldlm_extent new_ex = { .start = 0, .end = OBD_OBJECT_EOF }; if (lock->l_export == NULL) /* * this is local lock taken by server (e.g., as a part of * OST-side locking, or unlink handling). Expansion doesn't * make a lot of sense for local locks, because they are * dropped immediately on operation completion and would only * conflict with other threads. */ return; if (lock->l_policy_data.l_extent.start == 0 && lock->l_policy_data.l_extent.end == OBD_OBJECT_EOF) /* fast-path whole file locks */ return; ldlm_extent_internal_policy_granted(lock, &new_ex); ldlm_extent_internal_policy_waiting(lock, &new_ex); if (new_ex.start != lock->l_policy_data.l_extent.start || new_ex.end != lock->l_policy_data.l_extent.end) { *flags |= LDLM_FL_LOCK_CHANGED; lock->l_policy_data.l_extent.start = new_ex.start; lock->l_policy_data.l_extent.end = new_ex.end; }}static int ldlm_check_contention(struct ldlm_lock *lock, int contended_locks){ struct ldlm_resource *res = lock->l_resource; cfs_time_t now = cfs_time_current(); CDEBUG(D_DLMTRACE, "contended locks = %d\n", contended_locks); if (contended_locks > res->lr_namespace->ns_contended_locks) res->lr_contention_time = now; return cfs_time_before(now, cfs_time_add(res->lr_contention_time, cfs_time_seconds(res->lr_namespace->ns_contention_time)));}struct ldlm_extent_compat_args { struct list_head *work_list; struct ldlm_lock *lock; ldlm_mode_t mode; int *locks; int *compat;};static enum interval_iter ldlm_extent_compat_cb(struct interval_node *n, void *data){ struct ldlm_extent_compat_args *priv = data; struct ldlm_interval *node = to_ldlm_interval(n); struct ldlm_extent *extent; struct list_head *work_list = priv->work_list; struct ldlm_lock *lock, *enq = priv->lock; ldlm_mode_t mode = priv->mode; int count = 0; ENTRY;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?