tech-kern archive

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

Re: EINVAL from copyin/out - how?



    Date:        Fri, 15 Aug 2014 10:56:07 +0200
    From:        "Thomas Schmitt" <scdbackup%gmx.net@localhost>
    Message-ID:  <19156659087387845681%scdbackup.webframe.org@localhost>


  | Given the fact that you located the origin of EINVAL outside
  | of cd9660 (resp. underneath), i expect that ISO 9660 structure
  | aspects are only indirectly involved.

I agree, particularly as it works sometimes...

  | Especially the difference between i386 and amd64 can hardly
  | be explained by ISO 9660 aspects.

Unless there was some blatant unportable architecture dependant code
(assuming sizeof(char *) or something) - I agree, and if there were
I'd expect it to never work, or never work for some particular files,
or something like that.

  | My favority suspect would now be the code underneath bread(9)
  | and especially the mechanism which looks up the buffer and
  | decides whether a physical read operation on the DVD is needed.

Could be ... but (and this may be just the time since I really understood
how kernels worked has been so long that my assumptions no matter match
reality) the reason I'm concentrating on the fults when using tar is that
the tar file read loop is basically

        while ((n = read(fd, buf, bufzize)) > 0)
                write(ofd, buf, n);

along with the stuff that writes the header before each file, and makes
sure then that the output file contains exactly the number of bytes that
the header said it would contain (no more, no less, even if the file
changes size while the loop is happening).   All that is working fine
(ie: tar does exactly what it should be doing given what the kernel is doing).

The read() returns -1, with errno == EINVAL (on the first read of one of
the affected fies).  Here is where I may not be understanding the kernel
operation as it currently is ... for a read (after validating the fd, etc)
the kernell (as I remember it) goes through the filesystem, using the vnode,
gets the appropriate data (from the cache, or by accessing the device driver
for the underlying device upon whilch the filesystem is mounted).  During
this there can be EIO etc if things fail - but assuming it all succeeds
(and nly if it succeeds) the data (or perhaps just some of it if it was a
large read request - not relevent here, tar reads in reasonable buffer
sizes..) is iiving somewhere in kernel memory - the last step before returning
is to copy that out to user space - that's copyoyt()'s function (if the
user address is bogus, EFAULT will happen - tar isn't passing bogus addresses
and there are no EFAULTs).   There's no guarantee that the user's buffer
is all in mapped memory (in fact, for some of my tests, I'd be surprised if
any of it was, unless the same buffer had been used to construct and write the
file header) so zfod page faults might happen during the copyut (but those
should not in any way be affected by the source of the copy - the cd9660 fs
stuff).

That's where I don't see (currently) where the EINVAL can be coming from.

  | How about having a wrapper around bread(9), which checks for
  | error replies of bread(9) and eventually prints some message
  | which tells the failed block number.

Sure, I can do that - but if bread() failed, I'd expect to see EIO, not
EINVAL (normally anyway) - and unless in these modern kernels the bread()
is somehow being deferred until the cata is needed for copyout() I can't
see how it could possibly be relevant.  But it is certainly an easy thing
to try, so I'll do that.

  | Alternatively to an inspection of the ISO image, or if the block
  | number is implausible, you could equip the wrapper and its calls
  | with a string parameter which identifies the wrapper's caller.

I'll do that for sure anyway - stray output without knowing the source
just causes problems and confusion later.

Thanks,

kre



Home | Main Index | Thread Index | Old Index