From: Oleg Drokin Date: Fri, 11 Feb 2011 03:28:15 +0000 (-0500) Subject: b=24375 Fix lvb updating race in enqueue vs completion case X-Git-Tag: 2.0.59-llnl2-base~4 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=e70798ccca271c77a96494285c39f5141f6de8e0;ds=inline b=24375 Fix lvb updating race in enqueue vs completion case ldlm_enqueue_tail checked for lock mode and updated lvb without taking appropriate locks. Take res and lock around mode check and lvb updating. Issue: LU-67 Change-Id: I8fb764313326b8bf8f813e7cf77c050dd68afe45 Reviewed-on: http://review.whamcloud.com/229 Tested-by: Hudson Reviewed-by: Liang Zhen Reviewed-by: Andreas Dilger Reviewed-by: Alex Zhuravlev --- diff --git a/lustre/ldlm/ldlm_request.c b/lustre/ldlm/ldlm_request.c index de1885a..5d718c9 100644 --- a/lustre/ldlm/ldlm_request.c +++ b/lustre/ldlm/ldlm_request.c @@ -488,6 +488,7 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req, int is_replay = *flags & LDLM_FL_REPLAY; struct ldlm_lock *lock; struct ldlm_reply *reply; + struct ost_lvb *tmplvb; int cleanup_phase = 1; ENTRY; @@ -509,12 +510,11 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req, if (reply == NULL) rc = -EPROTO; if (lvb_len) { - struct ost_lvb *tmplvb; req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, lvb_len); - tmplvb = req_capsule_server_get(&req->rq_pill, + tmplvb = req_capsule_server_get(&req->rq_pill, &RMF_DLM_LVB); if (tmplvb == NULL) GOTO(cleanup, rc = -EPROTO); @@ -606,16 +606,25 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req, /* If the lock has already been granted by a completion AST, don't * clobber the LVB with an older one. */ - if (lvb_len && (lock->l_req_mode != lock->l_granted_mode)) { - void *tmplvb; + if (lvb_len) { + /* We must lock or a racing completion might update lvb + without letting us know and we'll clobber the correct value. + Cannot unlock after the check either, a that still leaves + a tiny window for completion to get in */ + lock_res_and_lock(lock); + if (lock->l_req_mode != lock->l_granted_mode) { - req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, - lvb_len); - tmplvb = req_capsule_server_get(&req->rq_pill, - &RMF_DLM_LVB); - if (tmplvb == NULL) - GOTO(cleanup, rc = -EPROTO); - memcpy(lock->l_lvb_data, tmplvb, lvb_len); + req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, + RCL_SERVER, lvb_len); + tmplvb = req_capsule_server_get(&req->rq_pill, + &RMF_DLM_LVB); + if (tmplvb == NULL) { + unlock_res_and_lock(lock); + GOTO(cleanup, rc = -EPROTO); + } + memcpy(lock->l_lvb_data, tmplvb, lvb_len); + } + unlock_res_and_lock(lock); } if (!is_replay) {