2022-03-21 22:08:53

by Jakob Koschel

[permalink] [raw]
Subject: [PATCH] ocfs2: fix check if list iterator did find an element

Instead of setting 'res' to NULL, it should only be set if
the suitable element was found.

In the original code 'res' would have been set to an incorrect pointer
if the list is empty.

In preparation to limit the scope of the list iterator to the list
traversal loop, use a dedicated pointer pointing to the found element [1].

Link: https://lore.kernel.org/all/[email protected]/
Signed-off-by: Jakob Koschel <[email protected]>
---
fs/ocfs2/dlm/dlmdebug.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index d442cf5dda8a..be5e9ed7da8d 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -541,7 +541,7 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
struct debug_lockres *dl = m->private;
struct dlm_ctxt *dlm = dl->dl_ctxt;
struct dlm_lock_resource *oldres = dl->dl_res;
- struct dlm_lock_resource *res = NULL;
+ struct dlm_lock_resource *res = NULL, *iter;
struct list_head *track_list;

spin_lock(&dlm->track_lock);
@@ -556,11 +556,11 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
}
}

- list_for_each_entry(res, track_list, tracking) {
- if (&res->tracking == &dlm->tracking_list)
- res = NULL;
- else
- dlm_lockres_get(res);
+ list_for_each_entry(iter, track_list, tracking) {
+ if (&iter->tracking != &dlm->tracking_list) {
+ dlm_lockres_get(iter);
+ res = iter;
+ }
break;
}
spin_unlock(&dlm->track_lock);

base-commit: 34e047aa16c0123bbae8e2f6df33e5ecc1f56601
--
2.25.1


2022-03-21 22:26:24

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH] ocfs2: fix check if list iterator did find an element

On Mon, Mar 21, 2022 at 02:34:34PM +0100, Jakob Koschel wrote:
> >> @@ -556,11 +556,11 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
> >> }
> >> }
> >>
> >> - list_for_each_entry(res, track_list, tracking) {
> >> - if (&res->tracking == &dlm->tracking_list)
> >> - res = NULL;
> >> - else
> >> - dlm_lockres_get(res);
> >> + list_for_each_entry(iter, track_list, tracking) {
> >> + if (&iter->tracking != &dlm->tracking_list) {

This is an open coded version of:

if (!list_entry_is_head(iter, &dlm->tracking_list, tracking)) {

Ideally someone would come through with enough confidence to just delete
it but the second best option is to just make it readable...

regards,
dan carpenter

> >> + dlm_lockres_get(iter);
> >> + res = iter;
> >> + }
> >> break;
> >> }

2022-03-21 22:47:45

by David Laight

[permalink] [raw]
Subject: RE: [PATCH] ocfs2: fix check if list iterator did find an element

From: Dan Carpenter
> Sent: 21 March 2022 13:55
> On Mon, Mar 21, 2022 at 02:34:34PM +0100, Jakob Koschel wrote:
> > >> @@ -556,11 +556,11 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
> > >> }
> > >> }
> > >>
> > >> - list_for_each_entry(res, track_list, tracking) {
> > >> - if (&res->tracking == &dlm->tracking_list)
> > >> - res = NULL;
> > >> - else
> > >> - dlm_lockres_get(res);
> > >> + list_for_each_entry(iter, track_list, tracking) {
> > >> + if (&iter->tracking != &dlm->tracking_list) {
>
> This is an open coded version of:
>
> if (!list_entry_is_head(iter, &dlm->tracking_list, tracking)) {

Doesn't list_for_each_entry() terminate before that happens?
So this code is probably still horribly broken.

My worry about bugs with these lists isn't really the code
that uses list_for_each_entry() - they are fairly easy to
locate, read and fix.
The problem is all the other code that is scanning these
list in other more obscure ways.

It really isn't a list structure that is easy to use at all.
It's only slight advantage is that you can unlink an item
without knowing the list head.
(Which can stop buggy code generating cross-linked lists.)

Unless you actually need to traverse backwards the 'back
pointer points to forwards pointer' list is much better.
Even if you have to maintain a 'pointer to last' to get
FIFO operation.

The other option is to double-link the items into a loop and
have a 'head' that points to the first item.

Both these loops have 'pointer to items' to don't need
container_of() and get better type checking from the compiler.

David

>
> Ideally someone would come through with enough confidence to just delete
> it but the second best option is to just make it readable...
>
> regards,
> dan carpenter
>
> > >> + dlm_lockres_get(iter);
> > >> + res = iter;
> > >> + }
> > >> break;
> > >> }

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2022-03-21 23:03:30

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH] ocfs2: fix check if list iterator did find an element

On Mon, Mar 21, 2022 at 04:00:10PM +0000, David Laight wrote:
> From: Dan Carpenter
> > Sent: 21 March 2022 13:55
> > On Mon, Mar 21, 2022 at 02:34:34PM +0100, Jakob Koschel wrote:
> > > >> @@ -556,11 +556,11 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
> > > >> }
> > > >> }
> > > >>
> > > >> - list_for_each_entry(res, track_list, tracking) {
> > > >> - if (&res->tracking == &dlm->tracking_list)
> > > >> - res = NULL;
> > > >> - else
> > > >> - dlm_lockres_get(res);
> > > >> + list_for_each_entry(iter, track_list, tracking) {
> > > >> + if (&iter->tracking != &dlm->tracking_list) {
> >
> > This is an open coded version of:
> >
> > if (!list_entry_is_head(iter, &dlm->tracking_list, tracking)) {
>
> Doesn't list_for_each_entry() terminate before that happens?
> So this code is probably still horribly broken.

There is ! in the condition. It's just a complicated way of writing
if (!0) { so code works fine, it's just messy.

regards,
dan carpenter