diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/ldlm/ldlm_flock.c')
-rw-r--r-- | drivers/staging/lustre/lustre/ldlm/ldlm_flock.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index c9aae132f98a..986bf384bff7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -205,6 +205,26 @@ ldlm_flock_deadlock(struct ldlm_lock *req, struct ldlm_lock *bl_lock) return 0; } +static void ldlm_flock_cancel_on_deadlock(struct ldlm_lock *lock, + struct list_head *work_list) +{ + CDEBUG(D_INFO, "reprocess deadlock req=%p\n", lock); + + if ((exp_connect_flags(lock->l_export) & + OBD_CONNECT_FLOCK_DEAD) == 0) { + CERROR( + "deadlock found, but client doesn't support flock canceliation\n"); + } else { + LASSERT(lock->l_completion_ast); + LASSERT((lock->l_flags & LDLM_FL_AST_SENT) == 0); + lock->l_flags |= LDLM_FL_AST_SENT | LDLM_FL_CANCEL_ON_BLOCK | + LDLM_FL_FLOCK_DEADLOCK; + ldlm_flock_blocking_unlink(lock); + ldlm_resource_unlink_lock(lock); + ldlm_add_ast_work_item(lock, NULL, work_list); + } +} + /** * Process a granting attempt for flock lock. * Must be called under ns lock held. @@ -272,6 +292,7 @@ reprocess: } } } else { + int reprocess_failed = 0; lockmode_verify(mode); /* This loop determines if there are existing locks @@ -293,8 +314,15 @@ reprocess: if (!ldlm_flocks_overlap(lock, req)) continue; - if (!first_enq) - return LDLM_ITER_CONTINUE; + if (!first_enq) { + reprocess_failed = 1; + if (ldlm_flock_deadlock(req, lock)) { + ldlm_flock_cancel_on_deadlock(req, + work_list); + return LDLM_ITER_CONTINUE; + } + continue; + } if (*flags & LDLM_FL_BLOCK_NOWAIT) { ldlm_flock_destroy(req, mode, *flags); @@ -330,6 +358,8 @@ reprocess: *flags |= LDLM_FL_BLOCK_GRANTED; return LDLM_ITER_STOP; } + if (reprocess_failed) + return LDLM_ITER_CONTINUE; } if (*flags & LDLM_FL_TEST_LOCK) { @@ -646,7 +676,10 @@ granted: /* ldlm_lock_enqueue() has already placed lock on the granted list. */ list_del_init(&lock->l_res_link); - if (flags & LDLM_FL_TEST_LOCK) { + if (lock->l_flags & LDLM_FL_FLOCK_DEADLOCK) { + LDLM_DEBUG(lock, "client-side enqueue deadlock received"); + rc = -EDEADLK; + } else 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 appropriate refcount.*/ @@ -672,7 +705,7 @@ granted: ldlm_process_flock_lock(lock, &noreproc, 1, &err, NULL); } unlock_res_and_lock(lock); - return 0; + return rc; } EXPORT_SYMBOL(ldlm_flock_completion_ast); |