[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <alpine.LRH.2.02.2204121253260.26107@file01.intranet.prod.int.rdu2.redhat.com>
Date: Tue, 12 Apr 2022 13:42:06 -0400 (EDT)
From: Mikulas Patocka <mpatocka@...hat.com>
To: Linus Torvalds <torvalds@...ux-foundation.org>
cc: Alexander Viro <viro@...iv.linux.org.uk>,
linux-fsdevel <linux-fsdevel@...r.kernel.org>,
Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
Matthew Wilcox <willy@...radead.org>
Subject: Re: [PATCH] stat: fix inconsistency between struct stat and struct
compat_stat
On Tue, 12 Apr 2022, Linus Torvalds wrote:
> On Mon, Apr 11, 2022 at 11:41 PM Mikulas Patocka <mpatocka@...hat.com> wrote:
> >
> > Also, if the st_dev and st_rdev values are 32-bit, we don't have to use
> > old_valid_dev to test if the value fits into them. This fixes -EOVERFLOW
> > on filesystems that are on NVMe because NVMe uses the major number 259.
>
> The problem with this part of the patch is that this:
>
> > @@ -353,7 +352,7 @@ static int cp_new_stat(struct kstat *sta
> > #endif
> >
> > INIT_STRUCT_STAT_PADDING(tmp);
> > - tmp.st_dev = encode_dev(stat->dev);
> > + tmp.st_dev = new_encode_dev(stat->dev);
>
> completely changes the format of that st_dev field.
we have these definitions:
static __always_inline u16 old_encode_dev(dev_t dev)
{
return (MAJOR(dev) << 8) | MINOR(dev);
}
static __always_inline u32 new_encode_dev(dev_t dev)
{
unsigned major = MAJOR(dev);
unsigned minor = MINOR(dev);
return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
}
As long as both major and minor numbers are less than 256, these functions
return equivalent results. So, I think it's safe to replace old_encode_dev
with new_encode_dev.
old_encode_dev shouldn't be called with minor >= 256, because it blends
the upper minor bits into the major field - the kernel doesn't do this and
checks the value with old_valid_dev before calling old_encode_dev. But
when old_valid_dev returns true, it doesn't matter if you use
old_encode_dev or new_encode_dev - both give equivalent results.
When I tested it, both gcc and openwatcom return st_dev 0x10301, which is
the expected value (the NVMe device has major 259 and minor 1).
> (b) we could just hide the bits in upper bits instead.
>
> So what I suggest we do is to make old_encode_dev() put the minor bits
> in bits 0..7 _and_ 16..23, and the major bits in 8..15 _and_ 24..32.
new_encode_dev puts the minor value into bits 0..7, 20..31 and the major
value into bits 8..19
So, we can use this instead of inventing a new format.
Mikulas
Powered by blists - more mailing lists