Skip to content

Commit

Permalink
Increase Linux pipe buffer size on zfs recv to the maximum system size
Browse files Browse the repository at this point in the history
I noticed when reviewing documentation that it is possible for userspace
to use fctnl(fd, F_SETPIPE_SZ, (unsigned long) size) to change the
kernel pipe buffer size on Linux to increase the pipe size up to the
value specified in /proc/sys/fs/pipe-max-size. There are users using
mbuffer to improve zfs recv performance when piping over the network, so
it seems advantageous to integrate such functionality directly into the
zfs recv tool. This avoids the addition of two buffers and two copies
(one for the buffer mbuffer adds and another for the additional pipe),
so it should be more efficient. This could have been made configurable
and/or this could have changed the value back to the original after we
were done with the file descriptor, but I do not see a strong case for
doing either, so I went with a simple implementation.

Closes openzfs#1161

Signed-off-by: Richard Yao <[email protected]>
  • Loading branch information
ryao committed Mar 11, 2015
1 parent 7f3e466 commit 3ea7a69
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions lib/libzfs/libzfs_sendrecv.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <sys/mnttab.h>
#include <sys/avl.h>
#include <sys/debug.h>
#include <sys/stat.h>
#include <stddef.h>
#include <pthread.h>
#include <umem.h>
Expand Down Expand Up @@ -3293,11 +3294,36 @@ int
zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
int infd, avl_tree_t *stream_avl)
{
struct stat sb;
char *top_zfs = NULL;
int err;
int cleanup_fd;
uint64_t action_handle = 0;

if (fstat(infd, &sb) == -1) {
perror("fstat");
return (-2);
}

/*
* 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 pipe_max_size;
unsigned long pipe_current_size;
(void) fscanf(procf, "%lu", &pipe_max_size);
(void) fcntl(infd, F_GETPIPE_SZ, &pipe_current_size);
if (pipe_max_size > pipe_current_size)
(void) fcntl(infd, F_SETPIPE_SZ, pipe_max_size);
fclose(procf);
}
}

cleanup_fd = open(ZFS_DEV, O_RDWR);
VERIFY(cleanup_fd >= 0);

Expand Down

0 comments on commit 3ea7a69

Please sign in to comment.