This patch will introduce plock_op_lookup() to lookup a plock op when a result needs to lookup the plock op to find the original request. Besides that we add additional sanity check to confirm the lookup is still working in case of non F_SETLKW request as it requires a specific order in recv_list.
Signed-off-by: Alexander Aring <aahri...@redhat.com> --- fs/dlm/plock.c | 107 +++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 39 deletions(-) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 578bf8a1325f..933fb575e83a 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -433,14 +433,58 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, return sizeof(info); } +static struct plock_op *plock_op_lookup(const struct dlm_plock_info *info) +{ + struct plock_op *op = NULL, *iter; + + if (info->wait) { + list_for_each_entry(iter, &recv_setlkw_list, list) { + if (iter->info.fsid == info->fsid && + iter->info.number == info->number && + iter->info.owner == info->owner && + iter->info.pid == info->pid && + iter->info.start == info->start && + iter->info.end == info->end) { + op = iter; + break; + } + } + } else { + op = list_first_entry_or_null(&recv_list, struct plock_op, + list); + if (op) { + /* sanity check to check we got the right one */ + switch (op->info.optype) { + case DLM_PLOCK_OP_GET: + /* we can't check on some fields on get */ + WARN_ON(op->info.fsid != info->fsid || + op->info.number != info->number || + op->info.owner != info->owner || + op->info.optype != info->optype); + break; + default: + WARN_ON(op->info.fsid != info->fsid || + op->info.number != info->number || + op->info.owner != info->owner || + op->info.pid != info->pid || + op->info.start != info->start || + op->info.end != info->end || + op->info.optype != info->optype); + break; + } + } + } + + return op; +} + /* a write copies in one plock result that should match a plock_op on the recv list */ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, loff_t *ppos) { - struct plock_op *op = NULL, *iter; struct dlm_plock_info info; - int do_callback = 0; + struct plock_op *op; if (count != sizeof(info)) return -EINVAL; @@ -452,46 +496,31 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, return -EINVAL; spin_lock(&ops_lock); - if (info.wait) { - list_for_each_entry(iter, &recv_setlkw_list, list) { - if (iter->info.fsid == info.fsid && - iter->info.number == info.number && - iter->info.owner == info.owner && - iter->info.pid == info.pid && - iter->info.start == info.start && - iter->info.end == info.end) { - list_del_init(&iter->list); - memcpy(&iter->info, &info, sizeof(info)); - if (iter->data) - do_callback = 1; - else - iter->done = 1; - op = iter; - break; - } - } + op = plock_op_lookup(&info); + if (!op) { + spin_unlock(&ops_lock); + pr_debug("%s: no op %x %llx", __func__, + info.fsid, (unsigned long long)info.number); + return count; + } + + list_del_init(&op->list); + /* update set new fields by user space e.g. F_GETLK */ + memcpy(&op->info, &info, sizeof(info)); + + /* check for async handling */ + if (op->data) { + spin_unlock(&ops_lock); + dlm_plock_callback(op); } else { - op = list_first_entry_or_null(&recv_list, struct plock_op, - list); - if (op) { - list_del_init(&op->list); - memcpy(&op->info, &info, sizeof(info)); - if (op->data) - do_callback = 1; - else - op->done = 1; - } + /* must be set under ops_lock, because retry in setlkw_wait() + * if -ERESTARTSYS. + */ + op->done = 1; + spin_unlock(&ops_lock); + wake_up(&recv_wq); } - spin_unlock(&ops_lock); - if (op) { - if (do_callback) - dlm_plock_callback(op); - else - wake_up(&recv_wq); - } else - pr_debug("%s: no op %x %llx", __func__, - info.fsid, (unsigned long long)info.number); return count; } -- 2.31.1