+ struct obd_export *exp = req->rq_export;
+ struct ldlm_reply *dlm_rep;
+ struct ldlm_lock *lock;
+ int rc;
+
+ ENTRY;
+
+ if (exp && exp->exp_nid_stats && exp->exp_nid_stats->nid_ldlm_stats)
+ lprocfs_counter_incr(exp->exp_nid_stats->nid_ldlm_stats,
+ LDLM_CONVERT - LDLM_FIRST_OPC);
+
+ rc = req_capsule_server_pack(&req->rq_pill);
+ if (rc)
+ RETURN(rc);
+
+ dlm_rep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
+ dlm_rep->lock_flags = dlm_req->lock_flags;
+
+ lock = ldlm_handle2lock(&dlm_req->lock_handle[0]);
+ if (lock) {
+ __u64 bits;
+ __u64 new;
+
+ bits = lock->l_policy_data.l_inodebits.bits;
+ new = dlm_req->lock_desc.l_policy_data.l_inodebits.bits;
+ LDLM_DEBUG(lock, "server-side convert handler START");
+
+ if (ldlm_is_cancel(lock)) {
+ LDLM_ERROR(lock, "convert on canceled lock!");
+ rc = ELDLM_NO_LOCK_DATA;
+ } else if (dlm_req->lock_desc.l_req_mode !=
+ lock->l_granted_mode) {
+ LDLM_ERROR(lock, "lock mode differs!");
+ rc = ELDLM_NO_LOCK_DATA;
+ } else if (bits == new) {
+ /*
+ * This can be valid situation if CONVERT RPCs are
+ * re-ordered. Just finish silently
+ */
+ LDLM_DEBUG(lock, "lock is converted already!");
+ rc = ELDLM_OK;
+ } else {
+ lock_res_and_lock(lock);
+ if (ldlm_is_waited(lock))
+ ldlm_del_waiting_lock(lock);
+
+ ldlm_clear_cbpending(lock);
+ lock->l_policy_data.l_inodebits.cancel_bits = 0;
+ ldlm_inodebits_drop(lock, bits & ~new);
+
+ ldlm_clear_blocking_data(lock);
+ unlock_res_and_lock(lock);
+
+ ldlm_reprocess_all(lock->l_resource, NULL);
+ rc = ELDLM_OK;
+ }
+
+ if (rc == ELDLM_OK) {
+ dlm_rep->lock_handle = lock->l_remote_handle;
+ ldlm_ibits_policy_local_to_wire(&lock->l_policy_data,
+ &dlm_rep->lock_desc.l_policy_data);
+ }
+
+ LDLM_DEBUG(lock, "server-side convert handler END, rc = %d",
+ rc);
+ LDLM_LOCK_PUT(lock);
+ } else {
+ rc = ELDLM_NO_LOCK_DATA;
+ LDLM_DEBUG_NOLOCK("server-side convert handler END, rc = %d",
+ rc);
+ }
+
+ req->rq_status = rc;