• Linus Torvalds's avatar
    uaccess: implement a proper unsafe_copy_to_user() and switch filldir over to it · c512c691
    Linus Torvalds authored
    In commit 9f79b78e ("Convert filldir[64]() from __put_user() to
    unsafe_put_user()") I made filldir() use unsafe_put_user(), which
    improves code generation on x86 enormously.
    
    But because we didn't have a "unsafe_copy_to_user()", the dirent name
    copy was also done by hand with unsafe_put_user() in a loop, and it
    turns out that a lot of other architectures didn't like that, because
    unlike x86, they have various alignment issues.
    
    Most non-x86 architectures trap and fix it up, and some (like xtensa)
    will just fail unaligned put_user() accesses unconditionally.  Which
    makes that "copy using put_user() in a loop" not work for them at all.
    
    I could make that code do explicit alignment etc, but the architectures
    that don't like unaligned accesses also don't really use the fancy
    "user_access_begin/end()" model, so they might just use the regular old
    __copy_to_user() interface.
    
    So this commit takes that looping implementation, turns it into the x86
    version of "unsafe_copy_to_user()", and makes other architectures
    implement the unsafe copy version as __copy_to_user() (the same way they
    do for the other unsafe_xyz() accessor functions).
    
    Note that it only does this for the copying _to_ user space, and we
    still don't have a unsafe version of copy_from_user().
    
    That's partly because we have no current users of it, but also partly
    because the copy_from_user() case is slightly different and cannot
    efficiently be implemented in terms of a unsafe_get_user() loop (because
    gcc can't do asm goto with outputs).
    
    It would be trivial to do this using "rep movsb", which would work
    really nicely on newer x86 cores, but really badly on some older ones.
    
    Al Viro is looking at cleaning up all our user copy routines to make
    this all a non-issue, but for now we have this simple-but-stupid version
    for x86 that works fine for the dirent name copy case because those
    names are short strings and we simply don't need anything fancier.
    
    Fixes: 9f79b78e ("Convert filldir[64]() from __put_user() to unsafe_put_user()")
    Reported-by: default avatarGuenter Roeck <linux@roeck-us.net>
    Reported-and-tested-by: default avatarTony Luck <tony.luck@intel.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Max Filippov <jcmvbkbc@gmail.com>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    c512c691
uaccess.h 22.2 KB