X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fldlm%2Fldlm_extent.c;h=c2c1e256c9be893b843ee736fe7282afe203a453;hb=ff17cc7e0282d9b1522810e0c5d12171c4d46a2d;hp=32fb89de20eafd5a4fafd238e8c58b0cafc2e30b;hpb=fe79e1b3a463c6ff8d6a8c8be2b9505df5a5702a;p=fs%2Flustre-release.git diff --git a/lustre/ldlm/ldlm_extent.c b/lustre/ldlm/ldlm_extent.c index 32fb89d..c2c1e25 100644 --- a/lustre/ldlm/ldlm_extent.c +++ b/lustre/ldlm/ldlm_extent.c @@ -36,67 +36,101 @@ * - the maximum extent * - containing the requested extent * - and not overlapping existing conflicting extents outside the requested one - * - * An alternative policy is to not shrink the new extent when conflicts exist */ + */ static void ldlm_extent_internal_policy(struct list_head *queue, struct ldlm_lock *req, struct ldlm_extent *new_ex) { struct list_head *tmp; ldlm_mode_t req_mode = req->l_req_mode; - __u64 req_start = req->l_policy_data.l_extent.start; - __u64 req_end = req->l_policy_data.l_extent.end; + __u64 req_start = req->l_req_extent.start; + __u64 req_end = req->l_req_extent.end; ENTRY; - if (new_ex->start == req_start && new_ex->end == req_end) { - EXIT; - return; - } + lockmode_verify(req_mode); list_for_each(tmp, queue) { 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; - if (req == lock) { + if (new_ex->start == req_start && new_ex->end == req_end) { EXIT; return; } - /* if lock doesn't overlap new_ex, skip it. */ - if (lock->l_policy_data.l_extent.end < new_ex->start || - lock->l_policy_data.l_extent.start > new_ex->end) + /* Don't conflict with ourselves */ + if (req == lock) + continue; + + /* If lock doesn't overlap new_ex, skip it. */ + if (l_extent->end < new_ex->start || + l_extent->start > new_ex->end) continue; /* Locks are compatible, overlap doesn't matter */ if (lockmode_compat(lock->l_req_mode, req_mode)) continue; - if (lock->l_policy_data.l_extent.start < req_start) { - if (lock->l_policy_data.l_extent.end == ~0) { + /* 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 (lock->l_req_extent.end >= req_start && + lock->l_req_extent.start <= req_end) + 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 the previous request. + * We don't grow downwards if there are lots of lockers. */ + if (l_extent->start < req_start) { + if (atomic_read(&req->l_resource->lr_refcount) > 20) new_ex->start = req_start; - new_ex->end = req_end; - EXIT; - return; - } - new_ex->start = min(lock->l_policy_data.l_extent.end+1, - req_start); + else + new_ex->start = min(l_extent->end+1, req_start); } - if (lock->l_policy_data.l_extent.end > req_end) { - if (lock->l_policy_data.l_extent.start == 0) { - new_ex->start = req_start; - new_ex->end = req_end; - EXIT; - return; - } - new_ex->end = MAX(lock->l_policy_data.l_extent.start-1, - req_end); + /* 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); } } EXIT; } -/* Determine if the lock is compatible with all locks on the queue. */ +/* 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 = ~0}; + + ldlm_extent_internal_policy(&res->lr_granted, lock, &new_ex); + ldlm_extent_internal_policy(&res->lr_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; + } +} + +/* Determine if the lock is compatible with all locks on the queue. + * We stop walking the queue if we hit ourselves so we don't take + * conflicting locks enqueued after us into accound, or we'd wait forever. */ static int ldlm_extent_compat_queue(struct list_head *queue, struct ldlm_lock *req, int send_cbs) @@ -104,11 +138,13 @@ ldlm_extent_compat_queue(struct list_head *queue, struct ldlm_lock *req, struct list_head *tmp; struct ldlm_lock *lock; ldlm_mode_t req_mode = req->l_req_mode; - __u64 req_start = req->l_policy_data.l_extent.start; - __u64 req_end = req->l_policy_data.l_extent.end; + __u64 req_start = req->l_req_extent.start; + __u64 req_end = req->l_req_extent.end; int compat = 1; ENTRY; + lockmode_verify(req_mode); + list_for_each(tmp, queue) { lock = list_entry(tmp, struct ldlm_lock, l_res_link); @@ -148,7 +184,6 @@ int ldlm_process_extent_lock(struct ldlm_lock *lock, int *flags, int first_enq, ldlm_error_t *err) { struct ldlm_resource *res = lock->l_resource; - struct ldlm_extent new_ex = {0, ~0}; struct list_head rpc_list = LIST_HEAD_INIT(rpc_list); int rc; ENTRY; @@ -165,22 +200,12 @@ int ldlm_process_extent_lock(struct ldlm_lock *lock, int *flags, int first_enq, RETURN(LDLM_ITER_STOP); ldlm_resource_unlink_lock(lock); + + ldlm_extent_policy(res, lock, flags); ldlm_grant_lock(lock, NULL, 0, 1); RETURN(LDLM_ITER_CONTINUE); } - /* In order to determine the largest possible extent we can - * grant, we need to scan all of the queues. */ - ldlm_extent_internal_policy(&res->lr_granted, lock, &new_ex); - ldlm_extent_internal_policy(&res->lr_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; - } - restart: LASSERT(res->lr_tmp == NULL); res->lr_tmp = &rpc_list; @@ -204,6 +229,7 @@ int ldlm_process_extent_lock(struct ldlm_lock *lock, int *flags, int first_enq, GOTO(restart, -ERESTART); *flags |= LDLM_FL_BLOCK_GRANTED; } else { + ldlm_extent_policy(res, lock, flags); ldlm_resource_unlink_lock(lock); ldlm_grant_lock(lock, NULL, 0, 0); }