Re: [v4.9 Regression] vfs,mm: fix a dead loop in truncate_inode_pages_range()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Dec 14, 2016 at 12:27 PM, Linus Torvalds
<torvalds@xxxxxxxxxxxxxxxxxxxx> wrote:
>
> The EINVAL was always wrong, I think, but it made some (bad) sense
> when you think of the issue as being the result of somebody trying to
> do something bad. But it isn't actually an error.

Here's an example program that I think shows this on pretty much any filesystem.

Run with something like

    strace ./a.out < ./a.out

and then look at the final part of the trace, which will look something like

    lseek(0, 17592186040320, SEEK_SET)      = 17592186040320
    read(0, 0x7ffe1d2df140, 10)             = -1 EINVAL (Invalid argument)
    lseek(0, 17592186040319, SEEK_SET)      = 17592186040319
    read(0, "", 10)                         = 0

and that EINVAL from the first read is just bogus and wrong. We're
clearly at a good offset - the lseek() succeeded - and we're clearly
past the end of the file, so we should be returning 0 (for that EOF).

And the second read succeeds just because we've done a seek to one byte less.

I'm not guaranteeing that I got that stupid binary search for the
filesystem s_maxsize right, but it worked for me. This is a truly
crappy test program, but whatever.

              Linus

---
#define _LARGEFILE64_SOURCE
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
        char buf[10];
        off64_t large_offset = 1000000;
        off64_t max_offset = (~(unsigned long long)0)>>1;

        for (;;) {
                off64_t try_offset = (unsigned long long)(max_offset +
large_offset + 1)/2;

                if (try_offset >= max_offset)
                        break;

                if (lseek64(0, try_offset, SEEK_SET) < 0)
                        max_offset = try_offset;
                else
                        large_offset = try_offset;
        }

        lseek64(0, large_offset, SEEK_SET);
        read(0, buf, 10);

        lseek64(0, large_offset-1, SEEK_SET);
        read(0, buf, 10);

        return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]