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 | 117 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index d6ec70547b77..b2b6635fcb28 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -423,66 +423,105 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, return sizeof(info); } -/* 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) +static struct plock_op *plock_op_lookup(const struct dlm_plock_info *info) { struct plock_op *op = NULL, *iter; - struct dlm_plock_info info; - int do_callback = 0; - - if (count != sizeof(info)) - return -EINVAL; - - if (copy_from_user(&info, u, sizeof(info))) - return -EFAULT; - - if (check_version(&info)) - return -EINVAL; - spin_lock(&ops_lock); - if (info.wait) { + /* F_SETLKW does not have an order in recv_list */ + if (info->wait) { list_for_each_entry(iter, &recv_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 && - iter->info.ex == info.ex && + 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 && + iter->info.ex == info->ex && iter->info.wait) { op = iter; + + /* sanity check should be DLM_PLOCK_OP_LOCK */ + WARN_ON(op->info.optype != DLM_PLOCK_OP_LOCK); break; } } } else { + /* others than F_SETLKW have an order in recv_list we + * need to jump over all F_SETLKW ops (info->wait) and match + * the first one. + */ list_for_each_entry(iter, &recv_list, list) { if (!iter->info.wait) { op = iter; + + /* sanity check to check we got the right one */ + WARN_ON(op->info.fsid != info->fsid || + op->info.number != info->number || + op->info.owner != info->owner || + op->info.optype != info->optype); + + switch (op->info.optype) { + case DLM_PLOCK_OP_GET: + break; + default: + WARN_ON(op->info.pid != info->pid || + op->info.start != info->start || + op->info.end != info->end || + op->info.ex != info->ex); + break; + } break; } } } - if (op) { - list_del_init(&op->list); - memcpy(&op->info, &info, sizeof(info)); - if (op->data) - do_callback = 1; - else - op->done = 1; - } - spin_unlock(&ops_lock); + return op; +} - if (op) { - if (do_callback) - dlm_plock_callback(op); - else - wake_up(&recv_wq); - } else +/* 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 dlm_plock_info info; + struct plock_op *op; + + if (count != sizeof(info)) + return -EINVAL; + + if (copy_from_user(&info, u, sizeof(info))) + return -EFAULT; + + if (check_version(&info)) + return -EINVAL; + + spin_lock(&ops_lock); + 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 { + /* must be set under ops_lock, because retry in setlkw_wait() + * if -ERESTARTSYS. + */ + op->done = 1; + spin_unlock(&ops_lock); + wake_up(&recv_wq); + } + return count; } -- 2.31.1