diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index e3572914c997..70870f766fbf 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -3297,6 +3298,48 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, int err; int cleanup_fd; uint64_t action_handle = 0; + struct stat sb; + + /* + * The only way fstat can fail is if we do not have a valid file + * descriptor. + */ + if (fstat(infd, &sb) == -1) { + perror("fstat"); + return (-2); + } + +#ifdef __linux__ +#ifndef F_SETPIPE_SZ +#define F_SETPIPE_SZ (F_SETLEASE + 7) +#endif /* F_SETPIPE_SZ */ + +#ifndef F_GETPIPE_SZ +#define F_GETPIPE_SZ (F_GETLEASE + 7) +#endif /* F_GETPIPE_SZ */ + + /* + * It is not uncommon for gigabytes to be processed in zfs receive. + * Speculatively increase the buffer size via Linux-specific fcntl() + * call. + */ + if (S_ISFIFO(sb.st_mode)) { + FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "r"); + + if (procf != NULL) { + unsigned long max_psize; + long cur_psize; + if (fscanf(procf, "%lu", &max_psize) > 0) { + cur_psize = fcntl(infd, F_GETPIPE_SZ); + if (cur_psize > 0 && + max_psize > (unsigned long) cur_psize) + (void) fcntl(infd, F_SETPIPE_SZ, + max_psize); + } + fclose(procf); + } + } +#endif /* __linux__ */ cleanup_fd = open(ZFS_DEV, O_RDWR); VERIFY(cleanup_fd >= 0);