X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fldlm%2Fldlm_flock.c;h=b3b2cb1cff545429cb8f07bcf5d162ed3e56bc75;hb=510b04494f3271675da53048f5987867e507f083;hp=1b2d3ebbbb660b96dca5f54e8d1a786b8847ae90;hpb=ecfb27dded64df5ea1ebdccc40da53206920c984;p=fs%2Flustre-release.git diff --git a/lustre/ldlm/ldlm_flock.c b/lustre/ldlm/ldlm_flock.c index 1b2d3eb..b3b2cb1 100644 --- a/lustre/ldlm/ldlm_flock.c +++ b/lustre/ldlm/ldlm_flock.c @@ -71,10 +71,10 @@ int ldlm_flock_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, /** * list_for_remaining_safe - iterate over the remaining entries in a list * and safeguard against removal of a list entry. - * @pos: the &struct list_head to use as a loop counter. pos MUST + * \param pos the &struct list_head to use as a loop counter. pos MUST * have been initialized prior to using it in this macro. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. + * \param n another &struct list_head to use as temporary storage + * \param head the head for your list. */ #define list_for_remaining_safe(pos, n, head) \ for (n = pos->next; pos != (head); pos = n, n = pos->next) @@ -108,10 +108,14 @@ ldlm_flock_destroy(struct ldlm_lock *lock, ldlm_mode_t mode, int flags) LASSERT(list_empty(&lock->l_flock_waitq)); list_del_init(&lock->l_res_link); - if (flags == LDLM_FL_WAIT_NOREPROC) { + if (flags == LDLM_FL_WAIT_NOREPROC && + !(lock->l_flags & LDLM_FL_FAILED)) { /* client side - set a flag to prevent sending a CANCEL */ lock->l_flags |= LDLM_FL_LOCAL_ONLY | LDLM_FL_CBPENDING; - ldlm_lock_decref_internal(lock, mode); + + /* when reaching here, it is under lock_res_and_lock(). Thus, + need call the nolock version of ldlm_lock_decref_internal*/ + ldlm_lock_decref_internal_nolock(lock, mode); } ldlm_lock_destroy_nolock(lock); @@ -164,6 +168,8 @@ ldlm_process_flock_lock(struct ldlm_lock *req, int *flags, int first_enq, int local = ns_is_client(ns); int added = (mode == LCK_NL); int overlaps = 0; + int splitted = 0; + const struct ldlm_callback_suite null_cbs = { NULL }; ENTRY; CDEBUG(D_DLMTRACE, "flags %#x pid %u mode %u start "LPU64" end "LPU64 @@ -182,6 +188,7 @@ ldlm_process_flock_lock(struct ldlm_lock *req, int *flags, int first_enq, req->l_blocking_ast = ldlm_flock_blocking_ast; } +reprocess: if ((*flags == LDLM_FL_WAIT_NOREPROC) || (mode == LCK_NL)) { /* This loop determines where this processes locks start * in the resource lr_granted list. */ @@ -365,15 +372,23 @@ ldlm_process_flock_lock(struct ldlm_lock *req, int *flags, int first_enq, /* XXX - if ldlm_lock_new() can sleep we should * release the ns_lock, allocate the new lock, * and restart processing this lock. */ - new2 = ldlm_lock_create(ns, &res->lr_name, LDLM_FLOCK, - lock->l_granted_mode, NULL, NULL, NULL, - NULL, 0); if (!new2) { - ldlm_flock_destroy(req, lock->l_granted_mode, *flags); - *err = -ENOLCK; - RETURN(LDLM_ITER_STOP); + unlock_res_and_lock(req); + new2 = ldlm_lock_create(ns, &res->lr_name, LDLM_FLOCK, + lock->l_granted_mode, &null_cbs, + NULL, 0); + lock_res_and_lock(req); + if (!new2) { + ldlm_flock_destroy(req, lock->l_granted_mode, + *flags); + *err = -ENOLCK; + RETURN(LDLM_ITER_STOP); + } + goto reprocess; } + splitted = 1; + new2->l_granted_mode = lock->l_granted_mode; new2->l_policy_data.l_flock.pid = new->l_policy_data.l_flock.pid; @@ -385,21 +400,27 @@ ldlm_process_flock_lock(struct ldlm_lock *req, int *flags, int first_enq, new->l_policy_data.l_flock.end + 1; new2->l_conn_export = lock->l_conn_export; if (lock->l_export != NULL) { - new2->l_export = class_export_get(lock->l_export); - spin_lock(&new2->l_export->exp_ldlm_data.led_lock); - list_add(&new2->l_export_chain, - &new2->l_export->exp_ldlm_data.led_held_locks); - spin_unlock(&new2->l_export->exp_ldlm_data.led_lock); + new2->l_export = class_export_lock_get(lock->l_export); + if (new2->l_export->exp_lock_hash && + hlist_unhashed(&new2->l_exp_hash)) + lustre_hash_add(new2->l_export->exp_lock_hash, + &new2->l_remote_handle, + &new2->l_exp_hash); } if (*flags == LDLM_FL_WAIT_NOREPROC) - ldlm_lock_addref_internal(new2, lock->l_granted_mode); + ldlm_lock_addref_internal_nolock(new2, + lock->l_granted_mode); /* insert new2 at lock */ ldlm_resource_add_lock(res, ownlocks, new2); - LDLM_LOCK_PUT(new2); + LDLM_LOCK_RELEASE(new2); break; } + /* if new2 is created but never used, destroy it*/ + if (splitted == 0 && new2 != NULL) + ldlm_lock_destroy_nolock(new2); + /* At this point we're granting the lock request. */ req->l_granted_mode = req->l_req_mode; @@ -428,9 +449,10 @@ restart: ldlm_reprocess_queue(res, &res->lr_waiting, &rpc_list); - unlock_res(res); - rc = ldlm_run_ast_work(&rpc_list, LDLM_WORK_BL_AST); - lock_res(res); + unlock_res_and_lock(req); + rc = ldlm_run_ast_work(&rpc_list, + LDLM_WORK_CP_AST); + lock_res_and_lock(req); if (rc == -ERESTART) GOTO(restart, -ERESTART); } @@ -483,17 +505,26 @@ ldlm_flock_interrupted_wait(void *data) EXIT; } +/** + * Flock completion calback function. + * + * \param lock [in,out]: A lock to be handled + * \param flags [in]: flags + * \param *data [in]: ldlm_work_cp_ast_lock() will use ldlm_cb_set_arg + * + * \retval 0 : success + * \retval <0 : failure + */ int ldlm_flock_completion_ast(struct ldlm_lock *lock, int flags, void *data) { - struct ldlm_namespace *ns; - cfs_flock_t *getlk = lock->l_ast_data; - struct ldlm_flock_wait_data fwd; - struct obd_device *obd; - struct obd_import *imp = NULL; - ldlm_error_t err; - int rc = 0; - struct l_wait_info lwi; + cfs_flock_t *getlk = lock->l_ast_data; + struct obd_device *obd; + struct obd_import *imp = NULL; + struct ldlm_flock_wait_data fwd; + struct l_wait_info lwi; + ldlm_error_t err; + int rc = 0; ENTRY; CDEBUG(D_DLMTRACE, "flags: 0x%x data: %p getlk: %p\n", @@ -504,11 +535,12 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, int flags, void *data) * holding the lock even if app still believes it has it, since * server already dropped it anyway. Only for granted locks too. */ lock_res_and_lock(lock); - if ((lock->l_flags & (LDLM_FL_FAILED|LDLM_FL_LOCAL_ONLY)) == + if ((lock->l_flags & (LDLM_FL_FAILED|LDLM_FL_LOCAL_ONLY)) == (LDLM_FL_FAILED|LDLM_FL_LOCAL_ONLY)) { unlock_res_and_lock(lock); if (lock->l_req_mode == lock->l_granted_mode && - lock->l_granted_mode != LCK_NL) + lock->l_granted_mode != LCK_NL && + NULL == data) ldlm_lock_decref_internal(lock, lock->l_req_mode); RETURN(0); } @@ -517,20 +549,25 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, int flags, void *data) LASSERT(flags != LDLM_FL_WAIT_NOREPROC); if (!(flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED | - LDLM_FL_BLOCK_CONV))) - goto granted; + LDLM_FL_BLOCK_CONV))) { + if (NULL == data) + /* mds granted the lock in the reply */ + goto granted; + /* CP AST RPC: lock get granted, wake it up */ + cfs_waitq_signal(&lock->l_waitq); + RETURN(0); + } LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, " "sleeping"); - fwd.fwd_lock = lock; obd = class_exp2obd(lock->l_conn_export); - /* if this is a local lock, then there is no import */ - if (obd != NULL) + /* if this is a local lock, there is no import */ + if (NULL != obd) imp = obd->u.cli.cl_import; - if (imp != NULL) { + if (NULL != imp) { spin_lock(&imp->imp_lock); fwd.fwd_generation = imp->imp_generation; spin_unlock(&imp->imp_lock); @@ -539,28 +576,32 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, int flags, void *data) lwi = LWI_TIMEOUT_INTR(0, NULL, ldlm_flock_interrupted_wait, &fwd); /* Go to sleep until the lock is granted. */ - rc = l_wait_event(lock->l_waitq, - ((lock->l_req_mode == lock->l_granted_mode) || - lock->l_destroyed), &lwi); + rc = l_wait_event(lock->l_waitq, is_granted_or_cancelled(lock), &lwi); - LDLM_DEBUG(lock, "client-side enqueue waking up: rc = %d", rc); - RETURN(rc); + if (rc) { + LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)", + rc); + RETURN(rc); + } granted: OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT, 10); - LDLM_DEBUG(lock, "client-side enqueue granted"); - ns = lock->l_resource->lr_namespace; - lock_res(lock->l_resource); - /* before flock's complete ast gets here, the flock - * can possibly be freed by another thread - */ - if (lock->l_destroyed) { - LDLM_DEBUG(lock, "already destroyed by another thread"); + lock_res_and_lock(lock); + if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED) { + LDLM_DEBUG(lock, "client-side enqueue waking up: destroyed"); unlock_res(lock->l_resource); - RETURN(0); + RETURN(-EIO); + } + if (rc) { + LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)", + rc); + unlock_res_and_lock(lock); + RETURN(rc); } + LDLM_DEBUG(lock, "client-side enqueue granted"); + /* take lock off the deadlock detection waitq. */ spin_lock(&ldlm_flock_waitq_lock); list_del_init(&lock->l_flock_waitq); @@ -572,8 +613,9 @@ granted: if (flags & LDLM_FL_TEST_LOCK) { /* fcntl(F_GETLK) request */ /* The old mode was saved in getlk->fl_type so that if the mode - * in the lock changes we can decref the approprate refcount. */ - ldlm_flock_destroy(lock, cfs_flock_type(getlk), LDLM_FL_WAIT_NOREPROC); + * in the lock changes we can decref the appropriate refcount.*/ + ldlm_flock_destroy(lock, cfs_flock_type(getlk), + LDLM_FL_WAIT_NOREPROC); switch (lock->l_granted_mode) { case LCK_PR: cfs_flock_set_type(getlk, F_RDLCK); @@ -584,19 +626,20 @@ granted: default: cfs_flock_set_type(getlk, F_UNLCK); } - cfs_flock_set_pid(getlk, (pid_t)lock->l_policy_data.l_flock.pid); - cfs_flock_set_start(getlk, (loff_t)lock->l_policy_data.l_flock.start); - cfs_flock_set_end(getlk, (loff_t)lock->l_policy_data.l_flock.end); + cfs_flock_set_pid(getlk, + (pid_t)lock->l_policy_data.l_flock.pid); + cfs_flock_set_start(getlk, + (loff_t)lock->l_policy_data.l_flock.start); + cfs_flock_set_end(getlk, + (loff_t)lock->l_policy_data.l_flock.end); } else { int noreproc = LDLM_FL_WAIT_NOREPROC; /* We need to reprocess the lock to do merges or splits * with existing locks owned by this process. */ ldlm_process_flock_lock(lock, &noreproc, 1, &err, NULL); - if (flags == 0) - cfs_waitq_signal(&lock->l_waitq); } - unlock_res(lock->l_resource); + unlock_res_and_lock(lock); RETURN(0); } EXPORT_SYMBOL(ldlm_flock_completion_ast);