This patch will change the handling if a plock operation was interrupted while waiting for a user space reply (probably dlm_controld). This is not while the posix lock waits in lock blocking state which is done by locks_lock_file_wait(). However the lock operation should be always interruptible, doesn't matter which wait is currently blocking the process.
If an interruption due waiting on a user space reply occurs the current behaviour is that we remove the already transmitted operation request to the user space from an list which is used to make a lookup if a reply comes back. This has as side effect that we see some: dev_write no op... in the kernel log because the lookup failed. This is easily reproducible by running: stress-ng --fcntl 100 and hitting strg-c afterwards. Instead of removing the op from the lookup list, we wait until the operation is completed. When the operation was completed we check if the wait was interrupted, if so we don't handle the request anymore and cleanup the original lock request. When there are still "dev_write no op" messages around it signals an issue that we removed an op while is hasn't been completed yet. This situation should never happen. Signed-off-by: Alexander Aring <aahri...@redhat.com> --- fs/dlm/plock.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index cf7bba461bfd..737f185aad8d 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -29,6 +29,8 @@ struct plock_async_data { struct plock_op { struct list_head list; int done; + /* if lock op got interrupted while waiting dlm_controld reply */ + bool sigint; struct dlm_plock_info info; /* if set indicates async handling */ struct plock_async_data *data; @@ -157,16 +159,24 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, rv = wait_event_interruptible(recv_wq, (op->done != 0)); if (rv == -ERESTARTSYS) { spin_lock(&ops_lock); - list_del(&op->list); + /* recheck under ops_lock if we got a done != 0, + * if so this interrupt case should be ignored + */ + if (op->done != 0) { + spin_unlock(&ops_lock); + goto do_lock_wait; + } + + op->sigint = true; spin_unlock(&ops_lock); log_debug(ls, "%s: wait interrupted %x %llx pid %d", __func__, ls->ls_global_id, (unsigned long long)number, op->info.pid); - dlm_release_plock_op(op); - do_unlock_close(&op->info); goto out; } +do_lock_wait: + WARN_ON(!list_empty(&op->list)); rv = op->info.rv; @@ -421,6 +431,19 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, if (iter->info.fsid == info.fsid && iter->info.number == info.number && iter->info.owner == info.owner) { + if (iter->sigint) { + list_del(&iter->list); + spin_unlock(&ops_lock); + + pr_debug("%s: sigint cleanup %x %llx pid %d", + __func__, iter->info.fsid, + (unsigned long long)iter->info.number, + iter->info.pid); + do_unlock_close(&iter->info); + memcpy(&iter->info, &info, sizeof(info)); + dlm_release_plock_op(iter); + return count; + } list_del_init(&iter->list); memcpy(&iter->info, &info, sizeof(info)); if (iter->data) -- 2.31.1