+/* If first_enq is 0 (ie, called from ldlm_reprocess_queue):
+ * - blocking ASTs have already been sent
+ * - the caller has already initialized req->lr_tmp
+ * - must call this function with the ns lock held
+ *
+ * If first_enq is 1 (ie, called from ldlm_lock_enqueue):
+ * - blocking ASTs have not been sent
+ * - the caller has NOT initialized req->lr_tmp, so we must
+ * - must call this function with the ns lock held once */
+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 list_head rpc_list = LIST_HEAD_INIT(rpc_list);
+ int rc, rc2;
+ ENTRY;
+
+ LASSERT(list_empty(&res->lr_converting));
+ *err = ELDLM_OK;
+
+ if (!first_enq) {
+ /* Careful observers will note that we don't handle -EWOULDBLOCK
+ * here, but it's ok for a non-obvious reason -- compat_queue
+ * can only return -EWOULDBLOCK if (flags & BLOCK_NOWAIT).
+ * flags should always be zero here, and if that ever stops
+ * being true, we want to find out. */
+ LASSERT(*flags == 0);
+ LASSERT(res->lr_tmp != NULL);
+ rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 0, flags,
+ err);
+ if (rc == 1) {
+ rc = ldlm_extent_compat_queue(&res->lr_waiting, lock, 0,
+ flags, err);
+ }
+ if (rc == 0)
+ 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);
+ }
+
+ restart:
+ LASSERT(res->lr_tmp == NULL);
+ res->lr_tmp = &rpc_list;
+ rc = ldlm_extent_compat_queue(&res->lr_granted, lock, 1, flags, err);
+ if (rc < 0)
+ GOTO(out, rc); /* lock was destroyed */
+ if (rc == 2) {
+ res->lr_tmp = NULL;
+ goto grant;
+ }
+
+ rc2 = ldlm_extent_compat_queue(&res->lr_waiting, lock, 1, flags, err);
+ if (rc2 < 0)
+ GOTO(out, rc = rc2); /* lock was destroyed */
+ res->lr_tmp = NULL;
+
+ if (rc + rc2 == 2) {
+ grant:
+ ldlm_extent_policy(res, lock, flags);
+ ldlm_resource_unlink_lock(lock);
+ ldlm_grant_lock(lock, NULL, 0, 0);
+ } else {
+ /* If either of the compat_queue()s returned failure, then we
+ * have ASTs to send and must go onto the waiting list.
+ *
+ * bug 2322: we used to unlink and re-add here, which was a
+ * terrible folly -- if we goto restart, we could get
+ * re-ordered! Causes deadlock, because ASTs aren't sent! */
+ if (list_empty(&lock->l_res_link))
+ ldlm_resource_add_lock(res, &res->lr_waiting, lock);
+ l_unlock(&res->lr_namespace->ns_lock);
+ rc = ldlm_run_ast_work(res->lr_namespace, &rpc_list);
+ l_lock(&res->lr_namespace->ns_lock);
+ if (rc == -ERESTART)
+ GOTO(restart, -ERESTART);
+ *flags |= LDLM_FL_BLOCK_GRANTED;
+ }
+ rc = 0;
+out:
+ res->lr_tmp = NULL;
+ RETURN(rc);
+}
+
+/* When a lock is cancelled by a client, the KMS may undergo change if this
+ * is the "highest lock". This function returns the new KMS value.