linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] linux/kernel.h: add container_from()
@ 2020-08-27  1:36 Allen Pais
  2020-08-27  2:31 ` Kees Cook
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Allen Pais @ 2020-08-27  1:36 UTC (permalink / raw)
  To: torvalds
  Cc: akpm, keescook, tglx, linux-kernel, Allen Pais,
	James E . J . Bottomley, Greg Kroah-Hartman, Jens Axboe

Introduce container_from() as a generic helper instead of
sub-systems defining a private from_* API
(Eg: from_tasklets recently introduced in
12cc923f1ccc: Tasklet: Introduce new initialization API)

The helper is similar to container_of() in argument order
with the difference of naming the containing structure instead
of having to specify its type.

Suggested-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Suggested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
 include/linux/kernel.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 500def620d8f..9d446324a8be 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1019,6 +1019,15 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
 			 "pointer type mismatch in container_of()");	\
 	IS_ERR_OR_NULL(__mptr) ? ERR_CAST(__mptr) :			\
 		((type *)(__mptr - offsetof(type, member))); })
+/**
+ * container_from - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @container:	the type of the container struct.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_from(ptr, container, member)	\
+	container_of(ptr, typeof(*container), member)
 
 /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27  1:36 [PATCH] linux/kernel.h: add container_from() Allen Pais
@ 2020-08-27  2:31 ` Kees Cook
  2020-08-27 12:19   ` Greg Kroah-Hartman
  2020-08-27 18:04 ` Linus Torvalds
  2020-08-27 18:07 ` Rasmus Villemoes
  2 siblings, 1 reply; 15+ messages in thread
From: Kees Cook @ 2020-08-27  2:31 UTC (permalink / raw)
  To: Allen Pais
  Cc: torvalds, akpm, tglx, linux-kernel, James E . J . Bottomley,
	Greg Kroah-Hartman, Jens Axboe

On Thu, Aug 27, 2020 at 07:06:36AM +0530, Allen Pais wrote:
> Introduce container_from() as a generic helper instead of
> sub-systems defining a private from_* API
> (Eg: from_tasklets recently introduced in
> 12cc923f1ccc: Tasklet: Introduce new initialization API)
> 
> The helper is similar to container_of() in argument order
> with the difference of naming the containing structure instead
> of having to specify its type.
> 
> Suggested-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
> Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Suggested-by: Jens Axboe <axboe@kernel.dk>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>

Acked-by: Kees Cook <keescook@chromium.org>

Who can carry this so it can get used by multiple trees? Should I keep a
git branch folks should merge when taking Allen's conversion patches?

(In the future we can do a treewide replacement of the
subsystem-specific from*() macros into container_from())

Thanks!

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27  2:31 ` Kees Cook
@ 2020-08-27 12:19   ` Greg Kroah-Hartman
  2020-08-27 17:50     ` Kees Cook
  0 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2020-08-27 12:19 UTC (permalink / raw)
  To: Kees Cook
  Cc: Allen Pais, torvalds, akpm, tglx, linux-kernel,
	James E . J . Bottomley, Jens Axboe

On Wed, Aug 26, 2020 at 07:31:40PM -0700, Kees Cook wrote:
> On Thu, Aug 27, 2020 at 07:06:36AM +0530, Allen Pais wrote:
> > Introduce container_from() as a generic helper instead of
> > sub-systems defining a private from_* API
> > (Eg: from_tasklets recently introduced in
> > 12cc923f1ccc: Tasklet: Introduce new initialization API)
> > 
> > The helper is similar to container_of() in argument order
> > with the difference of naming the containing structure instead
> > of having to specify its type.
> > 
> > Suggested-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
> > Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Suggested-by: Jens Axboe <axboe@kernel.dk>
> > Signed-off-by: Allen Pais <allen.lkml@gmail.com>
> 
> Acked-by: Kees Cook <keescook@chromium.org>
> 
> Who can carry this so it can get used by multiple trees? Should I keep a
> git branch folks should merge when taking Allen's conversion patches?

I can put it in my driver core tree, and give everyone a stable, signed,
tag to pull it from so that it can get propagated everywhere, if that
makes it easy for others to use it now.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 12:19   ` Greg Kroah-Hartman
@ 2020-08-27 17:50     ` Kees Cook
  0 siblings, 0 replies; 15+ messages in thread
From: Kees Cook @ 2020-08-27 17:50 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Allen Pais, torvalds, akpm, tglx, linux-kernel,
	James E . J . Bottomley, Jens Axboe

On Thu, Aug 27, 2020 at 02:19:41PM +0200, Greg Kroah-Hartman wrote:
> On Wed, Aug 26, 2020 at 07:31:40PM -0700, Kees Cook wrote:
> > On Thu, Aug 27, 2020 at 07:06:36AM +0530, Allen Pais wrote:
> > > Introduce container_from() as a generic helper instead of
> > > sub-systems defining a private from_* API
> > > (Eg: from_tasklets recently introduced in
> > > 12cc923f1ccc: Tasklet: Introduce new initialization API)
> > > 
> > > The helper is similar to container_of() in argument order
> > > with the difference of naming the containing structure instead
> > > of having to specify its type.
> > > 
> > > Suggested-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
> > > Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Suggested-by: Jens Axboe <axboe@kernel.dk>
> > > Signed-off-by: Allen Pais <allen.lkml@gmail.com>
> > 
> > Acked-by: Kees Cook <keescook@chromium.org>
> > 
> > Who can carry this so it can get used by multiple trees? Should I keep a
> > git branch folks should merge when taking Allen's conversion patches?
> 
> I can put it in my driver core tree, and give everyone a stable, signed,
> tag to pull it from so that it can get propagated everywhere, if that
> makes it easy for others to use it now.

Thank you; that would be lovely. :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27  1:36 [PATCH] linux/kernel.h: add container_from() Allen Pais
  2020-08-27  2:31 ` Kees Cook
@ 2020-08-27 18:04 ` Linus Torvalds
  2020-08-27 18:32   ` James Bottomley
  2020-08-27 18:07 ` Rasmus Villemoes
  2 siblings, 1 reply; 15+ messages in thread
From: Linus Torvalds @ 2020-08-27 18:04 UTC (permalink / raw)
  To: Allen Pais
  Cc: Andrew Morton, Kees Cook, Thomas Gleixner,
	Linux Kernel Mailing List, James E . J . Bottomley,
	Greg Kroah-Hartman, Jens Axboe

On Wed, Aug 26, 2020 at 6:36 PM Allen Pais <allen.lkml@gmail.com> wrote:
>
> Introduce container_from() as a generic helper instead of
> sub-systems defining a private from_

NAK.

This seems completely broken.

The documentation comment doesn't even match the macro, and claims
that "container" is a type.

Which it isn't. That's what container_of()" already takes.

And if the argument is that a broken commit introduced a broken macro,
then that's not a great argument. Yes, we have that broken
"from_tasklet()" macro, but it's not even *USED* anywhere.

So instead of adding a broken new concept that adds absolutely no
value, let's just remove the broken macro that isn't even used.

                      Linus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27  1:36 [PATCH] linux/kernel.h: add container_from() Allen Pais
  2020-08-27  2:31 ` Kees Cook
  2020-08-27 18:04 ` Linus Torvalds
@ 2020-08-27 18:07 ` Rasmus Villemoes
  2 siblings, 0 replies; 15+ messages in thread
From: Rasmus Villemoes @ 2020-08-27 18:07 UTC (permalink / raw)
  To: Allen Pais, torvalds
  Cc: akpm, keescook, tglx, linux-kernel, James E . J . Bottomley,
	Greg Kroah-Hartman, Jens Axboe

On 27/08/2020 03.36, Allen Pais wrote:
> Introduce container_from() as a generic helper instead of
> sub-systems defining a private from_* API
> (Eg: from_tasklets recently introduced in
> 12cc923f1ccc: Tasklet: Introduce new initialization API)
> 
> The helper is similar to container_of() in argument order
> with the difference of naming the containing structure instead
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> of having to specify its type.
> 

> +/**
> + * container_from - cast a member of a structure out to the containing structure
> + * @ptr:	the pointer to the member.
> + * @container:	the type of the container struct.
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This seems to have been copy-pasted from container_of? Shouldn't
@container be the (local) value we're storing into? As in foo =
container_from(..., foo, ...)? Or am I misunderstanding the purpose of this?

[And I think it would read nicer if the bikeshed was called
to_container(), but don't care deeply.]

Rasmus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 18:04 ` Linus Torvalds
@ 2020-08-27 18:32   ` James Bottomley
  2020-08-27 18:40     ` Linus Torvalds
  0 siblings, 1 reply; 15+ messages in thread
From: James Bottomley @ 2020-08-27 18:32 UTC (permalink / raw)
  To: Linus Torvalds, Allen Pais
  Cc: Andrew Morton, Kees Cook, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

On Thu, 2020-08-27 at 11:04 -0700, Linus Torvalds wrote:
> On Wed, Aug 26, 2020 at 6:36 PM Allen Pais <allen.lkml@gmail.com>
> wrote:
> > 
> > Introduce container_from() as a generic helper instead of
> > sub-systems defining a private from_
> 
> NAK.
> 
> This seems completely broken.
> 
> The documentation comment doesn't even match the macro, and claims
> that "container" is a type.
> 
> Which it isn't. That's what container_of()" already takes.
> 
> And if the argument is that a broken commit introduced a broken
> macro,
> then that's not a great argument. Yes, we have that broken
> "from_tasklet()" macro, but it's not even *USED* anywhere.
> 
> So instead of adding a broken new concept that adds absolutely no
> value, let's just remove the broken macro that isn't even used.

The argument is more over the tasklet rework adding from_tasklet that
was effectively completely generic.

https://lore.kernel.org/dri-devel/20200817091617.28119-1-allen.cryptic@gmail.com/

The tasklet rework people don't want to use container_of, which was our
first suggestion, because it produces lines which are "too long".  So
container_from is a compromise that takes the actual structure pointer
as a second argument instead of the structure type, thus being
completely generic and suitable for line length reduction in the
tasklet rework code.

James


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 18:32   ` James Bottomley
@ 2020-08-27 18:40     ` Linus Torvalds
  2020-08-27 18:48       ` Linus Torvalds
  0 siblings, 1 reply; 15+ messages in thread
From: Linus Torvalds @ 2020-08-27 18:40 UTC (permalink / raw)
  To: James Bottomley
  Cc: Allen Pais, Andrew Morton, Kees Cook, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

On Thu, Aug 27, 2020 at 11:32 AM James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
>
> The tasklet rework people don't want to use container_of, which was our
> first suggestion, because it produces lines which are "too long".

WTF?

Next somebody will decide that our list handling macros don't match
their mood, and make up their own.

Guys, there's a real advantage to just following convention and not
confusing people with new made-up stuff that does the same thing just
using slightly different names and slightly different semantics.

So let the tasklet rework people work on their own little thing if
they can't play with the rest of the kernel.

We'll just ignore them.

              Linus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 18:40     ` Linus Torvalds
@ 2020-08-27 18:48       ` Linus Torvalds
  2020-08-27 19:28         ` Kees Cook
  0 siblings, 1 reply; 15+ messages in thread
From: Linus Torvalds @ 2020-08-27 18:48 UTC (permalink / raw)
  To: James Bottomley
  Cc: Allen Pais, Andrew Morton, Kees Cook, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

On Thu, Aug 27, 2020 at 11:40 AM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> On Thu, Aug 27, 2020 at 11:32 AM James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
> >
> >
> > The tasklet rework people don't want to use container_of, which was our
> > first suggestion, because it produces lines which are "too long".
>
> WTF?

Side note: I'm entirely serious. If somebody has problems with "too
long lines", they are doing things wrong. Just ignore them.

Changing standard kernel interfaces is the wrong solution. What's
next? Using 2-character indentation like some broken projects do just
to make lines shorter and encourage people to do deep nesting?

No. The solution is to not write crap code with overly complex expressions.

"container_of()" has been a _very_ successful model, and the only
reason to ever wrap it is if you already *know* the type, and you wrap
it with an inline function that actually checks it.

For a lot of (usually) good examples of this, just do a

     git grep return.container_of

and find things like

    static inline struct kvm_pit *pit_state_to_pit(struct kvm_kpit_state *ps)
    {
        return container_of(ps, struct kvm_pit, pit_state);
    }

which now results in a type-checked *true* simplification of container-of.

It basically creates a specialized version which documents what it
does in the name, and does proper type checking, and doesn't try to be
another name for the existing generic container_of().

Seriously. It sounds to me like the tasklet rework people are people
we want to avoid. They're doing completely the wrong thing.

So just throw that garbage out.

                      Linus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 18:48       ` Linus Torvalds
@ 2020-08-27 19:28         ` Kees Cook
  2020-08-27 20:46           ` Linus Torvalds
  0 siblings, 1 reply; 15+ messages in thread
From: Kees Cook @ 2020-08-27 19:28 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: James Bottomley, Allen Pais, Andrew Morton, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

On Thu, Aug 27, 2020 at 11:48:19AM -0700, Linus Torvalds wrote:
> On Thu, Aug 27, 2020 at 11:40 AM Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > On Thu, Aug 27, 2020 at 11:32 AM James Bottomley
> > <James.Bottomley@hansenpartnership.com> wrote:
> > >
> > >
> > > The tasklet rework people don't want to use container_of, which was our
> > > first suggestion, because it produces lines which are "too long".
> >
> > WTF?
> 
> Side note: I'm entirely serious. If somebody has problems with "too
> long lines", they are doing things wrong. Just ignore them.
> 
> Changing standard kernel interfaces is the wrong solution. What's
> next? Using 2-character indentation like some broken projects do just
> to make lines shorter and encourage people to do deep nesting?
> 
> No. The solution is to not write crap code with overly complex expressions.
> 
> "container_of()" has been a _very_ successful model, and the only
> reason to ever wrap it is if you already *know* the type, and you wrap
> it with an inline function that actually checks it.

This works for the case where it's a known 1-to-1 conversion, as you
showed. It doesn't work well for the 1-to-many (like timer_struct before,
and tasklet now), where each user of the infrastructure contains the
callback handle struct in their specific containing struct, which is
common for these kinds of callbacks.

> which now results in a type-checked *true* simplification of container-of.

More important than the aesthetics is the type checking, for sure.

The common raw pattern for callbacks is:

void callback(struct callback_handle *inner)
{
	struct outer *instance;
	...
	instance = container_of(inner, struct outer, member_name_of_inner);

There's so much redundancy here. And while mismatches between "instance"
and the "struct outer" type argument will be caught by the compiler,
it's weird to repeat it. Some places will make this less weird by doing:

	instance = container_of(inner, typeof(*instance), member_name_of_inner);

and when doing the timer_struct replacement, people didn't like the line
wraps making their drivers "ugly", and the compromise was to implement
from_timer()[1]:

  Since the regular pattern of using container_of() during local variable
  declaration repeats the need for the variable type declaration
  to be included, this adds a helper modeled after other from_*()
  helpers that wrap container_of(), named from_timer(). This helper uses
  typeof(*variable), removing the type redundancy and minimizing the need
  for line wraps in forthcoming conversions from "unsigned data long" to
  "struct timer_list *" in the timer callbacks:

  -void callback(unsigned long data)
  +void callback(struct timer_list *t)
  {
  -   struct some_data_structure *local = (struct some_data_structure *)data;
  +   struct some_data_structure *local = from_timer(local, t, timer);

I still didn't like this because "local" got repeated. I still think
some kind of DECLARE*() would be best. Like:

#define DECLARE_CONTAINER(outer_type, outer, member_name_of_inner, inner) \
	outer_type outer_name = container_of(inner, typeof(*outer),       \
                                             member_name_of_inner)

Then the above old timer_struct example becomes:

  -void callback(unsigned long data)
  +void callback(struct timer_list *t)
  {
  -   struct some_data_structure *local = (struct some_data_structure *)data;
  +   DECLARE_CONTAINER(struct some_data_structure *, local, timer, t);

> Seriously. It sounds to me like the tasklet rework people are people
> we want to avoid. They're doing completely the wrong thing.

So, when it's only directed at me, I just delete the personal attacks
from the quoted sections in my replies and ignore it. When it splashes
on other people, though, I think I have a duty to object to the
behavior:

This is a particularly unfriendly way to mentor new contributors and to
treat existing contributors (and reinforces a false "we"/"them" split,
when everyone just wants to see the kernel be better). And to paint
what is a 300 patch effort that cleans up a poor API that no one else
has been willing to do as "doing completely the wrong thing" when the
complaint is mainly bikeshedding over a mostly mechanical step seems
like quite an overreaction.

But, yes, let's get the right API here. I think container_of() is a mess
for these 1-to-many cases. What do you suggest here? I'll change all of
from_timer() to use it too.

-Kees

[1] https://lore.kernel.org/lkml/20170928133817.GA113410@beast/

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 19:28         ` Kees Cook
@ 2020-08-27 20:46           ` Linus Torvalds
  2020-08-27 21:36             ` Al Viro
  2020-08-28  7:07             ` Allen
  0 siblings, 2 replies; 15+ messages in thread
From: Linus Torvalds @ 2020-08-27 20:46 UTC (permalink / raw)
  To: Kees Cook
  Cc: James Bottomley, Allen Pais, Andrew Morton, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

On Thu, Aug 27, 2020 at 12:28 PM Kees Cook <keescook@chromium.org> wrote:
>
> The common raw pattern for callbacks is:
>
> void callback(struct callback_handle *inner)
> {
>         struct outer *instance;
>         ...
>         instance = container_of(inner, struct outer, member_name_of_inner);
>
> There's so much redundancy here.

What?

It's not all that complicated or even particularly redundant. The main
redundancy comes from you splitting up the declaration from the
initialization - which is certainly fine, and often a good idea, but
it does mean that you mention "struct outer" and "instance" twice.

I don't see that kind of redundancy being a _problem_, though. "So
much redundancy" is just over-stating the issue completely.

In fact, we often encourage people to split declaration from
initialization exactly because it results in simpler expressions and
more legible code, even if that name is now redundant. So it's a small
extra typing of the type. Big deal.

The above is also a common pattern that once you know how
container_of() works, it's very legible.

Sure, if you're new to the kernel, and haven't seen "container_of()"
in other projects, it might initially be a bit of an odd pattern, but
that's the advantage of having one single standardized model: it
becomes a pattern, and you don't have to think about it.

And particularly with that argument-type pattern, you really have to
work at making over-long lines, since the indentation level will by
definition be just one.

Looking around, I do see a lot of people doing line-breaks, but that
tends to be when they insist on putting the variable initialization in
the declaration. And even then, it often seems pointless (eg

        struct idp_led *led = container_of(cdev,
                        struct idp_led, cdev);

was split for no good reason I can see, but it seems to be a pattern
in that file).

You really have to pick some pretty excessive type names (or variable
names) to get close to 80 characters. Again, to pick an example:

        struct timer_group_priv *priv = container_of(handle,
                        struct timer_group_priv, timer[handle->num]);

ends up being long even if you were to split it, but that funky
container_from() wouldn't have helped the real problem - the fact that
the above is complex and nasty.

And I had to _search_ for that example. All the normal cases of
split-line container-of's were due to doing it with the declaration,
or beause the first argument ended up being an expression in itself
and the nested expressions made it more complex.

And in the above example, the real complexity - and the reason the
line ends up long - is because the "member" isn't a member. The above
case works - and it's in fact *intended* to work, I'm not claiming
it's some mis-use of the macro.  But it's really a rather complex
case, where it would probably have been a good idea to add a comment
about how this really depends on handle->num being set correctly.

And in fact, it would probably have been a *perfect* example of where
a helper function really would have improved the code, not so much
from a line length perspective, but exactly because the above is a
much more complicated case than most container_of() cases are.

So a helper function like the kvm one I quoted would have been a good
idea. In ways that "container_from()" would not have been, since it
doesn't actually even address the source of complexity.

               Linus

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 20:46           ` Linus Torvalds
@ 2020-08-27 21:36             ` Al Viro
  2020-08-27 22:14               ` Kees Cook
  2020-08-28  7:07             ` Allen
  1 sibling, 1 reply; 15+ messages in thread
From: Al Viro @ 2020-08-27 21:36 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kees Cook, James Bottomley, Allen Pais, Andrew Morton,
	Thomas Gleixner, Linux Kernel Mailing List, Greg Kroah-Hartman,
	Jens Axboe

On Thu, Aug 27, 2020 at 01:46:33PM -0700, Linus Torvalds wrote:

> You really have to pick some pretty excessive type names (or variable
> names) to get close to 80 characters. Again, to pick an example:
> 
>         struct timer_group_priv *priv = container_of(handle,
>                         struct timer_group_priv, timer[handle->num]);
> 
> ends up being long even if you were to split it, but that funky
> container_from() wouldn't have helped the real problem - the fact that
> the above is complex and nasty.
> 
> And I had to _search_ for that example. All the normal cases of
> split-line container-of's were due to doing it with the declaration,
> or beause the first argument ended up being an expression in itself
> and the nested expressions made it more complex.

Speaking of searching, this kind of typeof use is, IMO, actively
harmful - it makes finding the places where we might get from
e.g. linked list to containing objects much harder.  container_of
(unless combined with obfuscating use of typeof()) at least gives
you a chance to grep - struct foo *not* followed by '*' is a pattern
that doesn't give too many false positives.  This one, OTOH, is
essentially impossible to grep for.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 21:36             ` Al Viro
@ 2020-08-27 22:14               ` Kees Cook
  2020-08-28  7:09                 ` Allen
  0 siblings, 1 reply; 15+ messages in thread
From: Kees Cook @ 2020-08-27 22:14 UTC (permalink / raw)
  To: Al Viro
  Cc: Linus Torvalds, James Bottomley, Allen Pais, Andrew Morton,
	Thomas Gleixner, Linux Kernel Mailing List, Greg Kroah-Hartman,
	Jens Axboe

On Thu, Aug 27, 2020 at 10:36:36PM +0100, Al Viro wrote:
> On Thu, Aug 27, 2020 at 01:46:33PM -0700, Linus Torvalds wrote:
> > You really have to pick some pretty excessive type names (or variable
> > names) to get close to 80 characters. Again, to pick an example:
> > 
> >         struct timer_group_priv *priv = container_of(handle,
> >                         struct timer_group_priv, timer[handle->num]);
> > 
> > ends up being long even if you were to split it, but that funky
> > container_from() wouldn't have helped the real problem - the fact that
> > the above is complex and nasty.

The point about doing the assignment with the declaration certainly makes
the "ugliness" worse, I agree. I'm still not generally convinced about
the redundancy level pros/cons, but I concede that having a common idiom
(rather than a succinct but subsystem-dependent idiom) is better for
people reading the code for the first time.

> > And I had to _search_ for that example. All the normal cases of
> > split-line container-of's were due to doing it with the declaration,
> > or beause the first argument ended up being an expression in itself
> > and the nested expressions made it more complex.
> 
> Speaking of searching, this kind of typeof use is, IMO, actively
> harmful - it makes finding the places where we might get from
> e.g. linked list to containing objects much harder.  container_of
> (unless combined with obfuscating use of typeof()) at least gives
> you a chance to grep - struct foo *not* followed by '*' is a pattern
> that doesn't give too many false positives.  This one, OTOH, is
> essentially impossible to grep for.

And this observation about workflow does strike a chord with me. I do end
up with those kind of searches too. In trying to examine my preferences
here, I think my instincts are to avoid open-coded types (leading me to
want to use typeof()) but I think those instincts were actually developed
from dealing with _sizeof_ and all the way it goes terribly wrong. So,
okay, I'm convinced. container_of() it is.

Doing these conversions becomes a little less mechanical if assignment
needs to be split from declaration, but hey, we've got a 100 character
line "limit" now, so maybe it'll be less needed. :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 20:46           ` Linus Torvalds
  2020-08-27 21:36             ` Al Viro
@ 2020-08-28  7:07             ` Allen
  1 sibling, 0 replies; 15+ messages in thread
From: Allen @ 2020-08-28  7:07 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kees Cook, James Bottomley, Andrew Morton, Thomas Gleixner,
	Linux Kernel Mailing List, Greg Kroah-Hartman, Jens Axboe

>
> I don't see that kind of redundancy being a _problem_, though. "So
> much redundancy" is just over-stating the issue completely.
>
> In fact, we often encourage people to split declaration from
> initialization exactly because it results in simpler expressions and
> more legible code, even if that name is now redundant. So it's a small
> extra typing of the type. Big deal.
>
> The above is also a common pattern that once you know how
> container_of() works, it's very legible.
>
> Sure, if you're new to the kernel, and haven't seen "container_of()"
> in other projects, it might initially be a bit of an odd pattern, but
> that's the advantage of having one single standardized model: it
> becomes a pattern, and you don't have to think about it.
>
> And particularly with that argument-type pattern, you really have to
> work at making over-long lines, since the indentation level will by
> definition be just one.
>
> Looking around, I do see a lot of people doing line-breaks, but that
> tends to be when they insist on putting the variable initialization in
> the declaration. And even then, it often seems pointless (eg
>
>         struct idp_led *led = container_of(cdev,
>                         struct idp_led, cdev);
>
> was split for no good reason I can see, but it seems to be a pattern
> in that file).
>
> You really have to pick some pretty excessive type names (or variable
> names) to get close to 80 characters. Again, to pick an example:
>
>         struct timer_group_priv *priv = container_of(handle,
>                         struct timer_group_priv, timer[handle->num]);
>
> ends up being long even if you were to split it, but that funky
> container_from() wouldn't have helped the real problem - the fact that
> the above is complex and nasty.
>

 An example with a really long member name is

+struct nokia_modem_device *modem = from_tasklet(modem, t,
+        nokia_modem_rst_ind_tasklet);

With container_of() one can imagine how long it would end up. And
am sure we have many more examples in the kernel.

I agree, It would have been simpler to use container_of() as it's been
widely used, but as mentioned by Kees, for 1-to-many conversions
it does not work well.

I guess container_from() is a NAK, if you would want us to just use
container_of() to keep the code clean and simple instead of using wrappers,
or any other method, we are open to suggestions.

Thanks,
- Allen

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] linux/kernel.h: add container_from()
  2020-08-27 22:14               ` Kees Cook
@ 2020-08-28  7:09                 ` Allen
  0 siblings, 0 replies; 15+ messages in thread
From: Allen @ 2020-08-28  7:09 UTC (permalink / raw)
  To: Kees Cook
  Cc: Al Viro, Linus Torvalds, James Bottomley, Andrew Morton,
	Thomas Gleixner, Linux Kernel Mailing List, Greg Kroah-Hartman,
	Jens Axboe

> > > You really have to pick some pretty excessive type names (or variable
> > > names) to get close to 80 characters. Again, to pick an example:
> > >
> > >         struct timer_group_priv *priv = container_of(handle,
> > >                         struct timer_group_priv, timer[handle->num]);
> > >
> > > ends up being long even if you were to split it, but that funky
> > > container_from() wouldn't have helped the real problem - the fact that
> > > the above is complex and nasty.
>
> The point about doing the assignment with the declaration certainly makes
> the "ugliness" worse, I agree. I'm still not generally convinced about
> the redundancy level pros/cons, but I concede that having a common idiom
> (rather than a succinct but subsystem-dependent idiom) is better for
> people reading the code for the first time.
>
> > > And I had to _search_ for that example. All the normal cases of
> > > split-line container-of's were due to doing it with the declaration,
> > > or beause the first argument ended up being an expression in itself
> > > and the nested expressions made it more complex.
> >
> > Speaking of searching, this kind of typeof use is, IMO, actively
> > harmful - it makes finding the places where we might get from
> > e.g. linked list to containing objects much harder.  container_of
> > (unless combined with obfuscating use of typeof()) at least gives
> > you a chance to grep - struct foo *not* followed by '*' is a pattern
> > that doesn't give too many false positives.  This one, OTOH, is
> > essentially impossible to grep for.
>
> And this observation about workflow does strike a chord with me. I do end
> up with those kind of searches too. In trying to examine my preferences
> here, I think my instincts are to avoid open-coded types (leading me to
> want to use typeof()) but I think those instincts were actually developed
> from dealing with _sizeof_ and all the way it goes terribly wrong. So,
> okay, I'm convinced. container_of() it is.

 so container_of() it is :)
Will start updating the rest of the patches.

Thanks,
- Allen

> Doing these conversions becomes a little less mechanical if assignment
> needs to be split from declaration, but hey, we've got a 100 character
> line "limit" now, so maybe it'll be less needed. :)
>
> --
> Kees Cook

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-08-28  7:10 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-27  1:36 [PATCH] linux/kernel.h: add container_from() Allen Pais
2020-08-27  2:31 ` Kees Cook
2020-08-27 12:19   ` Greg Kroah-Hartman
2020-08-27 17:50     ` Kees Cook
2020-08-27 18:04 ` Linus Torvalds
2020-08-27 18:32   ` James Bottomley
2020-08-27 18:40     ` Linus Torvalds
2020-08-27 18:48       ` Linus Torvalds
2020-08-27 19:28         ` Kees Cook
2020-08-27 20:46           ` Linus Torvalds
2020-08-27 21:36             ` Al Viro
2020-08-27 22:14               ` Kees Cook
2020-08-28  7:09                 ` Allen
2020-08-28  7:07             ` Allen
2020-08-27 18:07 ` Rasmus Villemoes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).