Hi Al,

it seems the following commit 523ac9afc73a ("switch default_file_splice_read() 
to use of pipe-backed iov_iter")
breaks sendfile from 9p fs into af_alg socket.
sendfile into af_alg is used by iproute2/tc.
I'm not sure whether it's 9p or crypto or vfs problem, but happy to test any 
patches.

The following program is a reduced test from iproute2.
On broken kernels it fails as:
$ ./a.out some_file
Error from sendfile (8192 vs 9624 bytes): Success

It seems to work fine when 'some_file' is on ext4 or tmpfs, so could be 9p 
related.

Thanks
------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/vfs.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/sendfile.h>
#include <sys/resource.h>

#include <linux/if_alg.h>

#include <arpa/inet.h>

#ifndef AF_ALG
#define AF_ALG 38
#endif

static int obj_hash(const char *object, uint8_t *out, size_t len)
{
        struct sockaddr_alg alg = {
                .salg_family    = AF_ALG,
                .salg_type      = "hash",
                .salg_name      = "sha1",
        };
        int ret, cfd, ofd, ffd;
        struct stat stbuff;
        ssize_t size;

        if (!object || len != 20)
                return -EINVAL;

        cfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        if (cfd < 0) {
                fprintf(stderr, "Cannot get AF_ALG socket: %s\n",
                        strerror(errno));
                return cfd;
        }

        ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg));
        if (ret < 0) {
                fprintf(stderr, "Error binding socket: %s\n", strerror(errno));
                goto out_cfd;
        }

        ofd = accept(cfd, NULL, 0);
        if (ofd < 0) {
                fprintf(stderr, "Error accepting socket: %s\n",
                        strerror(errno));
                ret = ofd;
                goto out_cfd;
        }

        ffd = open(object, O_RDONLY);
        if (ffd < 0) {
                fprintf(stderr, "Error opening object %s: %s\n",
                        object, strerror(errno));
                ret = ffd;
                goto out_ofd;
        }

        ret = fstat(ffd, &stbuff);
        if (ret < 0) {
                fprintf(stderr, "Error doing fstat: %s\n",
                        strerror(errno));
                goto out_ffd;
        }

        size = sendfile(ofd, ffd, NULL, stbuff.st_size);
        if (size != stbuff.st_size) {
                fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n",
                        size, stbuff.st_size, strerror(errno));
                ret = -1;
                goto out_ffd;
        }

        size = read(ofd, out, len);
        if (size != len) {
                fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n",
                        size, len, strerror(errno));
                ret = -1;
        } else {
                ret = 0;
        }
out_ffd:
        close(ffd);
out_ofd:
        close(ofd);
out_cfd:
        close(cfd);
        return ret;
}

int main(int ac, char **av)
{
        uint8_t hash[20] = {};

        if (ac != 2) {
                fprintf(stderr, "%s file\n", av[0]);
                return 1;
        }
        obj_hash(av[1], hash, sizeof(hash));
        printf("hash %llx\n", *(long long *)hash);
        return 0;
}

Reply via email to