static int osc_lock_unuse(const struct lu_env *env, const struct cl_lock_slice *slice) { struct osc_lock *ols = cl2osc_lock(slice); LINVRNT(osc_lock_invariant(ols)); switch (ols->ols_state) { case OLS_NEW: LASSERT(!ols->ols_hold); LASSERT(ols->ols_agl); return 0; case OLS_UPCALL_RECEIVED: osc_lock_unhold(ols); case OLS_ENQUEUED: LASSERT(!ols->ols_hold); osc_lock_detach(env, ols); ols->ols_state = OLS_NEW; return 0; case OLS_GRANTED: LASSERT(!ols->ols_glimpse); LASSERT(ols->ols_hold); /* * Move lock into OLS_RELEASED state before calling * osc_cancel_base() so that possible synchronous cancellation * (that always happens e.g., for liblustre) sees that lock is * released. */ ols->ols_state = OLS_RELEASED; return osc_lock_unhold(ols); default: CERROR("Impossible state: %d\n", ols->ols_state); LBUG(); } }
void osc_lock_fini(const struct lu_env *env, struct cl_lock_slice *slice) { struct osc_lock *ols = cl2osc_lock(slice); LINVRNT(osc_lock_invariant(ols)); LASSERT(ols->ols_dlmlock == NULL); OBD_SLAB_FREE_PTR(ols, osc_lock_kmem); }
static void osc_lock_granted(const struct lu_env *env, struct osc_lock *oscl, struct lustre_handle *lockh, bool lvb_update) { struct ldlm_lock *dlmlock; dlmlock = ldlm_handle2lock_long(lockh, 0); LASSERT(dlmlock); /* lock reference taken by ldlm_handle2lock_long() is * owned by osc_lock and released in osc_lock_detach() */ lu_ref_add(&dlmlock->l_reference, "osc_lock", oscl); oscl->ols_has_ref = 1; LASSERT(!oscl->ols_dlmlock); oscl->ols_dlmlock = dlmlock; /* This may be a matched lock for glimpse request, do not hold * lock reference in that case. */ if (!oscl->ols_glimpse) { /* hold a refc for non glimpse lock which will * be released in osc_lock_cancel() */ lustre_handle_copy(&oscl->ols_handle, lockh); ldlm_lock_addref(lockh, oscl->ols_einfo.ei_mode); oscl->ols_hold = 1; } /* Lock must have been granted. */ lock_res_and_lock(dlmlock); if (dlmlock->l_granted_mode == dlmlock->l_req_mode) { struct ldlm_extent *ext = &dlmlock->l_policy_data.l_extent; struct cl_lock_descr *descr = &oscl->ols_cl.cls_lock->cll_descr; /* extend the lock extent, otherwise it will have problem when * we decide whether to grant a lockless lock. */ descr->cld_mode = osc_ldlm2cl_lock(dlmlock->l_granted_mode); descr->cld_start = cl_index(descr->cld_obj, ext->start); descr->cld_end = cl_index(descr->cld_obj, ext->end); descr->cld_gid = ext->gid; /* no lvb update for matched lock */ if (lvb_update) { LASSERT(oscl->ols_flags & LDLM_FL_LVB_READY); osc_lock_lvb_update(env, cl2osc(oscl->ols_cl.cls_obj), dlmlock, NULL); } LINVRNT(osc_lock_invariant(oscl)); } unlock_res_and_lock(dlmlock); LASSERT(oscl->ols_state != OLS_GRANTED); oscl->ols_state = OLS_GRANTED; }
static void osc_lock_fini(const struct lu_env *env, struct cl_lock_slice *slice) { struct osc_lock *ols = cl2osc_lock(slice); LINVRNT(osc_lock_invariant(ols)); LASSERT(!ols->ols_dlmlock); kmem_cache_free(osc_lock_kmem, ols); }
static void osc_lock_fini(const struct lu_env *env, struct cl_lock_slice *slice) { struct osc_lock *ols = cl2osc_lock(slice); LINVRNT(osc_lock_invariant(ols)); /* * ->ols_hold can still be true at this point if, for example, a * thread that requested a lock was killed (and released a reference * to the lock), before reply from a server was received. In this case * lock is destroyed immediately after upcall. */ osc_lock_unhold(ols); LASSERT(ols->ols_lock == NULL); LASSERT(atomic_read(&ols->ols_pageref) == 0 || atomic_read(&ols->ols_pageref) == _PAGEREF_MAGIC); OBD_SLAB_FREE_PTR(ols, osc_lock_kmem); }
/** * Called when a lock is granted, from an upcall (when server returned a * granted lock), or from completion AST, when server returned a blocked lock. * * Called under lock and resource spin-locks, that are released temporarily * here. */ static void osc_lock_granted(const struct lu_env *env, struct osc_lock *olck, struct ldlm_lock *dlmlock, int rc) { struct ldlm_extent *ext; struct cl_lock *lock; struct cl_lock_descr *descr; LASSERT(dlmlock->l_granted_mode == dlmlock->l_req_mode); ENTRY; if (olck->ols_state < OLS_GRANTED) { lock = olck->ols_cl.cls_lock; ext = &dlmlock->l_policy_data.l_extent; descr = &osc_env_info(env)->oti_descr; descr->cld_obj = lock->cll_descr.cld_obj; /* XXX check that ->l_granted_mode is valid. */ descr->cld_mode = osc_ldlm2cl_lock(dlmlock->l_granted_mode); descr->cld_start = cl_index(descr->cld_obj, ext->start); descr->cld_end = cl_index(descr->cld_obj, ext->end); descr->cld_gid = ext->gid; /* * tell upper layers the extent of the lock that was actually * granted */ olck->ols_state = OLS_GRANTED; osc_lock_lvb_update(env, olck, rc); /* release DLM spin-locks to allow cl_lock_{modify,signal}() * to take a semaphore on a parent lock. This is safe, because * spin-locks are needed to protect consistency of * dlmlock->l_*_mode and LVB, and we have finished processing * them. */ unlock_res_and_lock(dlmlock); cl_lock_modify(env, lock, descr); cl_lock_signal(env, lock); LINVRNT(osc_lock_invariant(olck)); lock_res_and_lock(dlmlock); } EXIT; }
/** * Helper for osc_dlm_blocking_ast() handling discrepancies between cl_lock * and ldlm_lock caches. */ static int osc_dlm_blocking_ast0(const struct lu_env *env, struct ldlm_lock *dlmlock, void *data, int flag) { struct osc_lock *olck; struct cl_lock *lock; int result; int cancel; LASSERT(flag == LDLM_CB_BLOCKING || flag == LDLM_CB_CANCELING); cancel = 0; olck = osc_ast_data_get(dlmlock); if (olck != NULL) { lock = olck->ols_cl.cls_lock; cl_lock_mutex_get(env, lock); LINVRNT(osc_lock_invariant(olck)); if (olck->ols_ast_wait) { /* wake up osc_lock_use() */ cl_lock_signal(env, lock); olck->ols_ast_wait = 0; } /* * Lock might have been canceled while this thread was * sleeping for lock mutex, but olck is pinned in memory. */ if (olck == dlmlock->l_ast_data) { /* * NOTE: DLM sends blocking AST's for failed locks * (that are still in pre-OLS_GRANTED state) * too, and they have to be canceled otherwise * DLM lock is never destroyed and stuck in * the memory. * * Alternatively, ldlm_cli_cancel() can be * called here directly for osc_locks with * ols_state < OLS_GRANTED to maintain an * invariant that ->clo_cancel() is only called * for locks that were granted. */ LASSERT(data == olck); osc_lock_blocking(env, dlmlock, olck, flag == LDLM_CB_BLOCKING); } else cancel = 1; cl_lock_mutex_put(env, lock); osc_ast_data_put(env, olck); } else /* * DLM lock exists, but there is no cl_lock attached to it. * This is a `normal' race. cl_object and its cl_lock's can be * removed by memory pressure, together with all pages. */ cancel = (flag == LDLM_CB_BLOCKING); if (cancel) { struct lustre_handle *lockh; lockh = &osc_env_info(env)->oti_handle; ldlm_lock2handle(dlmlock, lockh); result = ldlm_cli_cancel(lockh, LCF_ASYNC); } else result = 0; return result; }