* [Cluster-devel] [PATCHv2 dlm/next 1/6] fs: dlm: replace sanity checks with WARN_ON
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 2/6] fs: dlm: cleanup plock_op vs plock_xop Alexander Aring
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
There are several sanity checks and recover handling if they occur in
the dlm plock handling. From my understanding those operation can't run
in parallel with any list manipulation which involved setting the list
holder of plock_op, if so we have a bug which this sanity check will
warn about. Previously if such sanity check occurred the dlm plock
handling was trying to recover from it by deleting the plock_op from a
list which the holder was set to. However there is a bug in the dlm
plock handling if this case ever happens. To make such bugs are more
visible for further investigations we add a WARN_ON() on those sanity
checks and remove the recovering handling because other possible side
effects.
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 32 ++++----------------------------
1 file changed, 4 insertions(+), 28 deletions(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index a10d2bcfe75a..55fba2f0234f 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -157,13 +157,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
goto out;
}
- spin_lock(&ops_lock);
- if (!list_empty(&op->list)) {
- log_error(ls, "dlm_posix_lock: op on list %llx",
- (unsigned long long)number);
- list_del(&op->list);
- }
- spin_unlock(&ops_lock);
+ WARN_ON(!list_empty(&op->list));
rv = op->info.rv;
@@ -190,13 +184,7 @@ static int dlm_plock_callback(struct plock_op *op)
struct plock_xop *xop = (struct plock_xop *)op;
int rv = 0;
- spin_lock(&ops_lock);
- if (!list_empty(&op->list)) {
- log_print("dlm_plock_callback: op on list %llx",
- (unsigned long long)op->info.number);
- list_del(&op->list);
- }
- spin_unlock(&ops_lock);
+ WARN_ON(!list_empty(&op->list));
/* check if the following 2 are still valid or make a copy */
file = xop->file;
@@ -289,13 +277,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
send_op(op);
wait_event(recv_wq, (op->done != 0));
- spin_lock(&ops_lock);
- if (!list_empty(&op->list)) {
- log_error(ls, "dlm_posix_unlock: op on list %llx",
- (unsigned long long)number);
- list_del(&op->list);
- }
- spin_unlock(&ops_lock);
+ WARN_ON(!list_empty(&op->list));
rv = op->info.rv;
@@ -343,13 +325,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
send_op(op);
wait_event(recv_wq, (op->done != 0));
- spin_lock(&ops_lock);
- if (!list_empty(&op->list)) {
- log_error(ls, "dlm_posix_get: op on list %llx",
- (unsigned long long)number);
- list_del(&op->list);
- }
- spin_unlock(&ops_lock);
+ WARN_ON(!list_empty(&op->list));
/* info.rv from userspace is 1 for conflict, 0 for no-conflict,
-ENOENT if there are no locks on the file */
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [Cluster-devel] [PATCHv2 dlm/next 2/6] fs: dlm: cleanup plock_op vs plock_xop
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 1/6] fs: dlm: replace sanity checks with WARN_ON Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 3/6] fs: dlm: rearrange async condition return Alexander Aring
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
Lately the different casting between plock_op and plock_xop and list
holders which was involved showed some issues which were hard to see.
This patch removes the "plock_xop" structure and introduces a
"struct plock_async_data". This structure will be set in "struct plock_op"
in case of asynchronous lock handling as the original "plock_xop" was
made for. There is no need anymore to cast pointers around for
additional fields in case of asynchronous lock handling. As disadvantage
another allocation was introduces but only needed in the asynchronous
case which is currently only used in combination with nfs lockd.
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 77 ++++++++++++++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index 55fba2f0234f..4e60dd657cb6 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -19,20 +19,20 @@ static struct list_head recv_list;
static wait_queue_head_t send_wq;
static wait_queue_head_t recv_wq;
-struct plock_op {
- struct list_head list;
- int done;
- struct dlm_plock_info info;
- int (*callback)(struct file_lock *fl, int result);
-};
-
-struct plock_xop {
- struct plock_op xop;
+struct plock_async_data {
void *fl;
void *file;
struct file_lock flc;
+ int (*callback)(struct file_lock *fl, int result);
};
+struct plock_op {
+ struct list_head list;
+ int done;
+ struct dlm_plock_info info;
+ /* if set indicates async handling */
+ struct plock_async_data *data;
+};
static inline void set_version(struct dlm_plock_info *info)
{
@@ -58,6 +58,12 @@ static int check_version(struct dlm_plock_info *info)
return 0;
}
+static void dlm_release_plock_op(struct plock_op *op)
+{
+ kfree(op->data);
+ kfree(op);
+}
+
static void send_op(struct plock_op *op)
{
set_version(&op->info);
@@ -101,22 +107,21 @@ static void do_unlock_close(struct dlm_ls *ls, u64 number,
int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
int cmd, struct file_lock *fl)
{
+ struct plock_async_data *op_data;
struct dlm_ls *ls;
struct plock_op *op;
- struct plock_xop *xop;
int rv;
ls = dlm_find_lockspace_local(lockspace);
if (!ls)
return -EINVAL;
- xop = kzalloc(sizeof(*xop), GFP_NOFS);
- if (!xop) {
+ op = kzalloc(sizeof(*op), GFP_NOFS);
+ if (!op) {
rv = -ENOMEM;
goto out;
}
- op = &xop->xop;
op->info.optype = DLM_PLOCK_OP_LOCK;
op->info.pid = fl->fl_pid;
op->info.ex = (fl->fl_type == F_WRLCK);
@@ -125,22 +130,32 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
op->info.number = number;
op->info.start = fl->fl_start;
op->info.end = fl->fl_end;
+ /* async handling */
if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
+ op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
+ if (!op_data) {
+ dlm_release_plock_op(op);
+ rv = -ENOMEM;
+ goto out;
+ }
+
/* fl_owner is lockd which doesn't distinguish
processes on the nfs client */
op->info.owner = (__u64) fl->fl_pid;
- op->callback = fl->fl_lmops->lm_grant;
- locks_init_lock(&xop->flc);
- locks_copy_lock(&xop->flc, fl);
- xop->fl = fl;
- xop->file = file;
+ op_data->callback = fl->fl_lmops->lm_grant;
+ locks_init_lock(&op_data->flc);
+ locks_copy_lock(&op_data->flc, fl);
+ op_data->fl = fl;
+ op_data->file = file;
+
+ op->data = op_data;
} else {
op->info.owner = (__u64)(long) fl->fl_owner;
}
send_op(op);
- if (!op->callback) {
+ if (!op->data) {
rv = wait_event_interruptible(recv_wq, (op->done != 0));
if (rv == -ERESTARTSYS) {
log_debug(ls, "dlm_posix_lock: wait killed %llx",
@@ -148,7 +163,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
spin_lock(&ops_lock);
list_del(&op->list);
spin_unlock(&ops_lock);
- kfree(xop);
+ dlm_release_plock_op(op);
do_unlock_close(ls, number, file, fl);
goto out;
}
@@ -167,7 +182,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
(unsigned long long)number);
}
- kfree(xop);
+ dlm_release_plock_op(op);
out:
dlm_put_lockspace(ls);
return rv;
@@ -177,20 +192,20 @@ EXPORT_SYMBOL_GPL(dlm_posix_lock);
/* Returns failure iff a successful lock operation should be canceled */
static int dlm_plock_callback(struct plock_op *op)
{
+ struct plock_async_data *op_data = op->data;
struct file *file;
struct file_lock *fl;
struct file_lock *flc;
int (*notify)(struct file_lock *fl, int result) = NULL;
- struct plock_xop *xop = (struct plock_xop *)op;
int rv = 0;
WARN_ON(!list_empty(&op->list));
/* check if the following 2 are still valid or make a copy */
- file = xop->file;
- flc = &xop->flc;
- fl = xop->fl;
- notify = op->callback;
+ file = op_data->file;
+ flc = &op_data->flc;
+ fl = op_data->fl;
+ notify = op_data->callback;
if (op->info.rv) {
notify(fl, op->info.rv);
@@ -221,7 +236,7 @@ static int dlm_plock_callback(struct plock_op *op)
}
out:
- kfree(xop);
+ dlm_release_plock_op(op);
return rv;
}
@@ -285,7 +300,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
rv = 0;
out_free:
- kfree(op);
+ dlm_release_plock_op(op);
out:
dlm_put_lockspace(ls);
fl->fl_flags = fl_flags;
@@ -345,7 +360,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
rv = 0;
}
- kfree(op);
+ dlm_release_plock_op(op);
out:
dlm_put_lockspace(ls);
return rv;
@@ -381,7 +396,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
(the process did not make an unlock call). */
if (op->info.flags & DLM_PLOCK_FL_CLOSE)
- kfree(op);
+ dlm_release_plock_op(op);
if (copy_to_user(u, &info, sizeof(info)))
return -EFAULT;
@@ -413,7 +428,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
op->info.owner == info.owner) {
list_del_init(&op->list);
memcpy(&op->info, &info, sizeof(info));
- if (op->callback)
+ if (op->data)
do_callback = 1;
else
op->done = 1;
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [Cluster-devel] [PATCHv2 dlm/next 3/6] fs: dlm: rearrange async condition return
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 1/6] fs: dlm: replace sanity checks with WARN_ON Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 2/6] fs: dlm: cleanup plock_op vs plock_xop Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 4/6] fs: dlm: improve plock logging if interrupted Alexander Aring
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
This patch moves the return of FILE_LOCK_DEFERRED a little bit earlier
than checking afterwards again if the request was an asynchronous request.
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index 4e60dd657cb6..757d9013788a 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -149,26 +149,25 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
op_data->file = file;
op->data = op_data;
+
+ send_op(op);
+ rv = FILE_LOCK_DEFERRED;
+ goto out;
} else {
op->info.owner = (__u64)(long) fl->fl_owner;
}
send_op(op);
- if (!op->data) {
- rv = wait_event_interruptible(recv_wq, (op->done != 0));
- if (rv == -ERESTARTSYS) {
- log_debug(ls, "dlm_posix_lock: wait killed %llx",
- (unsigned long long)number);
- spin_lock(&ops_lock);
- list_del(&op->list);
- spin_unlock(&ops_lock);
- dlm_release_plock_op(op);
- do_unlock_close(ls, number, file, fl);
- goto out;
- }
- } else {
- rv = FILE_LOCK_DEFERRED;
+ rv = wait_event_interruptible(recv_wq, (op->done != 0));
+ if (rv == -ERESTARTSYS) {
+ log_debug(ls, "%s: wait killed %llx", __func__,
+ (unsigned long long)number);
+ spin_lock(&ops_lock);
+ list_del(&op->list);
+ spin_unlock(&ops_lock);
+ dlm_release_plock_op(op);
+ do_unlock_close(ls, number, file, fl);
goto out;
}
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [Cluster-devel] [PATCHv2 dlm/next 4/6] fs: dlm: improve plock logging if interrupted
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
` (2 preceding siblings ...)
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 3/6] fs: dlm: rearrange async condition return Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 5/6] fs: dlm: remove unnecessary INIT_LIST_HEAD() Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 6/6] fs: dlm: move global to static inits Alexander Aring
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
This patch changes the log level if a plock is removed when interrupted
from debug to info. Additional it signals now that the plock entity was
removed to let the user know what's happening.
If on a dev_write() a pending plock cannot be find it will signal that
it might have been removed because wait interruption.
Before this patch there might be a "dev_write no op ..." info message
and the users can only guess that the plock was removed before because
the wait interruption. To be sure that is the case we log both messages
on the same log level.
Let both message be logged on info layer because it should not happened
a lot and if it happens it should be clear why the op was not found.
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index 757d9013788a..ce1af7986e16 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -161,11 +161,12 @@ 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) {
- log_debug(ls, "%s: wait killed %llx", __func__,
- (unsigned long long)number);
spin_lock(&ops_lock);
list_del(&op->list);
spin_unlock(&ops_lock);
+ log_print("%s: wait interrupted %x %llx, op removed",
+ __func__, ls->ls_global_id,
+ (unsigned long long)number);
dlm_release_plock_op(op);
do_unlock_close(ls, number, file, fl);
goto out;
@@ -443,8 +444,8 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
else
wake_up(&recv_wq);
} else
- log_print("dev_write no op %x %llx", info.fsid,
- (unsigned long long)info.number);
+ log_print("%s: no op %x %llx - may got interrupted?", __func__,
+ info.fsid, (unsigned long long)info.number);
return count;
}
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [Cluster-devel] [PATCHv2 dlm/next 5/6] fs: dlm: remove unnecessary INIT_LIST_HEAD()
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
` (3 preceding siblings ...)
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 4/6] fs: dlm: improve plock logging if interrupted Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 6/6] fs: dlm: move global to static inits Alexander Aring
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
There is no need to call INIT_LIST_HEAD() when it's set directly
afterwards by list_add_tail().
Reported-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index ce1af7986e16..ff439d780cb1 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -67,7 +67,6 @@ static void dlm_release_plock_op(struct plock_op *op)
static void send_op(struct plock_op *op)
{
set_version(&op->info);
- INIT_LIST_HEAD(&op->list);
spin_lock(&ops_lock);
list_add_tail(&op->list, &send_list);
spin_unlock(&ops_lock);
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [Cluster-devel] [PATCHv2 dlm/next 6/6] fs: dlm: move global to static inits
2022-02-17 19:39 [Cluster-devel] [PATCHv2 dlm/next 0/6] fs: dlm: cleanup plock code Alexander Aring
` (4 preceding siblings ...)
2022-02-17 19:39 ` [Cluster-devel] [PATCHv2 dlm/next 5/6] fs: dlm: remove unnecessary INIT_LIST_HEAD() Alexander Aring
@ 2022-02-17 19:39 ` Alexander Aring
5 siblings, 0 replies; 7+ messages in thread
From: Alexander Aring @ 2022-02-17 19:39 UTC (permalink / raw)
To: cluster-devel.redhat.com
Instead of init global module at module loading time we can move the
initialization of those global variables at memory initialization of the
module loader.
Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
fs/dlm/plock.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index ff439d780cb1..16241fe6ac3c 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -13,11 +13,11 @@
#include "dlm_internal.h"
#include "lockspace.h"
-static spinlock_t ops_lock;
-static struct list_head send_list;
-static struct list_head recv_list;
-static wait_queue_head_t send_wq;
-static wait_queue_head_t recv_wq;
+static DEFINE_SPINLOCK(ops_lock);
+static LIST_HEAD(send_list);
+static LIST_HEAD(recv_list);
+static DECLARE_WAIT_QUEUE_HEAD(send_wq);
+static DECLARE_WAIT_QUEUE_HEAD(recv_wq);
struct plock_async_data {
void *fl;
@@ -480,12 +480,6 @@ int dlm_plock_init(void)
{
int rv;
- spin_lock_init(&ops_lock);
- INIT_LIST_HEAD(&send_list);
- INIT_LIST_HEAD(&recv_list);
- init_waitqueue_head(&send_wq);
- init_waitqueue_head(&recv_wq);
-
rv = misc_register(&plock_dev_misc);
if (rv)
log_print("dlm_plock_init: misc_register failed %d", rv);
--
2.31.1
^ permalink raw reply related [flat|nested] 7+ messages in thread