• Mateusz Guzik's avatar
    vfs: shave work on failed file open · 93faf426
    Mateusz Guzik authored
    Failed opens (mostly ENOENT) legitimately happen a lot, for example here
    are stats from stracing kernel build for few seconds (strace -fc make):
    
      % time     seconds  usecs/call     calls    errors syscall
      ------ ----------- ----------- --------- --------- ------------------
        0.76    0.076233           5     15040      3688 openat
    
    (this is tons of header files tried in different paths)
    
    In the common case of there being nothing to close (only the file object
    to free) there is a lot of overhead which can be avoided.
    
    This is most notably delegation of freeing to task_work, which comes
    with an enormous cost (see 021a160a ("fs: use __fput_sync in
    close(2)" for an example).
    
    Benchmarked with will-it-scale with a custom testcase based on
    tests/open1.c, stuffed into tests/openneg.c:
    [snip]
            while (1) {
                    int fd = open("/tmp/nonexistent", O_RDONLY);
                    assert(fd == -1);
    
                    (*iterations)++;
            }
    [/snip]
    
    Sapphire Rapids, openneg_processes -t 1 (ops/s):
    before:	1950013
    after:	2914973 (+49%)
    
    file refcount is checked as a safety belt against buggy consumers with
    an atomic cmpxchg. Technically it is not necessary, but it happens to
    not be measurable due to several other atomics which immediately follow.
    Optmizing them away to make this atomic into a problem is left as an
    exercise for the reader.
    
    v2:
    - unexport fput_badopen and move to fs/internal.h
    - handle the refcount with cmpxchg, adjust commentary accordingly
    - tweak the commit message
    Signed-off-by: default avatarMateusz Guzik <mjguzik@gmail.com>
    Link: https://lore.kernel.org/r/20230926162228.68666-1-mjguzik@gmail.comSigned-off-by: default avatarChristian Brauner <brauner@kernel.org>
    93faf426
file_table.c 12.7 KB