• Omar Sandoval's avatar
    Btrfs: fix error handling in btrfs_truncate() · d5014738
    Omar Sandoval authored
    Jun Wu at Facebook reported that an internal service was seeing a return
    value of 1 from ftruncate() on Btrfs in some cases. This is coming from
    the NEED_TRUNCATE_BLOCK return value from btrfs_truncate_inode_items().
    
    btrfs_truncate() uses two variables for error handling, ret and err.
    When btrfs_truncate_inode_items() returns non-zero, we set err to the
    return value. However, NEED_TRUNCATE_BLOCK is not an error. Make sure we
    only set err if ret is an error (i.e., negative).
    
    To reproduce the issue: mount a filesystem with -o compress-force=zstd
    and the following program will encounter return value of 1 from
    ftruncate:
    
    int main(void) {
            char buf[256] = { 0 };
            int ret;
            int fd;
    
            fd = open("test", O_CREAT | O_WRONLY | O_TRUNC, 0666);
            if (fd == -1) {
                    perror("open");
                    return EXIT_FAILURE;
            }
    
            if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
                    perror("write");
                    close(fd);
                    return EXIT_FAILURE;
            }
    
            if (fsync(fd) == -1) {
                    perror("fsync");
                    close(fd);
                    return EXIT_FAILURE;
            }
    
            ret = ftruncate(fd, 128);
            if (ret) {
                    printf("ftruncate() returned %d\n", ret);
                    close(fd);
                    return EXIT_FAILURE;
            }
    
            close(fd);
            return EXIT_SUCCESS;
    }
    
    Fixes: ddfae63c ("btrfs: move btrfs_truncate_block out of trans handle")
    CC: stable@vger.kernel.org # 4.15+
    Reported-by: default avatarJun Wu <quark@fb.com>
    Signed-off-by: default avatarOmar Sandoval <osandov@fb.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    d5014738
inode.c 287 KB