+ ENTRY;
+
+ size = req_capsule_get_size(&req->rq_pill, &RMF_DLM_REQ, RCL_CLIENT);
+ if (size <= offsetof(struct ldlm_request, lock_handle) ||
+ (size - offsetof(struct ldlm_request, lock_handle)) /
+ sizeof(struct lustre_handle) < dlm_req->lock_count)
+ RETURN(0);
+
+ count = dlm_req->lock_count ? dlm_req->lock_count : 1;
+ if (first >= count)
+ RETURN(0);
+
+ if (count == 1 && dlm_req->lock_handle[0].cookie == 0)
+ RETURN(0);
+
+ /*
+ * There is no lock on the server at the replay time,
+ * skip lock cancelling to make replay tests to pass.
+ */
+ if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)
+ RETURN(0);
+
+ LDLM_DEBUG_NOLOCK("server-side cancel handler START: %d locks, starting at %d",
+ count, first);
+
+ for (i = first; i < count; i++) {
+ lock = ldlm_handle2lock(&dlm_req->lock_handle[i]);
+ if (!lock) {
+ /* below message checked in replay-single.sh test_36 */
+ LDLM_DEBUG_NOLOCK("server-side cancel handler stale lock (cookie %llu)",
+ dlm_req->lock_handle[i].cookie);
+ continue;
+ }
+
+ res = lock->l_resource;
+ done++;
+
+ /*
+ * This code is an optimization to only attempt lock
+ * granting on the resource (that could be CPU-expensive)
+ * after we are done cancelling lock in that resource.
+ */
+ if (res != pres) {
+ if (pres != NULL) {
+ ldlm_reprocess_all(pres, NULL);
+ LDLM_RESOURCE_DELREF(pres);
+ ldlm_resource_putref(pres);
+ }
+ if (res != NULL) {
+ ldlm_resource_getref(res);
+ LDLM_RESOURCE_ADDREF(res);
+
+ if (!ldlm_is_discard_data(lock))
+ ldlm_lvbo_update(res, lock,
+ NULL, 1);
+ }
+ pres = res;
+ }
+
+ if ((flags & LATF_STATS) && ldlm_is_ast_sent(lock) &&
+ lock->l_blast_sent != 0) {
+ time64_t delay = ktime_get_real_seconds() -
+ lock->l_blast_sent;
+ LDLM_DEBUG(lock,
+ "server cancels blocked lock after %llds",
+ (s64)delay);
+ at_measured(&lock->l_export->exp_bl_lock_at, delay);
+ }
+ ldlm_lock_cancel(lock);
+ LDLM_LOCK_PUT(lock);
+ }
+ if (pres != NULL) {
+ ldlm_reprocess_all(pres, NULL);
+ LDLM_RESOURCE_DELREF(pres);
+ ldlm_resource_putref(pres);
+ }
+ LDLM_DEBUG_NOLOCK("server-side cancel handler END");
+ RETURN(done);
+}
+EXPORT_SYMBOL(ldlm_request_cancel);
+
+/**
+ * Main LDLM entry point for server code to cancel locks.
+ *
+ * Typically gets called from service handler on LDLM_CANCEL opc.
+ */
+int ldlm_handle_cancel(struct ptlrpc_request *req)
+{
+ struct ldlm_request *dlm_req;
+ int rc;
+
+ ENTRY;
+
+ dlm_req = req_capsule_client_get(&req->rq_pill, &RMF_DLM_REQ);
+ if (dlm_req == NULL) {
+ CDEBUG(D_INFO, "bad request buffer for cancel\n");
+ RETURN(-EFAULT);
+ }
+
+ if (req_capsule_get_size(&req->rq_pill, &RMF_DLM_REQ, RCL_CLIENT) <
+ offsetof(struct ldlm_request, lock_handle[1]))
+ RETURN(-EPROTO);
+
+ if (req->rq_export && req->rq_export->exp_nid_stats &&
+ req->rq_export->exp_nid_stats->nid_ldlm_stats)
+ lprocfs_counter_incr(req->rq_export->exp_nid_stats->nid_ldlm_stats,
+ LDLM_CANCEL - LDLM_FIRST_OPC);
+
+ rc = req_capsule_server_pack(&req->rq_pill);
+ if (rc)
+ RETURN(rc);