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

Reply via email to