--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-10-2012, 07:35 PM
Dan Williams
Bcache: generic utility code
On Wed, May 9, 2012 at 8:10 PM, Kent Overstreet <koverstreet@google.com> wrote:
> Much of this code should be moved out of drivers/block/bcache, but it
> was originally written for bcache.
>
> Signed-off-by: Kent Overstreet <koverstreet@google.com>
> ---
...these missed the removal of the dynamic_fault bits.
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-10-2012, 09:42 PM
Kent Overstreet
Bcache: generic utility code
Whoops, grepped around but missed that. Thanks.
On Thu, May 10, 2012 at 12:35 PM, Dan Williams <dan.j.williams@intel.com> wrote:
> On Wed, May 9, 2012 at 8:10 PM, Kent Overstreet <koverstreet@google.com> wrote:
>> Much of this code should be moved out of drivers/block/bcache, but it
>> was originally written for bcache.
>>
>> Signed-off-by: Kent Overstreet <koverstreet@google.com>
>> ---
>
> [..]
>> +#include <linux/dynamic_fault.h>
> [..]
>> +#define bio_alloc_pages(...) * * * * * * * * * * * * * * * * * * * * *
>> + * * * (dynamic_fault() ? -ENOMEM * * *: bio_alloc_pages(__VA_ARGS__))
>> +
>
> ...these missed the removal of the dynamic_fault bits.
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-22-2012, 09:17 PM
Tejun Heo
Bcache: generic utility code
Hello, Kent.
I've been reading the code and am still very far from understanding
the whole thing but here are general impressions upto this point.
* I started reading from get_bucket(), mostly because I wasn't sure
where to start. It would be very helpful to the reviewers and
future participants if there's a design doc and more comments (much
more). The code is on the big side and the problem is exacerbated
by use of somewhat unconventional constructs and conventions and
lack of documentation and comments.
* It's unfortunate but true that different parts of kernel are held to
different standards in terms of conformance to overall style and
structure. Code for obscure device, for example, is allowed to be
way more weird than common core code. That said, one thing which is
generally frowned upon is bringing in lots of foreign constructs
because that tends to make the code much more difficult to follow
for other people than plain silly code. Even for drivers, code with
a lot of wrappers and foreign constructs (synchronization, data
structure...) tend to get nacked and are recommended to convert to
existing infrastructure even if that ends up, say, more verbose
code.
It is also true that new constructs and mechanisms are constantly
being added to kernel and the ones used by bcache could be useful
enough to have; however, with my currently limited understanding,
the oddities seem too much.
* Too many smart macros. Macros suck. Smart ones double suck.
* For file internal ones, it's okay to be somewhat relaxed with
namespace separation but bcache code seems to be going too far. It
also becomes a lot worse with macros as warnings and errors from
compiler get much more difficult to decipher. e.g. things like
next() and end() macros are calling for trouble.
* Somewhat related to the above, I'm not a fan of super-verbose
symbols but I *hope* that the variable names were just a tiny bit
more descriptive. At least, the ones used as arguments.
* The biggest thing that I dislike about closure is that it's not
clear what it does when I see one. Is it a refcount,
synchronization construct or asynchronous execution mechanism? To
me, it seems like a construct with too many purposes and too much
abstraction, which tends to make it difficult to understand, easy to
misuse and difficult to debug. IMHO, constructs like this could
seem very attractive to small group of people with certain concepts
firmly on their minds; however, one man's paradise is another man's
hell and we're often better off without either. In many ways,
closure feels like kobject and friends.
I'd like to recommend using something more concerete even if that
means more verbosity. ie. if there are lots of bio sequencing going
on, implement and use bio sequencer. That's way more concerete and
concerete stuff tends to be much easier to wrap one's head around
mostly because it's much easier to agree upon for different people
and they don't have to keep second-guessing what the original author
would have on his/her mind while implementing it.
The problem that closure poses is that stuff like this adds a lot to
on-going maintenance overhead. bcache could be very successful and
something we continue to use for decades but it might as well be
mostly meaningless in five years due to developments in storage
technology. It'll still have to be maintained and you might not be
around for the task and we don't want people to face code body which
depends on alien abstract synchronization and async constructs while
updating, say, block or workqueue API. Code may be doing complex
things but they still better use the constructs and follow the
conventions that the rest of the kernel is using as much as
possible.
Again, my understanding of the code base is quite limited at this
point so I might change my mind but these were the impressions I got
upto this point. I'll keep on reading. Specific comments follow.
On Wed, May 09, 2012 at 11:10:17PM -0400, Kent Overstreet wrote:
> +#define simple_strtoint(c, end, base) simple_strtol(c, end, base)
> +#define simple_strtouint(c, end, base) simple_strtoul(c, end, base)
> +
> +#define STRTO_H(name, type)
> +int name ## _h(const char *cp, type *res)
> +{
...
> +}
> +EXPORT_SYMBOL_GPL(name ## _h);
> +
> +STRTO_H(strtoint, int)
> +STRTO_H(strtouint, unsigned int)
> +STRTO_H(strtoll, long long)
> +STRTO_H(strtoull, unsigned long long)
Function defining macros == bad. Can't it be implemented with a
common backend function with wrappers implementing limits? Why not
use memparse()?
> +ssize_t hprint(char *buf, int64_t v)
> +{
> + static const char units[] = "?kMGTPEZY";
> + char dec[3] = "";
> + int u, t = 0;
> +
> + for (u = 0; v >= 1024 || v <= -1024; u++) {
> + t = v & ~(~0 << 10);
> + v >>= 10;
> + }
> +
> + if (!u)
> + return sprintf(buf, "%llu", v);
> +
> + if (v < 100 && v > -100)
> + sprintf(dec, ".%i", t / 100);
> +
> + return sprintf(buf, "%lli%s%c", v, dec, units[u]);
> +}
> +EXPORT_SYMBOL_GPL(hprint);
Not your fault but maybe we want integer vsnprintf modifier for this.
Also, sprintf() sucks.
> +bool is_zero(const char *p, size_t n)
> +{
> + for (size_t i = 0; i < n; i++)
This doesn't build. While loop var decl in for loop is nice, the
kernel isn't built in c99 mode. If you want to enable c99 mode
kernel-wide, you're welcome to try but you can't flip that
per-component.
These are now separate patch series, right? But, please don't use
nested functions. Apart from being very unconventional (does gnu99
even allow this?), the implicit outer scope access is dangerous when
mixed with context bouncing which is rather common in kernel. We
(well, at least I) actually want cross stack frame accesses to be
explicit.
I'm gonna stop here. It should be pretty clear what I'm bitching
about by now. Please make it C and, better, kernel C.
Thanks.
--
tejun
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-22-2012, 09:19 PM
Tejun Heo
Bcache: generic utility code
Hello, Kent.
I've been reading the code and am still very far from understanding
the whole thing but here are general impressions upto this point.
* I started reading from get_bucket(), mostly because I wasn't sure
where to start. It would be very helpful to the reviewers and
future participants if there's a design doc and more comments (much
more). The code is on the big side and the problem is exacerbated
by use of somewhat unconventional constructs and conventions and
lack of documentation and comments.
* It's unfortunate but true that different parts of kernel are held to
different standards in terms of conformance to overall style and
structure. Code for obscure device, for example, is allowed to be
way more weird than common core code. That said, one thing which is
generally frowned upon is bringing in lots of foreign constructs
because that tends to make the code much more difficult to follow
for other people than plain silly code. Even for drivers, code with
a lot of wrappers and foreign constructs (synchronization, data
structure...) tend to get nacked and are recommended to convert to
existing infrastructure even if that ends up, say, more verbose
code.
It is also true that new constructs and mechanisms are constantly
being added to kernel and the ones used by bcache could be useful
enough to have; however, with my currently limited understanding,
the oddities seem too much.
* Too many smart macros. Macros suck. Smart ones double suck.
* For file internal ones, it's okay to be somewhat relaxed with
namespace separation but bcache code seems to be going too far. It
also becomes a lot worse with macros as warnings and errors from
compiler get much more difficult to decipher. e.g. things like
next() and end() macros are calling for trouble.
* Somewhat related to the above, I'm not a fan of super-verbose
symbols but I *hope* that the variable names were just a tiny bit
more descriptive. At least, the ones used as arguments.
* The biggest thing that I dislike about closure is that it's not
clear what it does when I see one. Is it a refcount,
synchronization construct or asynchronous execution mechanism? To
me, it seems like a construct with too many purposes and too much
abstraction, which tends to make it difficult to understand, easy to
misuse and difficult to debug. IMHO, constructs like this could
seem very attractive to small group of people with certain concepts
firmly on their minds; however, one man's paradise is another man's
hell and we're often better off without either. In many ways,
closure feels like kobject and friends.
I'd like to recommend using something more concerete even if that
means more verbosity. ie. if there are lots of bio sequencing going
on, implement and use bio sequencer. That's way more concerete and
concerete stuff tends to be much easier to wrap one's head around
mostly because it's much easier to agree upon for different people
and they don't have to keep second-guessing what the original author
would have on his/her mind while implementing it.
The problem that closure poses is that stuff like this adds a lot to
on-going maintenance overhead. bcache could be very successful and
something we continue to use for decades but it might as well be
mostly meaningless in five years due to developments in storage
technology. It'll still have to be maintained and you might not be
around for the task and we don't want people to face code body which
depends on alien abstract synchronization and async constructs while
updating, say, block or workqueue API. Code may be doing complex
things but they still better use the constructs and follow the
conventions that the rest of the kernel is using as much as
possible.
Again, my understanding of the code base is quite limited at this
point so I might change my mind but these were the impressions I got
upto this point. I'll keep on reading. Specific comments follow.
On Wed, May 09, 2012 at 11:10:17PM -0400, Kent Overstreet wrote:
> +#define simple_strtoint(c, end, base) simple_strtol(c, end, base)
> +#define simple_strtouint(c, end, base) simple_strtoul(c, end, base)
> +
> +#define STRTO_H(name, type)
> +int name ## _h(const char *cp, type *res)
> +{
...
> +}
> +EXPORT_SYMBOL_GPL(name ## _h);
> +
> +STRTO_H(strtoint, int)
> +STRTO_H(strtouint, unsigned int)
> +STRTO_H(strtoll, long long)
> +STRTO_H(strtoull, unsigned long long)
Function defining macros == bad. Can't it be implemented with a
common backend function with wrappers implementing limits? Why not
use memparse()?
> +ssize_t hprint(char *buf, int64_t v)
> +{
> + static const char units[] = "?kMGTPEZY";
> + char dec[3] = "";
> + int u, t = 0;
> +
> + for (u = 0; v >= 1024 || v <= -1024; u++) {
> + t = v & ~(~0 << 10);
> + v >>= 10;
> + }
> +
> + if (!u)
> + return sprintf(buf, "%llu", v);
> +
> + if (v < 100 && v > -100)
> + sprintf(dec, ".%i", t / 100);
> +
> + return sprintf(buf, "%lli%s%c", v, dec, units[u]);
> +}
> +EXPORT_SYMBOL_GPL(hprint);
Not your fault but maybe we want integer vsnprintf modifier for this.
Also, sprintf() sucks.
> +bool is_zero(const char *p, size_t n)
> +{
> + for (size_t i = 0; i < n; i++)
This doesn't build. While loop var decl in for loop is nice, the
kernel isn't built in c99 mode. If you want to enable c99 mode
kernel-wide, you're welcome to try but you can't flip that
per-component.
These are now separate patch series, right? But, please don't use
nested functions. Apart from being very unconventional (does gnu99
even allow this?), the implicit outer scope access is dangerous when
mixed with context bouncing which is rather common in kernel. We
(well, at least I) actually want cross stack frame accesses to be
explicit.
I'm gonna stop here. It should be pretty clear what I'm bitching
about by now. Please make it C and, better, kernel C.
Thanks.
--
tejun
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-23-2012, 03:12 AM
Kent Overstreet
Bcache: generic utility code
On Tue, May 22, 2012 at 02:17:06PM -0700, Tejun Heo wrote:
> Hello, Kent.
>
> I've been reading the code and am still very far from understanding
> the whole thing but here are general impressions upto this point.
>
> * I started reading from get_bucket(), mostly because I wasn't sure
> where to start. It would be very helpful to the reviewers and
> future participants if there's a design doc and more comments (much
> more). The code is on the big side and the problem is exacerbated
> by use of somewhat unconventional constructs and conventions and
> lack of documentation and comments.
Yeah, I'm gonna try and spend more time on documentation. That's gonna
take a bit, though.
> * It's unfortunate but true that different parts of kernel are held to
> different standards in terms of conformance to overall style and
> structure. Code for obscure device, for example, is allowed to be
> way more weird than common core code. That said, one thing which is
> generally frowned upon is bringing in lots of foreign constructs
> because that tends to make the code much more difficult to follow
> for other people than plain silly code. Even for drivers, code with
> a lot of wrappers and foreign constructs (synchronization, data
> structure...) tend to get nacked and are recommended to convert to
> existing infrastructure even if that ends up, say, more verbose
> code.
>
> It is also true that new constructs and mechanisms are constantly
> being added to kernel and the ones used by bcache could be useful
> enough to have; however, with my currently limited understanding,
> the oddities seem too much.
>
> * Too many smart macros. Macros suck. Smart ones double suck.
>
> * For file internal ones, it's okay to be somewhat relaxed with
> namespace separation but bcache code seems to be going too far. It
> also becomes a lot worse with macros as warnings and errors from
> compiler get much more difficult to decipher. e.g. things like
> next() and end() macros are calling for trouble.
Yes, that's been on the todo list forever - legacy of it starting out as
a single file. I'll try and work some more on namespacing tonight.
> * Somewhat related to the above, I'm not a fan of super-verbose
> symbols but I *hope* that the variable names were just a tiny bit
> more descriptive. At least, the ones used as arguments.
If you want to point out particularly egregious examples in your code
reviews I'll tackle those first. I suffer from being too close to the
code, so I really have a hard time guessing what's going to trip other
people up.
> * The biggest thing that I dislike about closure is that it's not
> clear what it does when I see one. Is it a refcount,
> synchronization construct or asynchronous execution mechanism? To
> me, it seems like a construct with too many purposes and too much
> abstraction, which tends to make it difficult to understand, easy to
> misuse and difficult to debug. IMHO, constructs like this could
> seem very attractive to small group of people with certain concepts
> firmly on their minds; however, one man's paradise is another man's
> hell and we're often better off without either. In many ways,
> closure feels like kobject and friends.
Heh, it's worse than kobjects in that respect. But I really like the
fact that it's more abstract than kobjects, in that it's not at all tied
to implementation details of sysfs or anything else.
> I'd like to recommend using something more concerete even if that
> means more verbosity. ie. if there are lots of bio sequencing going
> on, implement and use bio sequencer. That's way more concerete and
> concerete stuff tends to be much easier to wrap one's head around
> mostly because it's much easier to agree upon for different people
> and they don't have to keep second-guessing what the original author
> would have on his/her mind while implementing it.
There's got to be some kind of middle ground. Having a unifying
abstraction for refcounty things really is incredibly powerful - the
unified parent mechanism makes a lot of problems go away, I don't think
I can adequately explain how sucessful that was, you had to experience
it.
But nevertheless I sympathize with your basic complaint - it ought to be
possible to restructure something so the code is easier to follow and
it's easier to tell what a given closure is for.
Maybe if I go through and document all the instances where they're
declared it might help.
> On Wed, May 09, 2012 at 11:10:17PM -0400, Kent Overstreet wrote:
> > +#define simple_strtoint(c, end, base) simple_strtol(c, end, base)
> > +#define simple_strtouint(c, end, base) simple_strtoul(c, end, base)
> > +
> > +#define STRTO_H(name, type)
> > +int name ## _h(const char *cp, type *res)
> > +{
> ...
> > +}
> > +EXPORT_SYMBOL_GPL(name ## _h);
> > +
> > +STRTO_H(strtoint, int)
> > +STRTO_H(strtouint, unsigned int)
> > +STRTO_H(strtoll, long long)
> > +STRTO_H(strtoull, unsigned long long)
>
> Function defining macros == bad. Can't it be implemented with a
> common backend function with wrappers implementing limits? Why not
> use memparse()?
Had not come across memparse(). I don't think it's a sufficient
replacement for my code because of the per type limits, but we should
definitely get rid of the duplication one way or the other.
As you can probably tell I'm strongly biased against duplication when
it's a question of macros vs. duplication - but if we can make the
commend backend code + wrapper approach work that's even better (smaller
code size ftw). It'll be tricky to get u64 vs. int64 right, but I'll
take a stab at it.
>
> > +ssize_t hprint(char *buf, int64_t v)
> > +{
> > + static const char units[] = "?kMGTPEZY";
> > + char dec[3] = "";
> > + int u, t = 0;
> > +
> > + for (u = 0; v >= 1024 || v <= -1024; u++) {
> > + t = v & ~(~0 << 10);
> > + v >>= 10;
> > + }
> > +
> > + if (!u)
> > + return sprintf(buf, "%llu", v);
> > +
> > + if (v < 100 && v > -100)
> > + sprintf(dec, ".%i", t / 100);
> > +
> > + return sprintf(buf, "%lli%s%c", v, dec, units[u]);
> > +}
> > +EXPORT_SYMBOL_GPL(hprint);
>
> Not your fault but maybe we want integer vsnprintf modifier for this.
Yes.
> Also, sprintf() sucks.
Yeah, but considering the output is very bounded... you are technically
correct, but I have a hard time caring. Making it a vsnprintf modifier
would make that issue go away though. I'll see if I can figure out how
to do it.
Output's again bounded so it's not _buggy_ as is, but this one I agree
more - I'll switch it.
> > +bool is_zero(const char *p, size_t n)
> > +{
> > + for (size_t i = 0; i < n; i++)
>
> This doesn't build. While loop var decl in for loop is nice, the
> kernel isn't built in c99 mode. If you want to enable c99 mode
> kernel-wide, you're welcome to try but you can't flip that
> per-component.
If patches to enable c99 mode would be accepted I'd be happy to work on
them (provided I can find time, but I doubt it'd be much work).
That said, I'm just as happy to switch to something that builds in c89
mode here.
I don't really get your objection to jumping into the middle of loops...
sure it shouldn't be the first way you try to write something, but I
don't see anything inherently wrong with it. IMO it _can_ make the code
easier to follow.
> > +#undef bio_alloc_pages
>
> Why is this undef necessary? If it's necessary, why isn't there any
> explanation?
>From the dynamic fault code, should've been removed.
>
> > +int bio_alloc_pages(struct bio *bio, gfp_t gfp)
> > +{
> > + int i;
> > + struct bio_vec *bv;
>
> New line missing.
>
> > + bio_for_each_segment(bv, bio, i) {
> > + bv->bv_page = alloc_page(gfp);
> > + if (!bv->bv_page) {
> > + while (bv-- != bio->bi_io_vec + bio->bi_idx)
> > + __free_page(bv->bv_page);
> > + return -ENOMEM;
> > + }
> > + }
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(bio_alloc_pages);
> > +
> > +struct bio *bio_split_front(struct bio *bio, int sectors, bio_alloc_fn *_alloc,
> > + gfp_t gfp, struct bio_set *bs)
> > +{
> > + unsigned idx, vcnt = 0, nbytes = sectors << 9;
> > + struct bio_vec *bv;
> > + struct bio *ret = NULL;
> > +
> > + struct bio *alloc(int n)
> > + {
> > + if (bs)
> > + return bio_alloc_bioset(gfp, n, bs);
> > + else if (_alloc)
> > + return _alloc(gfp, n);
> > + else
> > + return bio_kmalloc(gfp, n);
> > + }
>
> These are now separate patch series, right? But, please don't use
> nested functions. Apart from being very unconventional (does gnu99
> even allow this?), the implicit outer scope access is dangerous when
> mixed with context bouncing which is rather common in kernel. We
> (well, at least I) actually want cross stack frame accesses to be
> explicit.
Yes. I took out the nested function in the newer version (I never liked
the way allocation worked in the old code and I finally figured out a
sane way of doing it).
What do you mean by context bouncing? IME the problem with nested
functions in the kernel is the trampolines gcc can silently generate
(which is a serious problem).
No important difference, I just never saw bitmap_weight() before - I'll
switch to that. (These are faster, but bigger and in the kernel I highly
doubt we've a workload where the performance of popcount justifies the
extra memory).
>
> > +#ifndef USHRT_MAX
> > +#define USHRT_MAX ((u16)(~0U))
> > +#define SHRT_MAX ((s16)(USHRT_MAX>>1))
> > +#endif
> ...
>
> These compat macros can be removed for upstream submission, right?
This one I'm not getting rid of unless you know a better way of doing it
than I do - I use it all over the place and well, duplication.
> > +#define DECLARE_HEAP(type, name)
> > + struct {
> > + size_t size, used;
> > + type *data;
> > + } name
> > +
> > +#define init_heap(heap, _size, gfp)
>
> Ummm.... so, essentially templates done in macros. Please don't do
> that. Definitely NACK on this.
I have a passionate... dislike of templates, but do you have any
alternatives? I don't know any other way of implementing this that
doesn't give up typechecking, and especially for the fifo code that
typechecking is just too important to give up.
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-23-2012, 03:36 AM
Joe Perches
Bcache: generic utility code
On Tue, 2012-05-22 at 23:12 -0400, Kent Overstreet wrote:
> On Tue, May 22, 2012 at 02:17:06PM -0700, Tejun Heo wrote:
[]
> > > +ssize_t hprint(char *buf, int64_t v)
> > > +{
> > > + static const char units[] = "?kMGTPEZY";
> > > + char dec[3] = "";
> > > + int u, t = 0;
> > > +
> > > + for (u = 0; v >= 1024 || v <= -1024; u++) {
> > > + t = v & ~(~0 << 10);
> > > + v >>= 10;
> > > + }
> > > +
> > > + if (!u)
> > > + return sprintf(buf, "%llu", v);
> > > +
> > > + if (v < 100 && v > -100)
> > > + sprintf(dec, ".%i", t / 100);
> > > +
> > > + return sprintf(buf, "%lli%s%c", v, dec, units[u]);
> > > +}
> > > +EXPORT_SYMBOL_GPL(hprint);
> >
> > Not your fault but maybe we want integer vsnprintf modifier for this.
>
> Yes.
or maybe yet another lib/vsprintf pointer extension
like %pD with some descriptors after the %pD for
type, width and precision.
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-23-2012, 05:08 AM
Tejun Heo
Bcache: generic utility code
Hey,
On Tue, May 22, 2012 at 11:12:14PM -0400, Kent Overstreet wrote:
> On Tue, May 22, 2012 at 02:17:06PM -0700, Tejun Heo wrote:
> As you can probably tell I'm strongly biased against duplication when
> it's a question of macros vs. duplication - but if we can make the
> commend backend code + wrapper approach work that's even better (smaller
> code size ftw). It'll be tricky to get u64 vs. int64 right, but I'll
> take a stab at it.
Duplication does suck but it's something which can be traded off too.
It's case-by-case, I suppose.
> > Also, sprintf() sucks.
>
> Yeah, but considering the output is very bounded... you are technically
> correct, but I have a hard time caring. Making it a vsnprintf modifier
> would make that issue go away though. I'll see if I can figure out how
> to do it.
Block layer just fixed a uuid print buffer overflow bug caused by use
of sprintf() - vsnprintf used more delimiters than the code calling it
expected. When think kind of bugs trigger on stack buffer, they can
be quite a headache. IMHO it's much more preferable to have an extra
argument to limit buffer size in most cases.
> > This doesn't build. While loop var decl in for loop is nice, the
> > kernel isn't built in c99 mode. If you want to enable c99 mode
> > kernel-wide, you're welcome to try but you can't flip that
> > per-component.
>
> If patches to enable c99 mode would be accepted I'd be happy to work on
> them (provided I can find time, but I doubt it'd be much work).
I don't think it's gonna be acceptable. There isn't enough benefit at
this point to justify the churn - the only thing I can think of is
loop variable declaration which I don't think is enough.
> > > +EXPORT_SYMBOL_GPL(parse_uuid);
> >
> > Hmmm... can't we just enforce fixed format used by vsnprintf()?
>
> I don't follow - vsnprintf() is output, this is input...
Oh, I meant, can't we just require input to use the same exact format
used by vsnprintf(). Kernel being kind on pparameter inputs isn't
necessary and often leads to unexpected bugs anyway and if the format
is fixed, single call to sscanf() is enough.
> > > + bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0;
> > > + goto start;
> > > +
> > > + for (; size; bio->bi_vcnt++, bv++) {
> > > + bv->bv_offset = 0;
> > > +start: bv->bv_len = min_t(size_t, PAGE_SIZE - bv->bv_offset,
> > > + size);
> >
> > Please don't do this.
>
> I don't really get your objection to jumping into the middle of loops...
> sure it shouldn't be the first way you try to write something, but I
> don't see anything inherently wrong with it. IMO it _can_ make the code
> easier to follow.
Easier for whom is the question, I guess. We have only a couple
different patterns of goto in use in kernel. When usage deviates from
those, people get annoyed. It's not like goto is a pretty thing to
begin with.
> > These are now separate patch series, right? But, please don't use
> > nested functions. Apart from being very unconventional (does gnu99
> > even allow this?), the implicit outer scope access is dangerous when
> > mixed with context bouncing which is rather common in kernel. We
> > (well, at least I) actually want cross stack frame accesses to be
> > explicit.
>
> Yes. I took out the nested function in the newer version (I never liked
> the way allocation worked in the old code and I finally figured out a
> sane way of doing it).
>
> What do you mean by context bouncing? IME the problem with nested
> functions in the kernel is the trampolines gcc can silently generate
> (which is a serious problem).
I meant async execution. e.g. Passing nested function to workqueue.
By the time the nested function executes the parent frame is already
gone.
> > How are these different from bitmap_weight()?
>
> No important difference, I just never saw bitmap_weight() before - I'll
> switch to that. (These are faster, but bigger and in the kernel I highly
> doubt we've a workload where the performance of popcount justifies the
> extra memory).
I don't think these will be actually faster. bitmap_weight() is
pretty heavily optimized with constant shortcuts and arch dependent
implementations.
> > > +static inline void SET_##name(type *k, uint64_t v)
> > > +{
> > > + k->field &= ~(~((uint64_t) ~0 << size) << offset);
> > > + k->field |= v << offset;
> > > +}
> >
> > More function defining macros.
>
> This one I'm not getting rid of unless you know a better way of doing it
> than I do - I use it all over the place and well, duplication.
I think that macro abuses tend to lead to worse code in general.
Exotic stuff becomes less painful with magic macros which in turn make
people use magic stuff even when more conventional mechanisms can do.
Maybe these are simple enough. Maybe, I don't know.
> > > +#define DECLARE_HEAP(type, name)
> > > + struct {
> > > + size_t size, used;
> > > + type *data;
> > > + } name
> > > +
> > > +#define init_heap(heap, _size, gfp)
> >
> > Ummm.... so, essentially templates done in macros. Please don't do
> > that. Definitely NACK on this.
>
> I have a passionate... dislike of templates, but do you have any
> alternatives? I don't know any other way of implementing this that
> doesn't give up typechecking, and especially for the fifo code that
> typechecking is just too important to give up.
Unsure but either giving up type safety or implementing logic as
functions and wrap them with macros doing typechecks would be better.
Can't you use the existing prio_tree or prio_heap?
> > Is this *really* necessary?
>
> This one might be excessive - but if we can implement memparse() +
> variable limit correctly that would certainly get rid of this.
Is type-dependent variable limit really necessary? A lot of sysfs and
other interface doesn't care about input validation as long as it
doesn't break kernel.
Thanks.
--
tejun
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-23-2012, 05:54 AM
Kent Overstreet
Bcache: generic utility code
On Tue, May 22, 2012 at 10:08:08PM -0700, Tejun Heo wrote:
> Block layer just fixed a uuid print buffer overflow bug caused by use
> of sprintf() - vsnprintf used more delimiters than the code calling it
> expected. When think kind of bugs trigger on stack buffer, they can
> be quite a headache. IMHO it's much more preferable to have an extra
> argument to limit buffer size in most cases.
Well, with the removal of hprint() all uses of sprintf() that are left
save one are in sysfs.c, where size would be PAGE_SIZE.
(The one in super.c I really ought to get rid of, though).
>
> > > This doesn't build. While loop var decl in for loop is nice, the
> > > kernel isn't built in c99 mode. If you want to enable c99 mode
> > > kernel-wide, you're welcome to try but you can't flip that
> > > per-component.
> >
> > If patches to enable c99 mode would be accepted I'd be happy to work on
> > them (provided I can find time, but I doubt it'd be much work).
>
> I don't think it's gonna be acceptable. There isn't enough benefit at
> this point to justify the churn - the only thing I can think of is
> loop variable declaration which I don't think is enough.
If it would end up being more than a couple patches I'd definitely
agree. It would be handy though for compiling the kernel with clang -
not that I care about running kernels built with clang, but I would
happily take advantage of the compiler warnings.
But for the moment I think I'll chip away at c99 only stuff in bcache,
most of the use cases I really don't care about (maybe all of them now).
>
> > > > +EXPORT_SYMBOL_GPL(parse_uuid);
> > >
> > > Hmmm... can't we just enforce fixed format used by vsnprintf()?
> >
> > I don't follow - vsnprintf() is output, this is input...
>
> Oh, I meant, can't we just require input to use the same exact format
> used by vsnprintf(). Kernel being kind on pparameter inputs isn't
> necessary and often leads to unexpected bugs anyway and if the format
> is fixed, single call to sscanf() is enough.
Ahh - that is a good idea. Yeah, I'll have a look.
>
> > > > + bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0;
> > > > + goto start;
> > > > +
> > > > + for (; size; bio->bi_vcnt++, bv++) {
> > > > + bv->bv_offset = 0;
> > > > +start: bv->bv_len = min_t(size_t, PAGE_SIZE - bv->bv_offset,
> > > > + size);
> > >
> > > Please don't do this.
> >
> > I don't really get your objection to jumping into the middle of loops...
> > sure it shouldn't be the first way you try to write something, but I
> > don't see anything inherently wrong with it. IMO it _can_ make the code
> > easier to follow.
>
> Easier for whom is the question, I guess. We have only a couple
> different patterns of goto in use in kernel. When usage deviates from
> those, people get annoyed. It's not like goto is a pretty thing to
> begin with.
>
> > > These are now separate patch series, right? But, please don't use
> > > nested functions. Apart from being very unconventional (does gnu99
> > > even allow this?), the implicit outer scope access is dangerous when
> > > mixed with context bouncing which is rather common in kernel. We
> > > (well, at least I) actually want cross stack frame accesses to be
> > > explicit.
> >
> > Yes. I took out the nested function in the newer version (I never liked
> > the way allocation worked in the old code and I finally figured out a
> > sane way of doing it).
> >
> > What do you mean by context bouncing? IME the problem with nested
> > functions in the kernel is the trampolines gcc can silently generate
> > (which is a serious problem).
>
> I meant async execution. e.g. Passing nested function to workqueue.
> By the time the nested function executes the parent frame is already
> gone.
Oh, that would be bad
>
> > > How are these different from bitmap_weight()?
> >
> > No important difference, I just never saw bitmap_weight() before - I'll
> > switch to that. (These are faster, but bigger and in the kernel I highly
> > doubt we've a workload where the performance of popcount justifies the
> > extra memory).
>
> I don't think these will be actually faster. bitmap_weight() is
> pretty heavily optimized with constant shortcuts and arch dependent
> implementations.
Ah, I didn't notice the arch specific versions in my brief cscoping,
just an ffs() based one.
>
> > > > +static inline void SET_##name(type *k, uint64_t v)
> > > > +{
> > > > + k->field &= ~(~((uint64_t) ~0 << size) << offset);
> > > > + k->field |= v << offset;
> > > > +}
> > >
> > > More function defining macros.
> >
> > This one I'm not getting rid of unless you know a better way of doing it
> > than I do - I use it all over the place and well, duplication.
>
> I think that macro abuses tend to lead to worse code in general.
> Exotic stuff becomes less painful with magic macros which in turn make
> people use magic stuff even when more conventional mechanisms can do.
> Maybe these are simple enough. Maybe, I don't know.
Well, I'd really prefer it if C bitfields were well defined enough to
use them for an on disk format, but... they aren't. That's all it's
implementing.
> > > > +#define DECLARE_HEAP(type, name)
> > > > + struct {
> > > > + size_t size, used;
> > > > + type *data;
> > > > + } name
> > > > +
> > > > +#define init_heap(heap, _size, gfp)
> > >
> > > Ummm.... so, essentially templates done in macros. Please don't do
> > > that. Definitely NACK on this.
> >
> > I have a passionate... dislike of templates, but do you have any
> > alternatives? I don't know any other way of implementing this that
> > doesn't give up typechecking, and especially for the fifo code that
> > typechecking is just too important to give up.
>
> Unsure but either giving up type safety or implementing logic as
> functions and wrap them with macros doing typechecks would be better.
> Can't you use the existing prio_tree or prio_heap?
I'd definitely be fine with implementing both the heap and the fifo code
as functions wrapped in macros that provided the typechecking.
The existing prio_heap code isn't sufficient to replace my heap code -
it's missing heap_sift() and heap_full() (well, heap_full() could be
open coded with prio_heap).
Suppose it wouldn't be that much work to add that to the existing
prio_heap code and wrap it in some typechecking macros.
> Is type-dependent variable limit really necessary? A lot of sysfs and
> other interface doesn't care about input validation as long as it
> doesn't break kernel.
For raw integers I wouldn't care much, but where integers with human
readable units are accepted I'd really hate to lose the input validation
as it's really easy for a user to accidently overflow an integer.
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
05-23-2012, 03:15 PM
Vivek Goyal
Bcache: generic utility code
On Tue, May 22, 2012 at 02:17:06PM -0700, Tejun Heo wrote:
> Hello, Kent.
>
> I've been reading the code and am still very far from understanding
> the whole thing but here are general impressions upto this point.
>
> * I started reading from get_bucket(), mostly because I wasn't sure
> where to start. It would be very helpful to the reviewers and
> future participants if there's a design doc and more comments (much
> more). The code is on the big side and the problem is exacerbated
> by use of somewhat unconventional constructs and conventions and
> lack of documentation and comments.
I totally agreed. There is a lot going on and design doc is going to
help a lot while reviewing.
> * Too many smart macros. Macros suck. Smart ones double suck.
I had the same impression when I tried to read the code last. Too many
macros and it makes reading code really difficult.
[..]
> * Somewhat related to the above, I'm not a fan of super-verbose
> symbols but I *hope* that the variable names were just a tiny bit
> more descriptive. At least, the ones used as arguments.
Another thing is that keep variable names consistent. Last time I looked,
same name "c" was being used to represent cached_dev or cache_set or
something else too. If we keep variable name same to represent same
data structure, it becomes easier to read the code. I was totally lost
and always had to go back to figure out what "c" is representing, what
"d" is representing etc.
Thanks
Vivek
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel