size_t outargsize = sizeof(outarg);
uint64_t inargflags = 0;
uint64_t outargflags = 0;
+ bool buf_reallocable = se->buf_reallocable;
(void) nodeid;
if (se->debug) {
fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
if (bufsize > max_bufsize) {
bufsize = max_bufsize;
}
+ buf_reallocable = false;
}
if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
se->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
bufsize = FUSE_MIN_READ_BUFFER;
}
+ if (buf_reallocable)
+ bufsize = UINT_MAX;
se->conn.max_write = MIN(se->conn.max_write, bufsize - FUSE_BUFFER_HEADER_SIZE);
se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
fuse_ll_pipe_free(llp);
}
-static unsigned int get_max_pages(void)
-{
- char buf[32];
- long res;
- int fd;
- int err;
-
- fd = open("/proc/sys/fs/fuse/max_pages_limit", O_RDONLY);
- if (fd < 0)
- return FUSE_DEFAULT_MAX_PAGES_LIMIT;
-
- res = read(fd, buf, sizeof(buf) - 1);
-
- close(fd);
-
- if (res < 0)
- return FUSE_DEFAULT_MAX_PAGES_LIMIT;
-
- buf[res] = '\0';
-
- err = libfuse_strtol(buf, &res);
- return err ? FUSE_DEFAULT_MAX_PAGES_LIMIT : res;
-}
-
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
{
return fuse_session_receive_buf_int(se, buf, NULL);
{
int err;
ssize_t res;
-#ifdef HAVE_SPLICE
size_t bufsize = se->bufsize;
+#ifdef HAVE_SPLICE
struct fuse_ll_pipe *llp;
struct fuse_buf tmpbuf;
"fuse: failed to allocate read buffer\n");
return -ENOMEM;
}
+ buf->mem_size = se->bufsize;
+ se->buf_reallocable = true;
}
buf->size = se->bufsize;
buf->flags = 0;
"fuse: failed to allocate read buffer\n");
return -ENOMEM;
}
+ buf->mem_size = se->bufsize;
+ se->buf_reallocable = true;
}
restart:
+ if (se->buf_reallocable)
+ bufsize = buf->mem_size;
if (se->io != NULL) {
/* se->io->read is never NULL if se->io is not NULL as
specified by fuse_session_custom_io()*/
- res = se->io->read(ch ? ch->fd : se->fd, buf->mem, se->bufsize,
+ res = se->io->read(ch ? ch->fd : se->fd, buf->mem, bufsize,
se->userdata);
} else {
- res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
+ res = read(ch ? ch->fd : se->fd, buf->mem, bufsize);
}
err = errno;
if (fuse_session_exited(se))
return 0;
if (res == -1) {
+ if (err == EINVAL && se->buf_reallocable && se->bufsize > buf->mem_size) {
+ void *newbuf = malloc(se->bufsize);
+ if (!newbuf) {
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: failed to (re)allocate read buffer\n");
+ return -ENOMEM;
+ }
+ free(buf->mem);
+ buf->mem = newbuf;
+ buf->mem_size = se->bufsize;
+ se->buf_reallocable = true;
+ goto restart;
+ }
+
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto out1;
}
se->fd = -1;
- se->conn.max_write = UINT_MAX;
+ se->conn.max_write = FUSE_DEFAULT_MAX_PAGES_LIMIT * getpagesize();
+ se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
se->conn.max_readahead = UINT_MAX;
/* Parse options */
if (se->debug)
fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
- se->bufsize = get_max_pages() * getpagesize() +
- FUSE_BUFFER_HEADER_SIZE;
-
list_init_req(&se->list);
list_init_req(&se->interrupts);
list_init_nreq(&se->notify_list);