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 <liang@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
int is_replay = *flags & LDLM_FL_REPLAY;
struct ldlm_lock *lock;
struct ldlm_reply *reply;
int is_replay = *flags & LDLM_FL_REPLAY;
struct ldlm_lock *lock;
struct ldlm_reply *reply;
+ struct ost_lvb *tmplvb;
int cleanup_phase = 1;
ENTRY;
int cleanup_phase = 1;
ENTRY;
if (reply == NULL)
rc = -EPROTO;
if (lvb_len) {
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);
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);
&RMF_DLM_LVB);
if (tmplvb == NULL)
GOTO(cleanup, rc = -EPROTO);
/* If the lock has already been granted by a completion AST, don't
* clobber the LVB with an older one. */
/* 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);