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

Reply via email to