aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse.c5
-rw-r--r--lib/fuse_i.h2
-rw-r--r--lib/fuse_loop.c4
-rw-r--r--lib/fuse_loop_mt.c4
-rw-r--r--lib/fuse_lowlevel.c126
-rw-r--r--lib/util.h2
6 files changed, 102 insertions, 41 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index b6407eb..3f08d70 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -4550,14 +4550,13 @@ static int fuse_session_loop_remember(struct fuse *f)
else
break;
} else if (res > 0) {
- res = fuse_session_receive_buf(se, &fbuf);
-
+ res = fuse_session_receive_buf_int(se, &fbuf, NULL);
if (res == -EINTR)
continue;
if (res <= 0)
break;
- fuse_session_process_buf(se, &fbuf);
+ fuse_session_process_buf_int(se, &fbuf, NULL);
} else {
timeout = fuse_clean_cache(f);
curr_time(&now);
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index d4421f2..6713ab8 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -188,6 +188,8 @@ void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
+void fuse_buf_free(struct fuse_buf *buf);
+
int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan *ch);
void fuse_session_process_buf_int(struct fuse_session *se,
diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c
index cad3a5c..742d169 100644
--- a/lib/fuse_loop.c
+++ b/lib/fuse_loop.c
@@ -24,7 +24,7 @@ int fuse_session_loop(struct fuse_session *se)
};
while (!fuse_session_exited(se)) {
- res = fuse_session_receive_buf(se, &fbuf);
+ res = fuse_session_receive_buf_int(se, &fbuf, NULL);
if (res == -EINTR)
continue;
@@ -34,7 +34,7 @@ int fuse_session_loop(struct fuse_session *se)
fuse_session_process_buf(se, &fbuf);
}
- free(fbuf.mem);
+ fuse_buf_free(&fbuf);
if(res > 0)
/* No error, just the length of the most recently read
request */
diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c
index 075ac2e..c66a503 100644
--- a/lib/fuse_loop_mt.c
+++ b/lib/fuse_loop_mt.c
@@ -194,7 +194,7 @@ static void *fuse_do_work(void *data)
pthread_mutex_unlock(&mt->lock);
pthread_detach(w->thread_id);
- free(w->fbuf.mem);
+ fuse_buf_free(&w->fbuf);
fuse_chan_put(w->ch);
free(w);
return NULL;
@@ -350,7 +350,7 @@ static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
pthread_mutex_lock(&mt->lock);
list_del_worker(w);
pthread_mutex_unlock(&mt->lock);
- free(w->fbuf.mem);
+ fuse_buf_free(&w->fbuf);
fuse_chan_put(w->ch);
free(w);
}
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index b233e55..4b45f73 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -2945,13 +2945,52 @@ static void fuse_ll_pipe_destructor(void *data)
fuse_ll_pipe_free(llp);
}
-int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
+void fuse_buf_free(struct fuse_buf *buf)
{
- return fuse_session_receive_buf_int(se, buf, NULL);
+ if (buf->mem == NULL)
+ return;
+
+ size_t write_header_sz =
+ sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
+
+ char *ptr = (char *)buf->mem - pagesize + write_header_sz;
+ free(ptr);
+ buf->mem = NULL;
}
-int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
- struct fuse_chan *ch)
+/*
+ * This is used to allocate buffers that hold fuse requests
+ */
+static void *buf_alloc(size_t size, bool internal)
+{
+ /*
+ * For libfuse internal caller add in alignment. That cannot be done
+ * for an external caller, as it is not guaranteed that the external
+ * caller frees the raw pointer.
+ */
+ if (internal) {
+ size_t write_header_sz = sizeof(struct fuse_in_header) +
+ sizeof(struct fuse_write_in);
+ size_t new_size = ROUND_UP(size + write_header_sz, pagesize);
+
+ char *buf = aligned_alloc(pagesize, new_size);
+ if (buf == NULL)
+ return NULL;
+
+ buf += pagesize - write_header_sz;
+
+ return buf;
+ } else {
+ return malloc(size);
+ }
+}
+
+/*
+ *@param internal true if called from libfuse internal code
+ */
+static int _fuse_session_receive_buf(struct fuse_session *se,
+ struct fuse_buf *buf, struct fuse_chan *ch,
+ bool internal)
{
int err;
ssize_t res;
@@ -2960,7 +2999,8 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_ll_pipe *llp;
struct fuse_buf tmpbuf;
- if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
+ if (se->conn.proto_minor < 14 ||
+ !(se->conn.want & FUSE_CAP_SPLICE_READ))
goto fallback;
llp = fuse_ll_get_pipe(se);
@@ -2985,11 +3025,11 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
if (se->io != NULL && se->io->splice_receive != NULL) {
res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
- llp->pipe[1], NULL, bufsize, 0,
- se->userdata);
+ llp->pipe[1], NULL, bufsize, 0,
+ se->userdata);
} else {
res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
- bufsize, 0);
+ bufsize, 0);
}
err = errno;
@@ -3013,7 +3053,7 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
return -EIO;
}
- tmpbuf = (struct fuse_buf) {
+ tmpbuf = (struct fuse_buf){
.size = res,
.flags = FUSE_BUF_IS_FD,
.fd = llp->pipe[0],
@@ -3024,20 +3064,22 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
* fuse_loop_mt() needs to check for FORGET so this more than
* just an optimization.
*/
- if (res < sizeof(struct fuse_in_header) +
- sizeof(struct fuse_write_in) + pagesize) {
+ if (res < sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) +
+ pagesize) {
struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
struct fuse_bufvec dst = { .count = 1 };
if (!buf->mem) {
- buf->mem = malloc(se->bufsize);
+ buf->mem = buf_alloc(se->bufsize, internal);
if (!buf->mem) {
- fuse_log(FUSE_LOG_ERR,
+ fuse_log(
+ FUSE_LOG_ERR,
"fuse: failed to allocate read buffer\n");
return -ENOMEM;
}
buf->mem_size = se->bufsize;
- se->buf_reallocable = true;
+ if (internal)
+ se->buf_reallocable = true;
}
buf->size = se->bufsize;
buf->flags = 0;
@@ -3046,12 +3088,13 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
res = fuse_buf_copy(&dst, &src, 0);
if (res < 0) {
fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
- strerror(-res));
+ strerror(-res));
fuse_ll_clear_pipe(se);
return res;
}
if (res < tmpbuf.size) {
- fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
+ fuse_log(FUSE_LOG_ERR,
+ "fuse: copy from pipe: short read\n");
fuse_ll_clear_pipe(se);
return -EIO;
}
@@ -3069,24 +3112,25 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
fallback:
#endif
if (!buf->mem) {
- buf->mem = malloc(se->bufsize);
+ buf->mem = buf_alloc(se->bufsize, internal);
if (!buf->mem) {
fuse_log(FUSE_LOG_ERR,
- "fuse: failed to allocate read buffer\n");
+ "fuse: failed to allocate read buffer\n");
return -ENOMEM;
}
buf->mem_size = se->bufsize;
- se->buf_reallocable = true;
+ if (internal)
+ se->buf_reallocable = true;
}
restart:
if (se->buf_reallocable)
- bufsize = buf->mem_size;
+ 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, bufsize,
- se->userdata);
+ se->userdata);
} else {
res = read(ch ? ch->fd : se->fd, buf->mem, bufsize);
}
@@ -3095,18 +3139,20 @@ restart:
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;
+ if (err == EINVAL && se->buf_reallocable &&
+ se->bufsize > buf->mem_size) {
+ void *newbuf = buf_alloc(se->bufsize, internal);
+ if (!newbuf) {
+ fuse_log(
+ FUSE_LOG_ERR,
+ "fuse: failed to (re)allocate read buffer\n");
+ return -ENOMEM;
+ }
+ fuse_buf_free(buf);
+ buf->mem = newbuf;
+ buf->mem_size = se->bufsize;
+ se->buf_reallocable = true;
+ goto restart;
}
/* ENOENT means the operation was interrupted, it's safe
@@ -3127,7 +3173,7 @@ restart:
perror("fuse: reading device");
return -err;
}
- if ((size_t) res < sizeof(struct fuse_in_header)) {
+ if ((size_t)res < sizeof(struct fuse_in_header)) {
fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
return -EIO;
}
@@ -3137,6 +3183,18 @@ restart:
return res;
}
+int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
+{
+ return _fuse_session_receive_buf(se, buf, NULL, false);
+}
+
+/* libfuse internal handler */
+int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
+ struct fuse_chan *ch)
+{
+ return _fuse_session_receive_buf(se, buf, ch, true);
+}
+
FUSE_SYMVER("_fuse_session_new_317", "_fuse_session_new@@FUSE_3.17")
struct fuse_session *_fuse_session_new_317(struct fuse_args *args,
const struct fuse_lowlevel_ops *op,
diff --git a/lib/util.h b/lib/util.h
index 0a01711..74ce748 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -1 +1,3 @@
+#define ROUND_UP(val, round_to) (((val) + (round_to - 1)) & ~(round_to - 1))
+
int libfuse_strtol(const char *str, long *res);