On Tuesday 22 September 2015 11:46 PM, Yuriy Kolerov wrote: > Arguments offset and len in fallocate system call in Linux > kernel have 64-bit types.
Perhaps better to say that for common generic syscall ABI fallocate syscall handler in kernel expects 64 bit signed args for offset, len > However these arguments in fallocate > wrapper in uClibc may have 32-bit types. In this case it's > necessary to pass two 32-bit words to the systemc call for every > argument - an actual argument and its sign extension. No - this is not technically accurate. User space in theory can pass a true 64 bit value, not just a 32 bit value and a 32 bit sign extension. > Thus high word of 64-bit value must be 0 or 0xFFFFFFFF depending > on sign of the original 32-bit value (offset or len). It is how > sign extansion works - all high bits of the negative value must be 1. > > fallocate does sign extension incorrectly when 32 bit values are > passed (offset or len). It just fills the second word of 64-bit > value by zeros. E.g. fallocate works incorrectly when offset or > length is negative value - in this case kernel thinks that positive > values are passed. Again while the fix may be obvious, can u divulge the specific test case it fixes. > Signed-off-by: Yuriy Kolerov <[email protected]> > --- > libc/sysdeps/linux/common/fallocate.c | 10 ++++------ > 1 file changed, 4 insertions(+), 6 deletions(-) > > diff --git a/libc/sysdeps/linux/common/fallocate.c > b/libc/sysdeps/linux/common/fallocate.c > index b2309e9..446d9ef 100644 > --- a/libc/sysdeps/linux/common/fallocate.c > +++ b/libc/sysdeps/linux/common/fallocate.c > @@ -21,14 +21,12 @@ int attribute_hidden __libc_fallocate(int fd, int mode, > __off_t offset, __off_t > int ret; > > # if __WORDSIZE == 32 > - uint32_t off_low = offset; > - uint32_t len_low = len; > - /* may assert that these >>31 are 0 */ > - uint32_t zero = 0; > + int32_t offset_sign_extension = (offset < 0) ? 0xFFFFFFFF : 0; > + int32_t len_sign_extension = (len < 0) ? 0xFFFFFFFF : 0; > INTERNAL_SYSCALL_DECL(err); > ret = (int) (INTERNAL_SYSCALL(fallocate, err, 6, fd, mode, > - __LONG_LONG_PAIR (zero, off_low), > - __LONG_LONG_PAIR (zero, len_low))); > + __LONG_LONG_PAIR (offset_sign_extension, offset), > + __LONG_LONG_PAIR (len_sign_extension, len))); This is too ugly. Can u use existing macro OFF64_HI_LO() macro. Something like below: int64_t offset_ll = offset ; /* does appropriate sign extension */ int64_t len_ll = len; ret = (int) (INTERNAL_SYSCALL(fallocate, err, 6, fd, mode, OFF64_HI_LO(offset_ll), OFF64_HI_LO(len_ll)); > # elif __WORDSIZE == 64 > INTERNAL_SYSCALL_DECL(err); > ret = (int) (INTERNAL_SYSCALL(fallocate, err, 4, fd, mode, offset, > len)); _______________________________________________ uClibc mailing list [email protected] http://lists.busybox.net/mailman/listinfo/uclibc
