[PATCH,CFT] libc: add posix_fallocate()

Natanael Copa natanael.copa at gmail.com
Thu Jul 5 07:44:59 UTC 2012


On Tue, Jun 19, 2012 at 12:05 PM, Natanael Copa <natanael.copa at gmail.com> wrote:
> On Mon, Jun 18, 2012 at 5:27 PM, Bernhard Reutner-Fischer
> <rep.dot.nop at gmail.com> wrote:
>> On 18 April 2012 14:45, Bernhard Reutner-Fischer <rep.dot.nop at gmail.com> wrote:
>>> On 17 April 2012 23:18, Khem Raj <raj.khem at gmail.com> wrote:
>>>> On Tue, Apr 17, 2012 at 12:30 AM, Bernhard Reutner-Fischer
>>>> <rep.dot.nop at gmail.com> wrote:
>>>>> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
>>>>> ---
>>>>>  include/fcntl.h                                  |    4 +-
>>>>>  libc/sysdeps/linux/common/Makefile.in            |    3 +-
>>>>>  libc/sysdeps/linux/common/bits/kernel-features.h |    8 ++
>>>>>  libc/sysdeps/linux/common/posix_fallocate.c      |   43 ++++++++
>>>>>  libc/sysdeps/linux/common/posix_fallocate64.c    |   39 +++++++
>>>>>  libc/sysdeps/linux/common/stubs.c                |    4 +
>>>>>  test/.gitignore                                  |    1 +
>>>>>  test/unistd/Makefile.in                          |    3 +
>>>>>  test/unistd/tst-posix_fallocate.c                |  121 ++++++++++++++++++++++
>>>>>  9 files changed, 222 insertions(+), 4 deletions(-)
>>>>>  create mode 100644 libc/sysdeps/linux/common/posix_fallocate.c
>>>>>  create mode 100644 libc/sysdeps/linux/common/posix_fallocate64.c
>>>>>  create mode 100644 test/unistd/tst-posix_fallocate.c
>>>>>
>>>>
>>>> Looks ok to me. Did you test it on a 32bit and a 64 bit arch ?
>>>
>>> I compiled it on x86 and x86_64 where it generated reasonably looking code.
>>> No runtime-tests performed yet, thus Call For Testers..
>>>
>>>> mips would be interesting.
>>>
>>> mips and e.g. ppc* variants of bitness and endianess would indeed be
>>> interresting, yes.
>>
>> Anyone? :)
>
> I have it backported to 0.9.33.2.
>
>
> Works on x86_64 (the test case passes)
>
>
> on x86:
>
> The output of failed test is:
> 1st posix_fallocate call failed
>
> The error code appears to be "no such file or directory"
>
> I have a vauge memory about syscalls with N args (6?) beeing broken.

I have looked into this a bit. The generated assembly code is broke.
ebp should be set to zero but it is not. It looks like gcc gets
confused in referring to the local variable called "zero". Not sure if
its a gcc bug or why it happens.

Dump of assembler code for function posix_fallocate:
   0x4bdf2bb8 <+0>:	push   %edi
   0x4bdf2bb9 <+1>:	push   %esi
   0x4bdf2bba <+2>:	push   %ecx
   0x4bdf2bbb <+3>:	movl   $0x0,(%esp)    # zero = 0
   0x4bdf2bc2 <+10>:	xor    %ecx,%ecx
   0x4bdf2bc4 <+12>:	mov    0x18(%esp),%edi
   0x4bdf2bc8 <+16>:	mov    0x14(%esp),%edx
   0x4bdf2bcc <+20>:	mov    0x10(%esp),%eax
   0x4bdf2bd0 <+24>:	mov    %ecx,%esi
   0x4bdf2bd2 <+26>:	push   %ebx
   0x4bdf2bd3 <+27>:	mov    %eax,%ebx
   0x4bdf2bd5 <+29>:	push   %ebp
   0x4bdf2bd6 <+30>:	mov    (%esp),%ebp
                        ^^^^^^^^^^^^^^^^^^
I think it goes wrong here. Due to the previous push ebx, (%esp) no
longer points to the "zero" variable. and a bad value gets stored into
ebp. Syscall fails with "File too large".

I stepped myself here with gdb and setting ebp = 0 made the syscall
exit with success.

   0x4bdf2bd9 <+33>:	mov    $0x144,%eax
   0x4bdf2bde <+38>:	int    $0x80
   0x4bdf2be0 <+40>:	pop    %ebp
   0x4bdf2be1 <+41>:	pop    %ebx
   0x4bdf2be2 <+42>:	cmp    $0xfffff000,%eax
   0x4bdf2be7 <+47>:	jbe    0x4bdf2bed <posix_fallocate+53>
   0x4bdf2be9 <+49>:	mov    %eax,%esi
   0x4bdf2beb <+51>:	neg    %esi
   0x4bdf2bed <+53>:	mov    %esi,%eax
   0x4bdf2bef <+55>:	pop    %edx
   0x4bdf2bf0 <+56>:	pop    %esi
   0x4bdf2bf1 <+57>:	pop    %edi
   0x4bdf2bf2 <+58>:	ret
End of assembler dump.

It is possible to work around it by allowing the 6th syscall arg be an
immediate value rather than force it to be a memory reference. I'd say
this is a good idea anyways.

diff --git a/libc/sysdeps/linux/i386/bits/syscalls.h b/libc/sysdeps/linux/i386/
bits/syscalls.h
index 9fb4f35..566b5ac 100644
--- a/libc/sysdeps/linux/i386/bits/syscalls.h
+++ b/libc/sysdeps/linux/i386/bits/syscalls.h
@@ -136,7 +136,7 @@ __asm__ (
 #define ASMFMT_5(arg1, arg2, arg3, arg4, arg5) \
        , "a" (arg1), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)
 #define ASMFMT_6(arg1, arg2, arg3, arg4, arg5, arg6) \
-       , "a" (arg1), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5), "m" (arg6
)
+       , "a" (arg1), "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5), "g" (arg6
)

 #else /* !PIC */

Then you could remove the "uint32_t zero = 0".

--- ./libc/sysdeps/linux/common/posix_fallocate.c.orig
+++ ./libc/sysdeps/linux/common/posix_fallocate.c
@@ -22,11 +22,10 @@
        uint32_t off_low = offset;
        uint32_t len_low = len;
        /* may assert that these >>31 are 0 */
-       uint32_t zero = 0;
        INTERNAL_SYSCALL_DECL(err);
        ret = (int) (INTERNAL_SYSCALL(fallocate, err, 6, fd, 0,
-               __LONG_LONG_PAIR (zero, off_low),
-               __LONG_LONG_PAIR (zero, len_low)));
+               __LONG_LONG_PAIR (0, off_low),
+               __LONG_LONG_PAIR (0, len_low)));
 # elif __WORDSIZE == 64
        INTERNAL_SYSCALL_DECL(err);
        ret = (int) (INTERNAL_SYSCALL(fallocate, err, 4, fd, 0, offset, len));

I pushed the posix_fallocate patch and the fix/workaround to alpine
linux. It works now.
http://git.alpinelinux.org/cgit/aports/tree/main/libc0.9.32/posix_fallocate-fix.patch


> Appears that posix_fallocate is the only syscall that uses all 6 args.

This was wrong. There are many.

> I wonder if it might be due to our syscalls.h patch for stack
> unwinding, but I doubt that.
> http://git.alpinelinux.org/cgit/aports/plain/main/libc0.9.32/0007-libc-x86-fix-stack-unwinding-and-backtrace-informati.patch


>
>
> --
> Natanael Copa



-- 
Natanael Copa


More information about the uClibc mailing list