14#include "fuse_config.h"
16#include "fuse_kernel.h"
19#include "mount_util.h"
21#include "fuse_uring_i.h"
45#ifndef F_LINUX_SPECIFIC_BASE
46#define F_LINUX_SPECIFIC_BASE 1024
49#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
56#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
57#define OFFSET_MAX 0x7fffffffffffffffLL
59struct fuse_pollhandle {
61 struct fuse_session *se;
64static size_t pagesize;
66static __attribute__((constructor))
void fuse_ll_init_pagesize(
void)
68 pagesize = getpagesize();
73static void trace_request_receive(
int err)
75 USDT(libfuse, request_receive, err);
78static void trace_request_process(
unsigned int opcode,
unsigned int unique)
80 USDT(libfuse, request_process, opcode, unique);
83static void trace_request_reply(uint64_t unique,
unsigned int len,
84 int error,
int reply_err)
86 USDT(libfuse, request_reply, unique, len, error, reply_err);
89static void trace_request_receive(
int err)
94static void trace_request_process(
unsigned int opcode,
unsigned int unique)
100static void trace_request_reply(uint64_t unique,
unsigned int len,
101 int error,
int reply_err)
110static void convert_stat(
const struct stat *stbuf,
struct fuse_attr *attr)
112 attr->ino = stbuf->st_ino;
113 attr->mode = stbuf->st_mode;
114 attr->nlink = stbuf->st_nlink;
115 attr->uid = stbuf->st_uid;
116 attr->gid = stbuf->st_gid;
117 attr->rdev = stbuf->st_rdev;
118 attr->size = stbuf->st_size;
119 attr->blksize = stbuf->st_blksize;
120 attr->blocks = stbuf->st_blocks;
121 attr->atime = stbuf->st_atime;
122 attr->mtime = stbuf->st_mtime;
123 attr->ctime = stbuf->st_ctime;
124 attr->atimensec = ST_ATIM_NSEC(stbuf);
125 attr->mtimensec = ST_MTIM_NSEC(stbuf);
126 attr->ctimensec = ST_CTIM_NSEC(stbuf);
129static void convert_attr(
const struct fuse_setattr_in *attr,
struct stat *stbuf)
131 stbuf->st_mode = attr->mode;
132 stbuf->st_uid = attr->uid;
133 stbuf->st_gid = attr->gid;
134 stbuf->st_size = attr->size;
135 stbuf->st_atime = attr->atime;
136 stbuf->st_mtime = attr->mtime;
137 stbuf->st_ctime = attr->ctime;
138 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
139 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
140 ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
143static size_t iov_length(
const struct iovec *iov,
size_t count)
148 for (seg = 0; seg < count; seg++)
149 ret += iov[seg].iov_len;
153void list_init_req(
struct fuse_req *req)
159static void list_del_req(
struct fuse_req *req)
161 struct fuse_req *prev = req->prev;
162 struct fuse_req *next = req->next;
167static void list_add_req(
struct fuse_req *req,
struct fuse_req *next)
169 struct fuse_req *prev = next->prev;
178 if (req->flags.is_uring) {
179 fuse_log(FUSE_LOG_ERR,
"Refusing to destruct uring req\n");
182 assert(req->ch == NULL);
183 pthread_mutex_destroy(&req->lock);
190 struct fuse_session *se = req->se;
196 if (se->conn.no_interrupt || req->flags.is_uring) {
197 ctr = --req->ref_cnt;
198 fuse_chan_put(req->ch);
201 pthread_mutex_lock(&se->lock);
202 req->u.ni.func = NULL;
203 req->u.ni.data = NULL;
205 ctr = --req->ref_cnt;
206 fuse_chan_put(req->ch);
208 pthread_mutex_unlock(&se->lock);
214static struct fuse_req *fuse_ll_alloc_req(
struct fuse_session *se)
216 struct fuse_req *req;
218 req = (
struct fuse_req *) calloc(1,
sizeof(
struct fuse_req));
220 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate request\n");
225 pthread_mutex_init(&req->lock, NULL);
234static int fuse_write_msg_dev(
struct fuse_session *se,
struct fuse_chan *ch,
235 struct iovec *iov,
int count)
245 res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
248 res = writev(ch ? ch->fd : se->fd, iov, count);
254 perror(
"fuse: writing device");
261static int fuse_send_msg(
struct fuse_session *se,
struct fuse_chan *ch,
264 struct fuse_out_header *out = iov[0].iov_base;
266 bool is_uring = req && req->flags.is_uring ? true :
false;
270 out->len = iov_length(iov, count);
273 if (out->unique == 0) {
274 fuse_log(FUSE_LOG_DEBUG,
"NOTIFY: code=%d length=%u\n",
275 out->error, out->len);
276 }
else if (out->error) {
278 " unique: %llu, error: %i (%s), outsize: %i\n",
279 (
unsigned long long) out->unique, out->error,
280 strerror(-out->error), out->len);
283 " unique: %llu, success, outsize: %i\n",
284 (
unsigned long long) out->unique, out->len);
289 err = fuse_send_msg_uring(req, iov, count);
291 err = fuse_write_msg_dev(se, ch, iov, count);
293 trace_request_reply(out->unique, out->len, out->error, err);
297int fuse_send_reply_iov_nofree(
fuse_req_t req,
int error,
struct iovec *iov,
300 struct fuse_out_header out;
302#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
303 const char *str = strerrordesc_np(error * -1);
304 if ((str == NULL && error != 0) || error > 0) {
306 if (error <= -1000 || error > 0) {
308 fuse_log(FUSE_LOG_ERR,
"fuse: bad error value: %i\n", error);
312 out.unique = req->unique;
315 iov[0].iov_base = &out;
316 iov[0].iov_len =
sizeof(
struct fuse_out_header);
318 return fuse_send_msg(req->se, req->ch, iov, count, req);
321static int send_reply_iov(
fuse_req_t req,
int error,
struct iovec *iov,
326 res = fuse_send_reply_iov_nofree(req, error, iov, count);
331static int send_reply(
fuse_req_t req,
int error,
const void *arg,
334 if (req->flags.is_uring)
335 return send_reply_uring(req, error, arg, argsize);
340 iov[1].iov_base = (
void *) arg;
341 iov[1].iov_len = argsize;
344 return send_reply_iov(req, error, iov, count);
350 struct iovec *padded_iov;
352 padded_iov = malloc((count + 1) *
sizeof(
struct iovec));
353 if (padded_iov == NULL)
356 memcpy(padded_iov + 1, iov, count *
sizeof(
struct iovec));
359 res = send_reply_iov(req, 0, padded_iov, count);
369 const char *name,
const struct stat *stbuf, off_t off)
374 size_t entlen_padded;
375 struct fuse_dirent *dirent;
377 namelen = strlen(name);
378 entlen = FUSE_NAME_OFFSET + namelen;
379 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
381 if ((buf == NULL) || (entlen_padded > bufsize))
382 return entlen_padded;
384 dirent = (
struct fuse_dirent*) buf;
385 dirent->ino = stbuf->st_ino;
387 dirent->namelen = namelen;
388 dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
389 memcpy(dirent->name, name, namelen);
390 memset(dirent->name + namelen, 0, entlen_padded - entlen);
392 return entlen_padded;
395static void convert_statfs(
const struct statvfs *stbuf,
396 struct fuse_kstatfs *kstatfs)
398 kstatfs->bsize = stbuf->f_bsize;
399 kstatfs->frsize = stbuf->f_frsize;
400 kstatfs->blocks = stbuf->f_blocks;
401 kstatfs->bfree = stbuf->f_bfree;
402 kstatfs->bavail = stbuf->f_bavail;
403 kstatfs->files = stbuf->f_files;
404 kstatfs->ffree = stbuf->f_ffree;
405 kstatfs->namelen = stbuf->f_namemax;
408static int send_reply_ok(
fuse_req_t req,
const void *arg,
size_t argsize)
410 return send_reply(req, 0, arg, argsize);
415 return send_reply(req, -err, NULL, 0);
420 if (req->flags.is_uring) {
421 send_reply_uring(req, 0, NULL, 0);
427static unsigned long calc_timeout_sec(
double t)
429 if (t > (
double) ULONG_MAX)
434 return (
unsigned long) t;
437static unsigned int calc_timeout_nsec(
double t)
439 double f = t - (double) calc_timeout_sec(t);
442 else if (f >= 0.999999999)
445 return (
unsigned int) (f * 1.0e9);
448static void fill_entry(
struct fuse_entry_out *arg,
451 arg->nodeid = e->
ino;
456 arg->attr_valid_nsec = calc_timeout_nsec(e->
attr_timeout);
457 convert_stat(&e->
attr, &arg->attr);
469 size_t entlen_padded;
471 namelen = strlen(name);
472 entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
473 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
474 if ((buf == NULL) || (entlen_padded > bufsize))
475 return entlen_padded;
477 struct fuse_direntplus *dp = (
struct fuse_direntplus *) buf;
478 memset(&dp->entry_out, 0,
sizeof(dp->entry_out));
479 fill_entry(&dp->entry_out, e);
481 struct fuse_dirent *dirent = &dp->dirent;
482 dirent->ino = e->
attr.st_ino;
484 dirent->namelen = namelen;
485 dirent->type = (e->
attr.st_mode & S_IFMT) >> 12;
486 memcpy(dirent->name, name, namelen);
487 memset(dirent->name + namelen, 0, entlen_padded - entlen);
489 return entlen_padded;
492static void fill_open(
struct fuse_open_out *arg,
498 arg->open_flags |= FOPEN_PASSTHROUGH;
501 arg->open_flags |= FOPEN_DIRECT_IO;
503 arg->open_flags |= FOPEN_KEEP_CACHE;
505 arg->open_flags |= FOPEN_CACHE_DIR;
507 arg->open_flags |= FOPEN_NONSEEKABLE;
509 arg->open_flags |= FOPEN_NOFLUSH;
511 arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
516 struct fuse_entry_out arg;
518 FUSE_COMPAT_ENTRY_OUT_SIZE :
sizeof(arg);
525 memset(&arg, 0,
sizeof(arg));
527 return send_reply_ok(req, &arg, size);
533 alignas(uint64_t)
char buf[
sizeof(
struct fuse_entry_out) +
sizeof(
struct fuse_open_out)];
535 FUSE_COMPAT_ENTRY_OUT_SIZE :
sizeof(
struct fuse_entry_out);
536 struct fuse_entry_out *earg = (
struct fuse_entry_out *) buf;
537 struct fuse_open_out *oarg = (
struct fuse_open_out *) (buf + entrysize);
539 memset(buf, 0,
sizeof(buf));
542 return send_reply_ok(req, buf,
543 entrysize +
sizeof(
struct fuse_open_out));
549 struct fuse_attr_out arg;
551 FUSE_COMPAT_ATTR_OUT_SIZE :
sizeof(arg);
553 memset(&arg, 0,
sizeof(arg));
554 arg.attr_valid = calc_timeout_sec(attr_timeout);
555 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
556 convert_stat(attr, &arg.attr);
558 return send_reply_ok(req, &arg, size);
563 return send_reply_ok(req, linkname, strlen(linkname));
568 struct fuse_backing_map map = { .fd = fd };
571 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map);
573 fuse_log(FUSE_LOG_ERR,
"fuse: passthrough_open: %s\n", strerror(errno));
580int fuse_passthrough_close(
fuse_req_t req,
int backing_id)
584 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id);
586 fuse_log(FUSE_LOG_ERR,
"fuse: passthrough_close: %s\n", strerror(errno));
593 struct fuse_open_out arg;
595 memset(&arg, 0,
sizeof(arg));
597 return send_reply_ok(req, &arg,
sizeof(arg));
600static int do_fuse_reply_write(
fuse_req_t req,
size_t count)
602 struct fuse_write_out arg;
604 memset(&arg, 0,
sizeof(arg));
607 return send_reply_ok(req, &arg,
sizeof(arg));
610static int do_fuse_reply_copy(
fuse_req_t req,
size_t count)
612 struct fuse_copy_file_range_out arg;
614 memset(&arg, 0,
sizeof(arg));
615 arg.bytes_copied = count;
617 return send_reply_ok(req, &arg,
sizeof(arg));
626 if (req->flags.is_copy_file_range_64)
627 return do_fuse_reply_copy(req, count);
629 return do_fuse_reply_write(req, count);
634 return send_reply_ok(req, buf, size);
637static int fuse_send_data_iov_fallback(
struct fuse_session *se,
638 struct fuse_chan *ch,
639 struct iovec *iov,
int iov_count,
643 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
648 if (
buf->count == 1 &&
buf->idx == 0 &&
buf->off == 0 &&
653 iov[iov_count].iov_base =
buf->buf[0].
mem;
654 iov[iov_count].iov_len = len;
656 return fuse_send_msg(se, ch, iov, iov_count, req);
659 res = posix_memalign(&mbuf, pagesize, len);
663 mem_buf.
buf[0].
mem = mbuf;
671 iov[iov_count].iov_base = mbuf;
672 iov[iov_count].iov_len = len;
674 res = fuse_send_msg(se, ch, iov, iov_count, req);
686static void fuse_ll_pipe_free(
struct fuse_ll_pipe *llp)
694#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
695static int fuse_pipe(
int fds[2])
702 if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
703 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
704 fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
705 fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
713static int fuse_pipe(
int fds[2])
715 return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
719static struct fuse_ll_pipe *fuse_ll_get_pipe(
struct fuse_session *se)
721 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
725 llp = malloc(
sizeof(
struct fuse_ll_pipe));
729 res = fuse_pipe(llp->pipe);
738 llp->size = pagesize * 16;
741 pthread_setspecific(se->pipe_key, llp);
748static void fuse_ll_clear_pipe(
struct fuse_session *se)
750 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
752 pthread_setspecific(se->pipe_key, NULL);
753 fuse_ll_pipe_free(llp);
757#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
758static int read_back(
int fd,
char *buf,
size_t len)
762 res = read(fd, buf, len);
765 "fuse: internal error: failed to read back from pipe: %s\n",
771 "fuse: internal error: short read back from pipe: %i from %zd\n",
778static int grow_pipe_to_max(
int pipefd)
785 maxfd = open(
"/proc/sys/fs/pipe-max-size", O_RDONLY | O_CLOEXEC);
789 res = read(maxfd, buf,
sizeof(buf) - 1);
800 res = libfuse_strtol(buf, &max);
803 res = fcntl(pipefd, F_SETPIPE_SZ, max);
809static int fuse_send_data_iov(
struct fuse_session *se,
struct fuse_chan *ch,
810 struct iovec *iov,
int iov_count,
816 struct fuse_out_header *out = iov[0].iov_base;
817 struct fuse_ll_pipe *llp;
820 size_t total_buf_size;
823 struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
825 if (se->broken_splice_nonblock)
835 total_buf_size -=
buf->off;
837 if (total_buf_size < 2 * pagesize)
840 if (se->conn.proto_minor < 14 ||
844 llp = fuse_ll_get_pipe(se);
849 headerlen = iov_length(iov, iov_count);
851 out->len = headerlen + len;
857 pipesize = pagesize * (iov_count +
buf->count + 1) + out->len;
859 if (llp->size < pipesize) {
861 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
863 res = grow_pipe_to_max(llp->pipe[0]);
871 if (llp->size < pipesize)
876 res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
880 if (res != headerlen) {
882 fuse_log(FUSE_LOG_ERR,
"fuse: short vmsplice to pipe: %u/%zu\n", res,
888 pipe_buf.
buf[0].
fd = llp->pipe[1];
893 if (res == -EAGAIN || res == -EINVAL) {
905 se->broken_splice_nonblock = 1;
907 pthread_setspecific(se->pipe_key, NULL);
908 fuse_ll_pipe_free(llp);
915 if (res != 0 && res < len) {
916 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
918 size_t now_len = res;
928 res = posix_memalign(&mbuf, pagesize, len);
932 mem_buf.
buf[0].
mem = mbuf;
933 mem_buf.
off = now_len;
937 size_t extra_len = res;
943 tmpbuf = malloc(headerlen);
944 if (tmpbuf == NULL) {
949 res = read_back(llp->pipe[0], tmpbuf, headerlen);
955 res = read_back(llp->pipe[0], mbuf, now_len);
960 len = now_len + extra_len;
961 iov[iov_count].iov_base = mbuf;
962 iov[iov_count].iov_len = len;
964 res = fuse_send_msg(se, ch, iov, iov_count, req);
972 out->len = headerlen + len;
976 " unique: %llu, success, outsize: %i (splice)\n",
977 (
unsigned long long) out->unique, out->len);
983 splice_flags |= SPLICE_F_MOVE;
985 if (se->io != NULL && se->io->splice_send != NULL) {
986 res = se->io->splice_send(llp->pipe[0], NULL,
987 ch ? ch->fd : se->fd, NULL, out->len,
988 splice_flags, se->userdata);
990 res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
991 out->len, splice_flags);
995 perror(
"fuse: splice from pipe");
998 if (res != out->len) {
1000 fuse_log(FUSE_LOG_ERR,
"fuse: short splice from pipe: %u/%u\n",
1007 fuse_ll_clear_pipe(se);
1011 return fuse_send_data_iov_fallback(se, ch, iov, iov_count,
buf, len, req);
1014static int fuse_send_data_iov(
struct fuse_session *se,
struct fuse_chan *ch,
1015 struct iovec *iov,
int iov_count,
1022 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, req_data, len, req);
1029 struct iovec iov[2];
1030 struct fuse_out_header out;
1033 if (req->flags.is_uring)
1034 return fuse_reply_data_uring(req, bufv, flags);
1036 iov[0].iov_base = &out;
1037 iov[0].iov_len =
sizeof(
struct fuse_out_header);
1039 out.unique = req->unique;
1042 res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags, req);
1053 struct fuse_statfs_out arg;
1055 FUSE_COMPAT_STATFS_SIZE :
sizeof(arg);
1057 memset(&arg, 0,
sizeof(arg));
1058 convert_statfs(stbuf, &arg.st);
1060 return send_reply_ok(req, &arg, size);
1065 struct fuse_getxattr_out arg;
1067 memset(&arg, 0,
sizeof(arg));
1070 return send_reply_ok(req, &arg,
sizeof(arg));
1075 struct fuse_lk_out arg;
1077 memset(&arg, 0,
sizeof(arg));
1078 arg.lk.type = lock->l_type;
1079 if (lock->l_type != F_UNLCK) {
1080 arg.lk.start = lock->l_start;
1081 if (lock->l_len == 0)
1082 arg.lk.end = OFFSET_MAX;
1084 arg.lk.end = lock->l_start + lock->l_len - 1;
1086 arg.lk.pid = lock->l_pid;
1087 return send_reply_ok(req, &arg,
sizeof(arg));
1092 struct fuse_bmap_out arg;
1094 memset(&arg, 0,
sizeof(arg));
1097 return send_reply_ok(req, &arg,
sizeof(arg));
1100static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(
const struct iovec *iov,
1103 struct fuse_ioctl_iovec *fiov;
1106 fiov = malloc(
sizeof(fiov[0]) * count);
1110 for (i = 0; i < count; i++) {
1111 fiov[i].base = (uintptr_t) iov[i].iov_base;
1112 fiov[i].len = iov[i].iov_len;
1119 const struct iovec *in_iov,
size_t in_count,
1120 const struct iovec *out_iov,
size_t out_count)
1122 struct fuse_ioctl_out arg;
1123 struct fuse_ioctl_iovec *in_fiov = NULL;
1124 struct fuse_ioctl_iovec *out_fiov = NULL;
1125 struct iovec iov[4];
1129 memset(&arg, 0,
sizeof(arg));
1130 arg.flags |= FUSE_IOCTL_RETRY;
1131 arg.in_iovs = in_count;
1132 arg.out_iovs = out_count;
1133 iov[count].iov_base = &arg;
1134 iov[count].iov_len =
sizeof(arg);
1139 iov[count].iov_base = (
void *)in_iov;
1140 iov[count].iov_len =
sizeof(in_iov[0]) * in_count;
1145 iov[count].iov_base = (
void *)out_iov;
1146 iov[count].iov_len =
sizeof(out_iov[0]) * out_count;
1151 if (
sizeof(
void *) == 4 && req->flags.ioctl_64bit) {
1157 in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
1161 iov[count].iov_base = (
void *)in_fiov;
1162 iov[count].iov_len =
sizeof(in_fiov[0]) * in_count;
1166 out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
1170 iov[count].iov_base = (
void *)out_fiov;
1171 iov[count].iov_len =
sizeof(out_fiov[0]) * out_count;
1176 res = send_reply_iov(req, 0, iov, count);
1190 struct fuse_ioctl_out arg;
1191 struct iovec iov[3];
1194 memset(&arg, 0,
sizeof(arg));
1195 arg.result = result;
1196 iov[count].iov_base = &arg;
1197 iov[count].iov_len =
sizeof(arg);
1201 iov[count].iov_base = (
char *) buf;
1202 iov[count].iov_len = size;
1206 return send_reply_iov(req, 0, iov, count);
1212 struct iovec *padded_iov;
1213 struct fuse_ioctl_out arg;
1216 padded_iov = malloc((count + 2) *
sizeof(
struct iovec));
1217 if (padded_iov == NULL)
1220 memset(&arg, 0,
sizeof(arg));
1221 arg.result = result;
1222 padded_iov[1].iov_base = &arg;
1223 padded_iov[1].iov_len =
sizeof(arg);
1225 memcpy(&padded_iov[2], iov, count *
sizeof(
struct iovec));
1227 res = send_reply_iov(req, 0, padded_iov, count + 2);
1235 struct fuse_poll_out arg;
1237 memset(&arg, 0,
sizeof(arg));
1238 arg.revents = revents;
1240 return send_reply_ok(req, &arg,
sizeof(arg));
1245 struct fuse_lseek_out arg;
1247 memset(&arg, 0,
sizeof(arg));
1250 return send_reply_ok(req, &arg,
sizeof(arg));
1255 double attr_timeout)
1257 struct fuse_statx_out arg;
1259 memset(&arg, 0,
sizeof(arg));
1261 arg.attr_valid = calc_timeout_sec(attr_timeout);
1262 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
1263 memcpy(&arg.stat, statx,
sizeof(arg.stat));
1265 return send_reply_ok(req, &arg,
sizeof(arg));
1269 double attr_timeout)
1281 const void *op_in,
const void *in_payload)
1285 char *name = (
char *)in_payload;
1288 req->se->op.
lookup(req, nodeid, name);
1296 _do_lookup(req, nodeid, NULL, inarg);
1300 const void *op_in,
const void *in_payload)
1304 struct fuse_forget_in *arg = (
struct fuse_forget_in *)op_in;
1307 req->se->op.
forget(req, nodeid, arg->nlookup);
1315 _do_forget(req, nodeid, inarg, NULL);
1319 const void *op_in,
const void *in_payload)
1324 const struct fuse_batch_forget_in *arg = op_in;
1325 const struct fuse_forget_one *forgets = in_payload;
1329 (
struct fuse_forget_data *)in_payload);
1330 }
else if (req->se->op.
forget) {
1331 for (i = 0; i < arg->count; i++) {
1332 const struct fuse_forget_one *forget = &forgets[i];
1333 struct fuse_req *dummy_req;
1335 dummy_req = fuse_ll_alloc_req(req->se);
1336 if (dummy_req == NULL)
1339 dummy_req->unique = req->unique;
1340 dummy_req->ctx = req->ctx;
1341 dummy_req->ch = NULL;
1343 req->se->op.
forget(dummy_req, forget->nodeid,
1355 struct fuse_batch_forget_in *arg = (
void *)inarg;
1356 struct fuse_forget_one *param = (
void *)PARAM(arg);
1358 _do_batch_forget(req, nodeid, inarg, param);
1362 const void *op_in,
const void *in_payload)
1364 struct fuse_getattr_in *arg = (
struct fuse_getattr_in *)op_in;
1371 if (arg->getattr_flags & FUSE_GETATTR_FH) {
1372 memset(&fi, 0,
sizeof(fi));
1379 req->se->op.
getattr(req, nodeid, fip);
1387 _do_getattr(req, nodeid, inarg, NULL);
1391 const void *op_in,
const void *in_payload)
1394 const struct fuse_setattr_in *arg = op_in;
1395 uint32_t valid = arg->valid;
1401 memset(&stbuf, 0,
sizeof(stbuf));
1402 convert_attr(arg, &stbuf);
1403 if (arg->valid & FATTR_FH) {
1405 memset(&fi_store, 0,
sizeof(fi_store));
1409 valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
1410 FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
1411 FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
1412 FUSE_SET_ATTR_KILL_SUID | FUSE_SET_ATTR_KILL_SGID |
1413 FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
1414 FUSE_SET_ATTR_CTIME;
1416 req->se->op.
setattr(req, nodeid, &stbuf, valid, fi);
1424 _do_setattr(req, nodeid, inarg, NULL);
1428 const void *op_in,
const void *in_payload)
1431 const struct fuse_access_in *arg = op_in;
1434 req->se->op.
access(req, nodeid, arg->mask);
1442 _do_access(req, nodeid, inarg, NULL);
1446 const void *op_in,
const void *in_payload)
1460 _do_readlink(req, nodeid, inarg, NULL);
1464 const void *op_in,
const void *in_payload)
1466 const struct fuse_mknod_in *arg = (
struct fuse_mknod_in *)op_in;
1467 const char *name = in_payload;
1470 req->ctx.
umask = arg->umask;
1472 if (req->se->op.
mknod)
1473 req->se->op.
mknod(req, nodeid, name, arg->mode, arg->rdev);
1480 struct fuse_mknod_in *arg = (
struct fuse_mknod_in *)inarg;
1481 char *name = PARAM(arg);
1484 name = (
char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
1486 _do_mknod(req, nodeid, inarg, name);
1490 const void *op_in,
const void *in_payload)
1492 const char *name = in_payload;
1493 const struct fuse_mkdir_in *arg = op_in;
1496 req->ctx.
umask = arg->umask;
1498 if (req->se->op.
mkdir)
1499 req->se->op.
mkdir(req, nodeid, name, arg->mode);
1506 const struct fuse_mkdir_in *arg = inarg;
1507 const char *name = PARAM(arg);
1509 _do_mkdir(req, nodeid, inarg, name);
1513 const void *op_in,
const void *in_payload)
1516 const char *name = in_payload;
1519 req->se->op.
unlink(req, nodeid, name);
1527 _do_unlink(req, nodeid, NULL, inarg);
1531 const void *op_in,
const void *in_payload)
1534 const char *name = in_payload;
1536 if (req->se->op.
rmdir)
1537 req->se->op.
rmdir(req, nodeid, name);
1544 _do_rmdir(req, nodeid, NULL, inarg);
1548 const void *op_in,
const void *in_payload)
1551 const char *name = (
char *)in_payload;
1552 const char *linkname = name + strlen(name) + 1;
1555 req->se->op.
symlink(req, linkname, nodeid, name);
1563 _do_symlink(req, nodeid, NULL, inarg);
1567 const void *op_in,
const void *in_payload)
1569 const struct fuse_rename_in *arg = (
struct fuse_rename_in *)op_in;
1570 const char *oldname = in_payload;
1571 const char *newname = oldname + strlen(oldname) + 1;
1574 req->se->op.
rename(req, nodeid, oldname, arg->newdir, newname,
1583 const struct fuse_rename_in *arg = inarg;
1584 const void *payload = PARAM(arg);
1586 _do_rename(req, nodeid, arg, payload);
1590 const void *op_in,
const void *in_payload)
1592 const struct fuse_rename2_in *arg = op_in;
1593 const char *oldname = in_payload;
1594 const char *newname = oldname + strlen(oldname) + 1;
1597 req->se->op.
rename(req, nodeid, oldname, arg->newdir, newname,
1606 const struct fuse_rename2_in *arg = inarg;
1607 const void *payload = PARAM(arg);
1609 _do_rename2(req, nodeid, arg, payload);
1613 const void *in_payload)
1616 const struct fuse_create_in *arg = op_in;
1621 memset(&fi, 0,
sizeof(fi));
1622 fi.
flags = arg->flags;
1625 req->ctx.
umask = arg->umask;
1627 req->se->op.
tmpfile(req, nodeid, arg->mode, &fi);
1634 struct fuse_create_in *arg = (
struct fuse_create_in *) inarg;
1636 _do_tmpfile(req, nodeid, arg, NULL);
1640 const void *in_payload)
1642 struct fuse_link_in *arg = (
struct fuse_link_in *)op_in;
1644 if (req->se->op.
link)
1645 req->se->op.
link(req, arg->oldnodeid, nodeid, in_payload);
1652 const struct fuse_link_in *arg = inarg;
1653 const void *name = PARAM(arg);
1655 _do_link(req, nodeid, inarg, name);
1659 const void *op_in,
const void *in_payload)
1661 const struct fuse_create_in *arg = op_in;
1662 const char *name = in_payload;
1664 if (req->se->op.
create) {
1667 memset(&fi, 0,
sizeof(fi));
1668 fi.
flags = arg->flags;
1671 req->ctx.
umask = arg->umask;
1675 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
1677 req->se->op.
create(req, nodeid, name, arg->mode, &fi);
1686 const struct fuse_create_in *arg = (
struct fuse_create_in *)inarg;
1687 void *payload = PARAM(arg);
1690 payload = (
char *)inarg +
sizeof(
struct fuse_open_in);
1692 _do_create(req, nodeid, arg, payload);
1696 const void *in_payload)
1699 struct fuse_open_in *arg = (
struct fuse_open_in *)op_in;
1702 memset(&fi, 0,
sizeof(fi));
1703 fi.
flags = arg->flags;
1707 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
1709 if (req->se->op.
open)
1710 req->se->op.
open(req, nodeid, &fi);
1719 _do_open(req, nodeid, inarg, NULL);
1723 const void *in_payload)
1726 struct fuse_read_in *arg = (
struct fuse_read_in *)op_in;
1728 if (req->se->op.
read) {
1731 memset(&fi, 0,
sizeof(fi));
1735 fi.
flags = arg->flags;
1737 req->se->op.
read(req, nodeid, arg->size, arg->offset, &fi);
1744 _do_read(req, nodeid, inarg, NULL);
1748 const void *op_in,
const void *in_payload)
1750 struct fuse_write_in *arg = (
struct fuse_write_in *)op_in;
1751 const char *buf = in_payload;
1754 memset(&fi, 0,
sizeof(fi));
1756 fi.
writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
1760 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
1764 fi.
flags = arg->flags;
1767 if (req->se->op.
write)
1768 req->se->op.
write(req, nodeid, buf, arg->size, arg->offset,
1776 struct fuse_write_in *arg = (
struct fuse_write_in *)inarg;
1777 const void *payload;
1780 payload = ((
char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1782 payload = PARAM(arg);
1784 _do_write(req, nodeid, arg, payload);
1790 struct fuse_session *se = req->se;
1791 struct fuse_write_in *arg = (
struct fuse_write_in *)op_in;
1794 memset(&fi, 0,
sizeof(fi));
1796 fi.
writepage = arg->write_flags & FUSE_WRITE_CACHE;
1800 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
1802 if (se->conn.proto_minor >= 9) {
1804 fi.
flags = arg->flags;
1807 se->op.write_buf(req, nodeid, bufv, arg->offset, &fi);
1811 const void *inarg,
const struct fuse_buf *ibuf)
1813 struct fuse_session *se = req->se;
1818 struct fuse_write_in *arg = (
struct fuse_write_in *)inarg;
1820 if (se->conn.proto_minor < 9) {
1821 bufv.
buf[0].
mem = ((
char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1822 bufv.
buf[0].
size -=
sizeof(
struct fuse_in_header) +
1823 FUSE_COMPAT_WRITE_IN_SIZE;
1827 bufv.
buf[0].
mem = PARAM(arg);
1829 bufv.
buf[0].
size -=
sizeof(
struct fuse_in_header) +
1830 sizeof(struct fuse_write_in);
1832 if (bufv.
buf[0].
size < arg->size) {
1834 "fuse: %s: buffer size too small\n", __func__);
1840 _do_write_buf(req, nodeid, inarg, &bufv);
1845 fuse_ll_clear_pipe(se);
1849 const void *op_in,
const void *in_payload)
1852 struct fuse_flush_in *arg = (
struct fuse_flush_in *)op_in;
1855 memset(&fi, 0,
sizeof(fi));
1861 if (req->se->op.
flush)
1862 req->se->op.
flush(req, nodeid, &fi);
1869 _do_flush(req, nodeid, inarg, NULL);
1873 const void *op_in,
const void *in_payload)
1876 const struct fuse_release_in *arg = op_in;
1879 memset(&fi, 0,
sizeof(fi));
1880 fi.
flags = arg->flags;
1883 fi.
flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1886 if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1887 fi.flock_release = 1;
1892 req->se->op.
release(req, nodeid, &fi);
1900 _do_release(req, nodeid, inarg, NULL);
1904 const void *op_in,
const void *in_payload)
1907 const struct fuse_fsync_in *arg = op_in;
1909 int datasync = arg->fsync_flags & 1;
1911 memset(&fi, 0,
sizeof(fi));
1914 if (req->se->op.
fsync)
1915 req->se->op.
fsync(req, nodeid, datasync, &fi);
1922 _do_fsync(req, nodeid, inarg, NULL);
1926 const void *op_in,
const void *in_payload)
1929 const struct fuse_open_in *arg = op_in;
1932 memset(&fi, 0,
sizeof(fi));
1933 fi.
flags = arg->flags;
1937 req->se->op.
opendir(req, nodeid, &fi);
1947 _do_opendir(req, nodeid, inarg, NULL);
1951 const void *op_in,
const void *in_payload)
1954 struct fuse_read_in *arg = (
struct fuse_read_in *)op_in;
1957 memset(&fi, 0,
sizeof(fi));
1961 req->se->op.
readdir(req, nodeid, arg->size, arg->offset, &fi);
1969 _do_readdir(req, nodeid, inarg, NULL);
1973 const void *op_in,
const void *in_payload)
1976 struct fuse_read_in *arg = (
struct fuse_read_in *)op_in;
1979 memset(&fi, 0,
sizeof(fi));
1983 req->se->op.
readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1991 _do_readdirplus(req, nodeid, inarg, NULL);
1995 const void *op_in,
const void *in_payload)
1998 struct fuse_release_in *arg = (
struct fuse_release_in *)op_in;
2001 memset(&fi, 0,
sizeof(fi));
2002 fi.
flags = arg->flags;
2014 _do_releasedir(req, nodeid, inarg, NULL);
2018 const void *op_in,
const void *in_payload)
2021 struct fuse_fsync_in *arg = (
struct fuse_fsync_in *)op_in;
2023 int datasync = arg->fsync_flags & 1;
2025 memset(&fi, 0,
sizeof(fi));
2029 req->se->op.
fsyncdir(req, nodeid, datasync, &fi);
2036 _do_fsyncdir(req, nodeid, inarg, NULL);
2040 const void *op_in,
const void *in_payload)
2047 req->se->op.
statfs(req, nodeid);
2049 struct statvfs buf = {
2059 _do_statfs(req, nodeid, inarg, NULL);
2063 const void *op_in,
const void *in_payload)
2065 struct fuse_setxattr_in *arg = (
struct fuse_setxattr_in *)op_in;
2066 const char *name = in_payload;
2067 const char *value = name + strlen(name) + 1;
2072 req->se->op.
setxattr(req, nodeid, name, value, arg->size,
2080 struct fuse_session *se = req->se;
2082 const struct fuse_setxattr_in *arg = inarg;
2083 char *payload = xattr_ext ? PARAM(arg) :
2084 (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
2086 _do_setxattr(req, nodeid, arg, payload);
2090 const void *op_in,
const void *in_payload)
2092 const struct fuse_getxattr_in *arg = op_in;
2095 req->se->op.
getxattr(req, nodeid, in_payload, arg->size);
2103 const struct fuse_getxattr_in *arg = inarg;
2104 const void *payload = PARAM(arg);
2106 _do_getxattr(req, nodeid, arg, payload);
2110 const void *inarg,
const void *in_payload)
2113 const struct fuse_getxattr_in *arg = inarg;
2116 req->se->op.
listxattr(req, nodeid, arg->size);
2123 _do_listxattr(req, nodeid, inarg, NULL);
2127 const void *inarg,
const void *in_payload)
2130 const char *name = in_payload;
2139 _do_removexattr(req, nodeid, NULL, inarg);
2142static void convert_fuse_file_lock(
const struct fuse_file_lock *fl,
2143 struct flock *flock)
2145 memset(flock, 0,
sizeof(
struct flock));
2146 flock->l_type = fl->type;
2147 flock->l_whence = SEEK_SET;
2148 flock->l_start = fl->start;
2149 if (fl->end == OFFSET_MAX)
2152 flock->l_len = fl->end - fl->start + 1;
2153 flock->l_pid = fl->pid;
2157 const void *op_in,
const void *in_payload)
2160 const struct fuse_lk_in *arg = op_in;
2164 memset(&fi, 0,
sizeof(fi));
2168 convert_fuse_file_lock(&arg->lk, &flock);
2169 if (req->se->op.
getlk)
2170 req->se->op.
getlk(req, nodeid, &fi, &flock);
2176 _do_getlk(req, nodeid, inarg, NULL);
2180 const void *op_in,
int sleep)
2182 const struct fuse_lk_in *arg = op_in;
2186 memset(&fi, 0,
sizeof(fi));
2190 if (arg->lk_flags & FUSE_LK_FLOCK) {
2193 switch (arg->lk.type) {
2207 if (req->se->op.
flock)
2208 req->se->op.
flock(req, nodeid, &fi, op);
2212 convert_fuse_file_lock(&arg->lk, &flock);
2213 if (req->se->op.
setlk)
2214 req->se->op.
setlk(req, nodeid, &fi, &flock, sleep);
2221 const void *op_in,
const void *in_payload)
2224 do_setlk_common(req, nodeid, op_in, 0);
2229 _do_setlk(req, nodeid, inarg, NULL);
2233 const void *op_in,
const void *in_payload)
2236 do_setlk_common(req, nodeid, op_in, 1);
2240 _do_setlkw(req, nodeid, inarg, NULL);
2243static int find_interrupted(
struct fuse_session *se,
struct fuse_req *req)
2245 struct fuse_req *curr;
2247 for (curr = se->list.next; curr != &se->list; curr = curr->next) {
2248 if (curr->unique == req->u.i.unique) {
2253 pthread_mutex_unlock(&se->lock);
2256 pthread_mutex_lock(&curr->lock);
2257 pthread_mutex_lock(&se->lock);
2258 curr->interrupted = 1;
2259 func = curr->u.ni.func;
2260 data = curr->u.ni.data;
2261 pthread_mutex_unlock(&se->lock);
2264 pthread_mutex_unlock(&curr->lock);
2266 pthread_mutex_lock(&se->lock);
2268 if (!curr->ref_cnt) {
2275 for (curr = se->interrupts.next; curr != &se->interrupts;
2276 curr = curr->next) {
2277 if (curr->u.i.unique == req->u.i.unique)
2284 const void *op_in,
const void *in_payload)
2287 const struct fuse_interrupt_in *arg = op_in;
2288 struct fuse_session *se = req->se;
2292 fuse_log(FUSE_LOG_DEBUG,
"INTERRUPT: %llu\n",
2293 (
unsigned long long) arg->unique);
2295 req->u.i.unique = arg->unique;
2297 pthread_mutex_lock(&se->lock);
2298 if (find_interrupted(se, req)) {
2299 fuse_chan_put(req->ch);
2303 list_add_req(req, &se->interrupts);
2304 pthread_mutex_unlock(&se->lock);
2308 _do_interrupt(req, nodeid, inarg, NULL);
2311static struct fuse_req *check_interrupt(
struct fuse_session *se,
2312 struct fuse_req *req)
2314 struct fuse_req *curr;
2316 for (curr = se->interrupts.next; curr != &se->interrupts;
2317 curr = curr->next) {
2318 if (curr->u.i.unique == req->unique) {
2319 req->interrupted = 1;
2321 fuse_chan_put(curr->ch);
2327 curr = se->interrupts.next;
2328 if (curr != &se->interrupts) {
2330 list_init_req(curr);
2337 const void *in_payload)
2340 const struct fuse_bmap_in *arg = op_in;
2342 if (req->se->op.
bmap)
2343 req->se->op.
bmap(req, nodeid, arg->blocksize, arg->block);
2349 _do_bmap(req, nodeid, inarg, NULL);
2353 const void *op_in,
const void *in_payload)
2355 struct fuse_ioctl_in *arg = (
struct fuse_ioctl_in *)op_in;
2356 unsigned int flags = arg->flags;
2357 const void *in_buf = in_payload;
2360 if (
flags & FUSE_IOCTL_DIR &&
2366 memset(&fi, 0,
sizeof(fi));
2369 if (
sizeof(
void *) == 4 && req->se->conn.
proto_minor >= 16 &&
2370 !(
flags & FUSE_IOCTL_32BIT)) {
2371 req->flags.ioctl_64bit = 1;
2374 if (req->se->op.
ioctl)
2375 req->se->op.
ioctl(req, nodeid, arg->cmd,
2376 (
void *)(uintptr_t)arg->arg, &fi,
flags,
2377 in_buf, arg->in_size, arg->out_size);
2383 const struct fuse_ioctl_in *arg = inarg;
2384 void *in_buf = arg->in_size ? PARAM(arg) : NULL;
2386 _do_ioctl(req, nodeid, arg, in_buf);
2395 const void *in_payload)
2398 struct fuse_poll_in *arg = (
struct fuse_poll_in *)op_in;
2401 memset(&fi, 0,
sizeof(fi));
2405 if (req->se->op.
poll) {
2406 struct fuse_pollhandle *ph = NULL;
2408 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
2409 ph = malloc(
sizeof(
struct fuse_pollhandle));
2418 req->se->op.
poll(req, nodeid, &fi, ph);
2426 _do_poll(req, nodeid, inarg, NULL);
2430 const void *op_in,
const void *in_payload)
2433 const struct fuse_fallocate_in *arg = op_in;
2436 memset(&fi, 0,
sizeof(fi));
2440 req->se->op.
fallocate(req, nodeid, arg->mode, arg->offset,
2449 _do_fallocate(req, nodeid, inarg, NULL);
2453 const struct fuse_copy_file_range_in *arg)
2457 memset(&fi_in, 0,
sizeof(fi_in));
2458 fi_in.fh = arg->fh_in;
2460 memset(&fi_out, 0,
sizeof(fi_out));
2461 fi_out.fh = arg->fh_out;
2465 arg->nodeid_out, arg->off_out,
2466 &fi_out, arg->len, arg->flags);
2472 const void *op_in,
const void *in_payload)
2474 const struct fuse_copy_file_range_in *arg = op_in;
2475 struct fuse_copy_file_range_in arg_tmp;
2479 if (arg->len > 0xfffff000) {
2481 arg_tmp.len = 0xfffff000;
2484 copy_file_range_common(req, nodeid_in, arg);
2490 _do_copy_file_range(req, nodeid_in, inarg, NULL);
2494 const void *op_in,
const void *in_payload)
2497 req->flags.is_copy_file_range_64 = 1;
2499 if (
sizeof(
size_t) == 4)
2500 _do_copy_file_range(req, nodeid_in, op_in, NULL);
2502 copy_file_range_common(req, nodeid_in, op_in);
2508 _do_copy_file_range_64(req, nodeid_in, inarg, NULL);
2516 const void *op_in,
const void *in_payload)
2519 const struct fuse_lseek_in *arg = op_in;
2522 memset(&fi, 0,
sizeof(fi));
2525 if (req->se->op.
lseek)
2526 req->se->op.
lseek(req, nodeid, arg->offset, arg->whence, &fi);
2533 _do_lseek(req, nodeid, inarg, NULL);
2538 const void *op_in,
const void *in_payload)
2541 const struct fuse_statx_in *arg = op_in;
2545 if (arg->getattr_flags & FUSE_GETATTR_FH) {
2546 memset(&fi, 0,
sizeof(fi));
2551 if (req->se->op.
statx)
2552 req->se->op.
statx(req, nodeid, arg->sx_flags, arg->sx_mask, fip);
2558 const void *op_in,
const void *in_payload)
2569 _do_statx(req, nodeid, inarg, NULL);
2572static bool want_flags_valid(uint64_t capable, uint64_t want)
2574 uint64_t unknown_flags = want & (~capable);
2575 if (unknown_flags != 0) {
2577 "fuse: unknown connection 'want' flags: 0x%08llx\n",
2578 (
unsigned long long)unknown_flags);
2589 struct fuse_session *se = container_of(conn,
struct fuse_session, conn);
2600 if (conn->
want != se->conn_want &&
2602 if (conn->
want_ext != se->conn_want_ext) {
2604 "%s: Both conn->want_ext and conn->want are set.\n"
2605 "want=%x want_ext=%llx, se->want=%x se->want_ext=%llx\n",
2606 __func__, conn->
want,
2607 (
unsigned long long)conn->
want_ext,
2609 (
unsigned long long)se->conn_want_ext);
2627 struct fuse_session *se = container_of(conn,
struct fuse_session, conn);
2631 se->conn_want_ext |= flag;
2633 se->conn_want |= flag;
2642 struct fuse_session *se = container_of(conn,
struct fuse_session, conn);
2645 se->conn_want_ext &= ~flag;
2646 conn->
want &= ~flag;
2647 se->conn_want &= ~flag;
2658static __attribute__((no_sanitize(
"thread"))) void
2660 const
void *in_payload)
2663 const struct fuse_init_in *arg = op_in;
2664 struct fuse_init_out outarg;
2665 struct fuse_session *se = req->se;
2666 size_t bufsize = se->bufsize;
2667 size_t outargsize =
sizeof(outarg);
2668 uint64_t inargflags = 0;
2669 uint64_t outargflags = 0;
2670 bool buf_reallocable = se->buf_reallocable;
2672 bool enable_io_uring =
false;
2675 fuse_log(FUSE_LOG_DEBUG,
"INIT: %u.%u\n", arg->major, arg->minor);
2676 if (arg->major == 7 && arg->minor >= 6) {
2677 fuse_log(FUSE_LOG_DEBUG,
"flags=0x%08x\n", arg->flags);
2678 fuse_log(FUSE_LOG_DEBUG,
"max_readahead=0x%08x\n",
2679 arg->max_readahead);
2682 se->conn.proto_major = arg->major;
2683 se->conn.proto_minor = arg->minor;
2684 se->conn.capable_ext = 0;
2685 se->conn.want_ext = 0;
2687 memset(&outarg, 0,
sizeof(outarg));
2688 outarg.major = FUSE_KERNEL_VERSION;
2689 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
2691 if (arg->major < 7) {
2692 fuse_log(FUSE_LOG_ERR,
"fuse: unsupported protocol version: %u.%u\n",
2693 arg->major, arg->minor);
2698 if (arg->major > 7) {
2700 send_reply_ok(req, &outarg,
sizeof(outarg));
2704 if (arg->minor >= 6) {
2705 if (arg->max_readahead < se->conn.max_readahead)
2706 se->conn.max_readahead = arg->max_readahead;
2707 inargflags = arg->flags;
2708 if (inargflags & FUSE_INIT_EXT)
2709 inargflags = inargflags | (uint64_t) arg->flags2 << 32;
2710 if (inargflags & FUSE_ASYNC_READ)
2712 if (inargflags & FUSE_POSIX_LOCKS)
2714 if (inargflags & FUSE_ATOMIC_O_TRUNC)
2716 if (inargflags & FUSE_EXPORT_SUPPORT)
2718 if (inargflags & FUSE_DONT_MASK)
2720 if (inargflags & FUSE_FLOCK_LOCKS)
2722 if (inargflags & FUSE_AUTO_INVAL_DATA)
2724 if (inargflags & FUSE_DO_READDIRPLUS)
2726 if (inargflags & FUSE_READDIRPLUS_AUTO)
2728 if (inargflags & FUSE_ASYNC_DIO)
2730 if (inargflags & FUSE_WRITEBACK_CACHE)
2732 if (inargflags & FUSE_NO_OPEN_SUPPORT)
2734 if (inargflags & FUSE_PARALLEL_DIROPS)
2736 if (inargflags & FUSE_POSIX_ACL)
2738 if (inargflags & FUSE_HANDLE_KILLPRIV)
2740 if (inargflags & FUSE_HANDLE_KILLPRIV_V2)
2742 if (inargflags & FUSE_CACHE_SYMLINKS)
2744 if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
2746 if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
2748 if (inargflags & FUSE_SETXATTR_EXT)
2750 if (!(inargflags & FUSE_MAX_PAGES)) {
2751 size_t max_bufsize =
2752 FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
2753 + FUSE_BUFFER_HEADER_SIZE;
2754 if (bufsize > max_bufsize) {
2755 bufsize = max_bufsize;
2757 buf_reallocable =
false;
2759 if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
2761 if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
2763 if (inargflags & FUSE_PASSTHROUGH)
2765 if (inargflags & FUSE_NO_EXPORT_SUPPORT)
2767 if (inargflags & FUSE_OVER_IO_URING)
2771 se->conn.max_readahead = 0;
2774 if (se->conn.proto_minor >= 14) {
2777 if ((se->io == NULL) || (se->io->splice_send != NULL)) {
2782 if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
2787 if (se->conn.proto_minor >= 18)
2797#define LL_SET_DEFAULT(cond, cap) \
2799 fuse_set_feature_flag(&se->conn, cap)
2807 LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
2811 LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
2820 se->conn.time_gran = 1;
2824 se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext);
2826 se->op.init(se->userdata, &se->conn);
2836 if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) {
2838 se->error = -EPROTO;
2843 unsigned max_read_mo = get_max_read(se->mo);
2844 if (se->conn.max_read != max_read_mo) {
2845 fuse_log(FUSE_LOG_ERR,
"fuse: error: init() and fuse_session_new() "
2846 "requested different maximum read size (%u vs %u)\n",
2847 se->conn.max_read, max_read_mo);
2849 se->error = -EPROTO;
2854 if (bufsize < FUSE_MIN_READ_BUFFER) {
2856 "fuse: warning: buffer size too small: %zu\n",
2858 bufsize = FUSE_MIN_READ_BUFFER;
2861 if (buf_reallocable)
2863 se->conn.max_write = MIN(se->conn.max_write, bufsize - FUSE_BUFFER_HEADER_SIZE);
2864 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
2866 if (arg->flags & FUSE_MAX_PAGES) {
2867 outarg.flags |= FUSE_MAX_PAGES;
2868 outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
2870 outargflags = outarg.flags;
2873 outargflags |= FUSE_BIG_WRITES;
2876 outargflags |= FUSE_ASYNC_READ;
2878 outargflags |= FUSE_POSIX_LOCKS;
2880 outargflags |= FUSE_ATOMIC_O_TRUNC;
2882 outargflags |= FUSE_EXPORT_SUPPORT;
2884 outargflags |= FUSE_DONT_MASK;
2886 outargflags |= FUSE_FLOCK_LOCKS;
2888 outargflags |= FUSE_AUTO_INVAL_DATA;
2890 outargflags |= FUSE_DO_READDIRPLUS;
2892 outargflags |= FUSE_READDIRPLUS_AUTO;
2894 outargflags |= FUSE_ASYNC_DIO;
2896 outargflags |= FUSE_WRITEBACK_CACHE;
2898 outargflags |= FUSE_PARALLEL_DIROPS;
2900 outargflags |= FUSE_POSIX_ACL;
2902 outargflags |= FUSE_HANDLE_KILLPRIV;
2904 outargflags |= FUSE_HANDLE_KILLPRIV_V2;
2906 outargflags |= FUSE_CACHE_SYMLINKS;
2908 outargflags |= FUSE_EXPLICIT_INVAL_DATA;
2910 outargflags |= FUSE_SETXATTR_EXT;
2912 outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
2914 outargflags |= FUSE_PASSTHROUGH;
2919 outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
2922 outargflags |= FUSE_NO_EXPORT_SUPPORT;
2924 outargflags |= FUSE_OVER_IO_URING;
2925 enable_io_uring =
true;
2928 if ((inargflags & FUSE_REQUEST_TIMEOUT) && se->conn.request_timeout) {
2929 outargflags |= FUSE_REQUEST_TIMEOUT;
2930 outarg.request_timeout = se->conn.request_timeout;
2933 outarg.max_readahead = se->conn.max_readahead;
2934 outarg.max_write = se->conn.max_write;
2935 if (se->conn.proto_minor >= 13) {
2936 if (se->conn.max_background >= (1 << 16))
2937 se->conn.max_background = (1 << 16) - 1;
2938 if (se->conn.congestion_threshold > se->conn.max_background)
2939 se->conn.congestion_threshold = se->conn.max_background;
2940 if (!se->conn.congestion_threshold) {
2941 se->conn.congestion_threshold =
2942 se->conn.max_background * 3 / 4;
2945 outarg.max_background = se->conn.max_background;
2946 outarg.congestion_threshold = se->conn.congestion_threshold;
2948 if (se->conn.proto_minor >= 23)
2949 outarg.time_gran = se->conn.time_gran;
2952 fuse_log(FUSE_LOG_DEBUG,
" INIT: %u.%u\n", outarg.major, outarg.minor);
2953 fuse_log(FUSE_LOG_DEBUG,
" flags=0x%08x\n", outarg.flags);
2954 fuse_log(FUSE_LOG_DEBUG,
" max_readahead=0x%08x\n",
2955 outarg.max_readahead);
2956 fuse_log(FUSE_LOG_DEBUG,
" max_write=0x%08x\n", outarg.max_write);
2957 fuse_log(FUSE_LOG_DEBUG,
" max_background=%i\n",
2958 outarg.max_background);
2959 fuse_log(FUSE_LOG_DEBUG,
" congestion_threshold=%i\n",
2960 outarg.congestion_threshold);
2961 fuse_log(FUSE_LOG_DEBUG,
" time_gran=%u\n",
2964 fuse_log(FUSE_LOG_DEBUG,
" max_stack_depth=%u\n",
2965 outarg.max_stack_depth);
2968 outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
2969 else if (arg->minor < 23)
2970 outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
2973 if (enable_io_uring) {
2974 int ring_rc = fuse_uring_start(se);
2978 "fuse: failed to start io-uring: %s\n",
2980 outargflags &= ~FUSE_OVER_IO_URING;
2981 enable_io_uring =
false;
2985 if (inargflags & FUSE_INIT_EXT) {
2986 outargflags |= FUSE_INIT_EXT;
2987 outarg.flags2 = outargflags >> 32;
2989 outarg.flags = outargflags;
2998 send_reply_ok(req, &outarg, outargsize);
2999 if (enable_io_uring)
3000 fuse_uring_wake_ring_threads(se);
3003static __attribute__((no_sanitize(
"thread"))) void
3006 _do_init(req, nodeid, inarg, NULL);
3010 const void *op_in,
const void *in_payload)
3012 struct fuse_session *se = req->se;
3019 mountpoint = atomic_exchange(&se->mountpoint, NULL);
3022 se->got_destroy = 1;
3025 se->op.destroy(se->userdata);
3027 send_reply_ok(req, NULL, 0);
3032 _do_destroy(req, nodeid, inarg, NULL);
3035static void list_del_nreq(
struct fuse_notify_req *nreq)
3037 struct fuse_notify_req *prev = nreq->prev;
3038 struct fuse_notify_req *next = nreq->next;
3043static void list_add_nreq(
struct fuse_notify_req *nreq,
3044 struct fuse_notify_req *next)
3046 struct fuse_notify_req *prev = next->prev;
3053static void list_init_nreq(
struct fuse_notify_req *nreq)
3060 const void *inarg,
const struct fuse_buf *buf)
3062 struct fuse_session *se = req->se;
3063 struct fuse_notify_req *nreq;
3064 struct fuse_notify_req *head;
3066 pthread_mutex_lock(&se->lock);
3067 head = &se->notify_list;
3068 for (nreq = head->next; nreq != head; nreq = nreq->next) {
3069 if (nreq->unique == req->unique) {
3070 list_del_nreq(nreq);
3074 pthread_mutex_unlock(&se->lock);
3077 nreq->reply(nreq, req, nodeid, inarg, buf);
3081 const void *inarg,
const struct fuse_buf *ibuf)
3085 buf.
size -=
sizeof(
struct fuse_in_header);
3086 _do_notify_reply(req, nodeid, inarg, &buf);
3089static int send_notify_iov(
struct fuse_session *se,
int notify_code,
3090 struct iovec *iov,
int count)
3092 struct fuse_out_header out;
3093 struct fuse_req *req = NULL;
3099 out.error = notify_code;
3100 iov[0].iov_base = &out;
3101 iov[0].iov_len =
sizeof(
struct fuse_out_header);
3103 return fuse_send_msg(se, NULL, iov, count, req);
3109 struct fuse_notify_poll_wakeup_out outarg;
3110 struct iovec iov[2];
3114 iov[1].iov_base = &outarg;
3115 iov[1].iov_len =
sizeof(outarg);
3117 return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
3124 off_t off, off_t len)
3126 struct fuse_notify_inval_inode_out outarg;
3127 struct iovec iov[2];
3132 if (se->conn.proto_minor < 12)
3139 iov[1].iov_base = &outarg;
3140 iov[1].iov_len =
sizeof(outarg);
3142 return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
3147 struct iovec iov[1];
3152 if (se->conn.proto_minor < 44)
3155 return send_notify_iov(se, FUSE_NOTIFY_INC_EPOCH, iov, 1);
3177static int fuse_lowlevel_notify_entry(
struct fuse_session *se,
fuse_ino_t parent,
3178 const char *name,
size_t namelen,
3181 struct fuse_notify_inval_entry_out outarg;
3182 struct iovec iov[3];
3187 if (se->conn.proto_minor < 12)
3190 outarg.parent = parent;
3191 outarg.namelen = namelen;
3193 if (flags & FUSE_LL_EXPIRE_ONLY)
3194 outarg.flags |= FUSE_EXPIRE_ONLY;
3196 iov[1].iov_base = &outarg;
3197 iov[1].iov_len =
sizeof(outarg);
3198 iov[2].iov_base = (
void *)name;
3199 iov[2].iov_len = namelen + 1;
3201 return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
3205 const char *name,
size_t namelen)
3207 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE);
3211 const char *name,
size_t namelen)
3219 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
3225 const char *name,
size_t namelen)
3227 struct fuse_notify_delete_out outarg;
3228 struct iovec iov[3];
3233 if (se->conn.proto_minor < 18)
3236 outarg.parent = parent;
3237 outarg.child = child;
3238 outarg.namelen = namelen;
3241 iov[1].iov_base = &outarg;
3242 iov[1].iov_len =
sizeof(outarg);
3243 iov[2].iov_base = (
void *)name;
3244 iov[2].iov_len = namelen + 1;
3246 return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
3253 struct fuse_out_header out;
3254 struct fuse_notify_store_out outarg;
3255 struct iovec iov[3];
3258 struct fuse_req *req = NULL;
3263 if (se->conn.proto_minor < 15)
3267 out.error = FUSE_NOTIFY_STORE;
3269 outarg.nodeid = ino;
3270 outarg.offset = offset;
3274 iov[0].iov_base = &out;
3275 iov[0].iov_len =
sizeof(out);
3276 iov[1].iov_base = &outarg;
3277 iov[1].iov_len =
sizeof(outarg);
3279 res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags, req);
3286struct fuse_retrieve_req {
3287 struct fuse_notify_req nreq;
3291static void fuse_ll_retrieve_reply(
struct fuse_notify_req *nreq,
3296 struct fuse_session *se = req->se;
3297 struct fuse_retrieve_req *rreq =
3298 container_of(nreq,
struct fuse_retrieve_req, nreq);
3299 const struct fuse_notify_retrieve_in *arg = inarg;
3306 bufv.
buf[0].
mem = PARAM(arg);
3308 bufv.
buf[0].
size -=
sizeof(
struct fuse_notify_retrieve_in);
3310 if (bufv.
buf[0].
size < arg->size) {
3311 fuse_log(FUSE_LOG_ERR,
"fuse: retrieve reply: buffer size too small\n");
3312 fuse_reply_none(req);
3317 if (se->op.retrieve_reply) {
3318 se->op.retrieve_reply(req, rreq->cookie, ino,
3319 arg->offset, &bufv);
3321 fuse_reply_none(req);
3326 fuse_ll_clear_pipe(se);
3330 size_t size, off_t offset,
void *cookie)
3332 struct fuse_notify_retrieve_out outarg;
3333 struct iovec iov[2];
3334 struct fuse_retrieve_req *rreq;
3340 if (se->conn.proto_minor < 15)
3343 rreq = malloc(
sizeof(*rreq));
3347 pthread_mutex_lock(&se->lock);
3348 rreq->cookie = cookie;
3349 rreq->nreq.unique = se->notify_ctr++;
3350 rreq->nreq.reply = fuse_ll_retrieve_reply;
3351 list_add_nreq(&rreq->nreq, &se->notify_list);
3352 pthread_mutex_unlock(&se->lock);
3354 outarg.notify_unique = rreq->nreq.unique;
3355 outarg.nodeid = ino;
3356 outarg.offset = offset;
3360 iov[1].iov_base = &outarg;
3361 iov[1].iov_len =
sizeof(outarg);
3363 err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
3365 pthread_mutex_lock(&se->lock);
3366 list_del_nreq(&rreq->nreq);
3367 pthread_mutex_unlock(&se->lock);
3376 return req->se->userdata;
3387 pthread_mutex_lock(&req->lock);
3388 pthread_mutex_lock(&req->se->lock);
3389 req->u.ni.func = func;
3390 req->u.ni.data = data;
3391 pthread_mutex_unlock(&req->se->lock);
3392 if (req->interrupted && func)
3394 pthread_mutex_unlock(&req->lock);
3401 pthread_mutex_lock(&req->se->lock);
3402 interrupted = req->interrupted;
3403 pthread_mutex_unlock(&req->se->lock);
3410 return req->flags.is_uring;
3429 [FUSE_LOOKUP] = { do_lookup,
"LOOKUP" },
3430 [FUSE_FORGET] = { do_forget,
"FORGET" },
3431 [FUSE_GETATTR] = { do_getattr,
"GETATTR" },
3432 [FUSE_SETATTR] = { do_setattr,
"SETATTR" },
3433 [FUSE_READLINK] = { do_readlink,
"READLINK" },
3434 [FUSE_SYMLINK] = { do_symlink,
"SYMLINK" },
3435 [FUSE_MKNOD] = { do_mknod,
"MKNOD" },
3436 [FUSE_MKDIR] = { do_mkdir,
"MKDIR" },
3437 [FUSE_UNLINK] = { do_unlink,
"UNLINK" },
3438 [FUSE_RMDIR] = { do_rmdir,
"RMDIR" },
3439 [FUSE_RENAME] = { do_rename,
"RENAME" },
3440 [FUSE_LINK] = { do_link,
"LINK" },
3441 [FUSE_OPEN] = { do_open,
"OPEN" },
3442 [FUSE_READ] = { do_read,
"READ" },
3443 [FUSE_WRITE] = { do_write,
"WRITE" },
3444 [FUSE_STATFS] = { do_statfs,
"STATFS" },
3445 [FUSE_RELEASE] = { do_release,
"RELEASE" },
3446 [FUSE_FSYNC] = { do_fsync,
"FSYNC" },
3447 [FUSE_SETXATTR] = { do_setxattr,
"SETXATTR" },
3448 [FUSE_GETXATTR] = { do_getxattr,
"GETXATTR" },
3449 [FUSE_LISTXATTR] = { do_listxattr,
"LISTXATTR" },
3450 [FUSE_REMOVEXATTR] = { do_removexattr,
"REMOVEXATTR" },
3451 [FUSE_FLUSH] = { do_flush,
"FLUSH" },
3452 [FUSE_INIT] = { do_init,
"INIT" },
3453 [FUSE_OPENDIR] = { do_opendir,
"OPENDIR" },
3454 [FUSE_READDIR] = { do_readdir,
"READDIR" },
3455 [FUSE_RELEASEDIR] = { do_releasedir,
"RELEASEDIR" },
3456 [FUSE_FSYNCDIR] = { do_fsyncdir,
"FSYNCDIR" },
3457 [FUSE_GETLK] = { do_getlk,
"GETLK" },
3458 [FUSE_SETLK] = { do_setlk,
"SETLK" },
3459 [FUSE_SETLKW] = { do_setlkw,
"SETLKW" },
3460 [FUSE_ACCESS] = { do_access,
"ACCESS" },
3461 [FUSE_CREATE] = { do_create,
"CREATE" },
3462 [FUSE_TMPFILE] = { do_tmpfile,
"TMPFILE" },
3463 [FUSE_INTERRUPT] = { do_interrupt,
"INTERRUPT" },
3464 [FUSE_BMAP] = { do_bmap,
"BMAP" },
3465 [FUSE_IOCTL] = { do_ioctl,
"IOCTL" },
3466 [FUSE_POLL] = { do_poll,
"POLL" },
3467 [FUSE_FALLOCATE] = { do_fallocate,
"FALLOCATE" },
3468 [FUSE_DESTROY] = { do_destroy,
"DESTROY" },
3469 [FUSE_NOTIFY_REPLY] = { (
void *) 1,
"NOTIFY_REPLY" },
3470 [FUSE_BATCH_FORGET] = { do_batch_forget,
"BATCH_FORGET" },
3471 [FUSE_READDIRPLUS] = { do_readdirplus,
"READDIRPLUS"},
3472 [FUSE_RENAME2] = { do_rename2,
"RENAME2" },
3473 [FUSE_COPY_FILE_RANGE] = { do_copy_file_range,
"COPY_FILE_RANGE" },
3474 [FUSE_COPY_FILE_RANGE_64] = { do_copy_file_range_64,
"COPY_FILE_RANGE_64" },
3475 [FUSE_LSEEK] = { do_lseek,
"LSEEK" },
3476 [FUSE_STATX] = { do_statx,
"STATX" },
3477 [CUSE_INIT] = { cuse_lowlevel_init,
"CUSE_INIT" },
3482 const void *op_payload);
3484} fuse_ll_ops2[] __attribute__((unused)) = {
3485 [FUSE_LOOKUP] = { _do_lookup,
"LOOKUP" },
3486 [FUSE_FORGET] = { _do_forget,
"FORGET" },
3487 [FUSE_GETATTR] = { _do_getattr,
"GETATTR" },
3488 [FUSE_SETATTR] = { _do_setattr,
"SETATTR" },
3489 [FUSE_READLINK] = { _do_readlink,
"READLINK" },
3490 [FUSE_SYMLINK] = { _do_symlink,
"SYMLINK" },
3491 [FUSE_MKNOD] = { _do_mknod,
"MKNOD" },
3492 [FUSE_MKDIR] = { _do_mkdir,
"MKDIR" },
3493 [FUSE_UNLINK] = { _do_unlink,
"UNLINK" },
3494 [FUSE_RMDIR] = { _do_rmdir,
"RMDIR" },
3495 [FUSE_RENAME] = { _do_rename,
"RENAME" },
3496 [FUSE_LINK] = { _do_link,
"LINK" },
3497 [FUSE_OPEN] = { _do_open,
"OPEN" },
3498 [FUSE_READ] = { _do_read,
"READ" },
3499 [FUSE_WRITE] = { _do_write,
"WRITE" },
3500 [FUSE_STATFS] = { _do_statfs,
"STATFS" },
3501 [FUSE_RELEASE] = { _do_release,
"RELEASE" },
3502 [FUSE_FSYNC] = { _do_fsync,
"FSYNC" },
3503 [FUSE_SETXATTR] = { _do_setxattr,
"SETXATTR" },
3504 [FUSE_GETXATTR] = { _do_getxattr,
"GETXATTR" },
3505 [FUSE_LISTXATTR] = { _do_listxattr,
"LISTXATTR" },
3506 [FUSE_REMOVEXATTR] = { _do_removexattr,
"REMOVEXATTR" },
3507 [FUSE_FLUSH] = { _do_flush,
"FLUSH" },
3508 [FUSE_INIT] = { _do_init,
"INIT" },
3509 [FUSE_OPENDIR] = { _do_opendir,
"OPENDIR" },
3510 [FUSE_READDIR] = { _do_readdir,
"READDIR" },
3511 [FUSE_RELEASEDIR] = { _do_releasedir,
"RELEASEDIR" },
3512 [FUSE_FSYNCDIR] = { _do_fsyncdir,
"FSYNCDIR" },
3513 [FUSE_GETLK] = { _do_getlk,
"GETLK" },
3514 [FUSE_SETLK] = { _do_setlk,
"SETLK" },
3515 [FUSE_SETLKW] = { _do_setlkw,
"SETLKW" },
3516 [FUSE_ACCESS] = { _do_access,
"ACCESS" },
3517 [FUSE_CREATE] = { _do_create,
"CREATE" },
3518 [FUSE_TMPFILE] = { _do_tmpfile,
"TMPFILE" },
3519 [FUSE_INTERRUPT] = { _do_interrupt,
"INTERRUPT" },
3520 [FUSE_BMAP] = { _do_bmap,
"BMAP" },
3521 [FUSE_IOCTL] = { _do_ioctl,
"IOCTL" },
3522 [FUSE_POLL] = { _do_poll,
"POLL" },
3523 [FUSE_FALLOCATE] = { _do_fallocate,
"FALLOCATE" },
3524 [FUSE_DESTROY] = { _do_destroy,
"DESTROY" },
3525 [FUSE_NOTIFY_REPLY] = { (
void *)1,
"NOTIFY_REPLY" },
3526 [FUSE_BATCH_FORGET] = { _do_batch_forget,
"BATCH_FORGET" },
3527 [FUSE_READDIRPLUS] = { _do_readdirplus,
"READDIRPLUS" },
3528 [FUSE_RENAME2] = { _do_rename2,
"RENAME2" },
3529 [FUSE_COPY_FILE_RANGE] = { _do_copy_file_range,
"COPY_FILE_RANGE" },
3530 [FUSE_COPY_FILE_RANGE_64] = { _do_copy_file_range_64,
"COPY_FILE_RANGE_64" },
3531 [FUSE_LSEEK] = { _do_lseek,
"LSEEK" },
3532 [FUSE_STATX] = { _do_statx,
"STATX" },
3533 [CUSE_INIT] = { _cuse_lowlevel_init,
"CUSE_INIT" },
3541#define FUSE_MAXOP (CUSE_INIT + 1)
3549fuse_req_opcode_sanity_ok(
struct fuse_session *se,
enum fuse_opcode in_op)
3553 if (!se->got_init) {
3554 enum fuse_opcode expected;
3556 expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
3557 if (in_op != expected)
3559 }
else if (in_op == FUSE_INIT || in_op == CUSE_INIT)
3566fuse_session_in2req(
struct fuse_req *req,
struct fuse_in_header *in)
3568 req->unique = in->unique;
3569 req->ctx.
uid = in->uid;
3570 req->ctx.
gid = in->gid;
3571 req->ctx.
pid = in->pid;
3578fuse_req_check_allow_root(
struct fuse_session *se,
enum fuse_opcode in_op,
3583 if (se->deny_others && in_uid != se->owner && in_uid != 0 &&
3584 in_op != FUSE_INIT && in_op != FUSE_READ &&
3585 in_op != FUSE_WRITE && in_op != FUSE_FSYNC &&
3586 in_op != FUSE_RELEASE && in_op != FUSE_READDIR &&
3587 in_op != FUSE_FSYNCDIR && in_op != FUSE_RELEASEDIR &&
3588 in_op != FUSE_NOTIFY_REPLY &&
3589 in_op != FUSE_READDIRPLUS)
3595static const char *opname(
enum fuse_opcode opcode)
3597 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
3600 return fuse_ll_ops[opcode].name;
3603static int fuse_ll_copy_from_pipe(
struct fuse_bufvec *dst,
3608 fuse_log(FUSE_LOG_ERR,
"fuse: copy from pipe: %s\n", strerror(-res));
3612 fuse_log(FUSE_LOG_ERR,
"fuse: copy from pipe: short read\n");
3621 fuse_session_process_buf_internal(se, buf, NULL);
3625void fuse_session_process_buf_internal(
struct fuse_session *se,
3626 const struct fuse_buf *buf,
struct fuse_chan *ch)
3628 const size_t write_header_size =
sizeof(
struct fuse_in_header) +
3629 sizeof(struct fuse_write_in);
3631 struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
3632 struct fuse_in_header *in;
3634 struct fuse_req *req;
3643 mbuf = malloc(tmpbuf.
buf[0].
size);
3645 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate header\n");
3648 tmpbuf.
buf[0].
mem = mbuf;
3650 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
3659 trace_request_process(in->opcode, in->unique);
3663 "dev unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
3664 (
unsigned long long) in->unique,
3665 opname((
enum fuse_opcode) in->opcode), in->opcode,
3666 (
unsigned long long) in->nodeid, buf->
size, in->pid);
3669 req = fuse_ll_alloc_req(se);
3671 struct fuse_out_header out = {
3672 .unique = in->unique,
3675 struct iovec iov = {
3677 .iov_len =
sizeof(
struct fuse_out_header),
3680 fuse_send_msg(se, ch, &iov, 1, NULL);
3684 fuse_session_in2req(req, in);
3685 req->ch = ch ? fuse_chan_get(ch) : NULL;
3687 err = fuse_req_opcode_sanity_ok(se, in->opcode);
3691 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
3696 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
3699 if (se->conn.no_interrupt && in->opcode == FUSE_INTERRUPT) {
3701 fuse_log(FUSE_LOG_DEBUG,
"FUSE_INTERRUPT: reply to kernel to disable interrupt\n");
3704 if (!se->conn.no_interrupt && in->opcode != FUSE_INTERRUPT) {
3705 struct fuse_req *intr;
3706 pthread_mutex_lock(&se->lock);
3707 intr = check_interrupt(se, req);
3708 list_add_req(req, &se->list);
3709 pthread_mutex_unlock(&se->lock);
3715 (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
3716 in->opcode != FUSE_NOTIFY_REPLY) {
3720 newmbuf = realloc(mbuf, buf->
size);
3721 if (newmbuf == NULL)
3725 tmpbuf = FUSE_BUFVEC_INIT(buf->
size - write_header_size);
3726 tmpbuf.
buf[0].
mem = (
char *)mbuf + write_header_size;
3728 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
3736 inarg = (
void *) &in[1];
3737 if (in->opcode == FUSE_WRITE && se->op.write_buf)
3738 do_write_buf(req, in->nodeid, inarg, buf);
3739 else if (in->opcode == FUSE_NOTIFY_REPLY)
3740 do_notify_reply(req, in->nodeid, inarg, buf);
3742 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
3752 fuse_ll_clear_pipe(se);
3756void fuse_session_process_uring_cqe(
struct fuse_session *se,
3757 struct fuse_req *req,
3758 struct fuse_in_header *in,
void *op_in,
3759 void *op_payload,
size_t payload_len)
3763 fuse_session_in2req(req, in);
3765 err = fuse_req_opcode_sanity_ok(se, in->opcode);
3769 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
3774 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops2[in->opcode].func)
3780 "cqe unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
3781 (
unsigned long long)in->unique,
3782 opname((
enum fuse_opcode)in->opcode), in->opcode,
3783 (
unsigned long long)in->nodeid, payload_len, in->pid);
3786 if (in->opcode == FUSE_WRITE && se->op.write_buf) {
3788 .buf[0] = { .size = payload_len,
3790 .mem = op_payload },
3793 _do_write_buf(req, in->nodeid, op_in, &bufv);
3794 }
else if (in->opcode == FUSE_NOTIFY_REPLY) {
3795 struct fuse_buf buf = { .size = payload_len,
3796 .mem = op_payload };
3797 _do_notify_reply(req, in->nodeid, op_payload, &buf);
3799 fuse_ll_ops2[in->opcode].func(req, in->nodeid, op_in,
3809#define LL_OPTION(n,o,v) \
3810 { n, offsetof(struct fuse_session, o), v }
3812static const struct fuse_opt fuse_ll_opts[] = {
3813 LL_OPTION(
"debug", debug, 1),
3814 LL_OPTION(
"-d", debug, 1),
3815 LL_OPTION(
"--debug", debug, 1),
3816 LL_OPTION(
"allow_root", deny_others, 1),
3817 LL_OPTION(
"io_uring", uring.enable, 1),
3818 LL_OPTION(
"io_uring_q_depth=%u", uring.q_depth, -1),
3824 printf(
"using FUSE kernel interface version %i.%i\n",
3825 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
3826 fuse_mount_version();
3834" -o allow_other allow access by all users\n"
3835" -o allow_root allow access by root\n"
3836" -o auto_unmount auto unmount on process termination\n"
3837" -o io_uring enable io-uring\n"
3838" -o io_uring_q_depth=<n> io-uring queue depth\n"
3844 struct fuse_ll_pipe *llp;
3846 if (se->got_init && !se->got_destroy) {
3848 se->op.destroy(se->userdata);
3850 llp = pthread_getspecific(se->pipe_key);
3852 fuse_ll_pipe_free(llp);
3853 pthread_key_delete(se->pipe_key);
3854 sem_destroy(&se->mt_finish);
3855 pthread_mutex_destroy(&se->mt_lock);
3856 pthread_mutex_destroy(&se->lock);
3857 free(se->cuse_data);
3862 destroy_mount_opts(se->mo);
3863 free(atomic_exchange(&se->mountpoint, NULL));
3868static void fuse_ll_pipe_destructor(
void *data)
3870 struct fuse_ll_pipe *llp = data;
3871 fuse_ll_pipe_free(llp);
3874void fuse_buf_free(
struct fuse_buf *buf)
3876 if (buf->
mem == NULL)
3879 size_t write_header_sz =
3880 sizeof(
struct fuse_in_header) + sizeof(struct fuse_write_in);
3882 char *ptr = (
char *)buf->
mem - pagesize + write_header_sz;
3890static void *buf_alloc(
size_t size,
bool internal)
3898 size_t write_header_sz =
sizeof(
struct fuse_in_header) +
3899 sizeof(struct fuse_write_in);
3900 size_t new_size = ROUND_UP(size + write_header_sz, pagesize);
3902 char *buf = aligned_alloc(pagesize, new_size);
3906 buf += pagesize - write_header_sz;
3910 return malloc(size);
3917static int _fuse_session_receive_buf(
struct fuse_session *se,
3918 struct fuse_buf *buf,
struct fuse_chan *ch,
3925 struct fuse_ll_pipe *llp;
3929 bufsize = se->bufsize;
3931 if (se->conn.proto_minor < 14 ||
3935 llp = fuse_ll_get_pipe(se);
3939 if (llp->size < bufsize) {
3940 if (llp->can_grow) {
3941 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
3944 res = grow_pipe_to_max(llp->pipe[0]);
3947 fuse_ll_clear_pipe(se);
3952 if (llp->size < bufsize) {
3953 fuse_ll_clear_pipe(se);
3958 if (se->io != NULL && se->io->splice_receive != NULL) {
3959 res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
3960 llp->pipe[1], NULL, bufsize, 0,
3963 res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
3967 trace_request_receive(err);
3973 if (err == ENODEV) {
3981 if (err == EINVAL && bufsize < se->bufsize) {
3982 fuse_ll_clear_pipe(se);
3986 if (err != EINTR && err != EAGAIN)
3987 perror(
"fuse: splice from device");
3991 if (res <
sizeof(
struct fuse_in_header)) {
3992 fuse_log(FUSE_LOG_ERR,
"short splice from fuse device\n");
4007 if (res <
sizeof(
struct fuse_in_header) +
sizeof(
struct fuse_write_in) +
4013 buf->
mem = buf_alloc(bufsize, internal);
4017 "fuse: failed to allocate read buffer\n");
4028 fuse_log(FUSE_LOG_ERR,
"fuse: copy from pipe: %s\n",
4030 fuse_ll_clear_pipe(se);
4033 if (res < tmpbuf.size) {
4035 "fuse: copy from pipe: short read\n");
4036 fuse_ll_clear_pipe(se);
4039 assert(res == tmpbuf.size);
4043 buf->
fd = tmpbuf.fd;
4054 bufsize = se->bufsize;
4055 buf->mem = buf_alloc(bufsize, internal);
4057 fuse_log(FUSE_LOG_ERR,
4058 "fuse: failed to allocate read buffer\n");
4067 if (se->io != NULL) {
4070 res = se->io->read(ch ? ch->fd : se->fd, buf->mem, bufsize,
4073 res = read(ch ? ch->fd : se->fd, buf->mem, bufsize);
4076 trace_request_receive(err);
4081 if (err == EINVAL && internal && se->bufsize > bufsize) {
4083 bufsize = se->bufsize;
4084 void *newbuf = buf_alloc(bufsize, internal);
4088 "fuse: failed to (re)allocate read buffer\n");
4102 if (err == ENODEV) {
4111 if (err != EINTR && err != EAGAIN)
4112 perror(
"fuse: reading device");
4115 if ((
size_t)res <
sizeof(
struct fuse_in_header)) {
4116 fuse_log(FUSE_LOG_ERR,
"short read on fuse device\n");
4127 return _fuse_session_receive_buf(se,
buf, NULL,
false);
4131int fuse_session_receive_buf_internal(
struct fuse_session *se,
4133 struct fuse_chan *ch)
4139 if (unlikely(!se->got_init) && !se->buf_reallocable)
4140 se->buf_reallocable =
true;
4142 return _fuse_session_receive_buf(se,
buf, ch,
true);
4145struct fuse_session *
4146fuse_session_new_versioned(
struct fuse_args *args,
4151 struct fuse_session *se;
4152 struct mount_opts *mo;
4154 if (op == NULL || op_size == 0) {
4156 "fuse: warning: empty op list passed to fuse_session_new()\n");
4160 if (version == NULL) {
4161 fuse_log(FUSE_LOG_ERR,
"fuse: warning: version not passed to fuse_session_new()\n");
4166 fuse_log(FUSE_LOG_ERR,
"fuse: warning: library too old, some operations may not work\n");
4170 if (args == NULL || args->
argc == 0) {
4171 fuse_log(FUSE_LOG_ERR,
"fuse: empty argv passed to fuse_session_new().\n");
4175 se = (
struct fuse_session *) calloc(1,
sizeof(
struct fuse_session));
4177 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate fuse object\n");
4181 se->conn.max_write = FUSE_DEFAULT_MAX_PAGES_LIMIT * getpagesize();
4182 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
4183 se->conn.max_readahead = UINT_MAX;
4189 se->uring.enable = getenv(
"FUSE_URING_ENABLE") ?
4190 atoi(getenv(
"FUSE_URING_ENABLE")) :
4191 SESSION_DEF_URING_ENABLE;
4192 se->uring.q_depth = getenv(
"FUSE_URING_QUEUE_DEPTH") ?
4193 atoi(getenv(
"FUSE_URING_QUEUE_DEPTH")) :
4194 SESSION_DEF_URING_Q_DEPTH;
4199 if(se->deny_others) {
4209 mo = parse_mount_opts(args);
4213 if(args->
argc == 1 &&
4214 args->
argv[0][0] ==
'-') {
4215 fuse_log(FUSE_LOG_ERR,
"fuse: warning: argv[0] looks like an option, but "
4216 "will be ignored\n");
4217 }
else if (args->
argc != 1) {
4219 fuse_log(FUSE_LOG_ERR,
"fuse: unknown option(s): `");
4220 for(i = 1; i < args->
argc-1; i++)
4227 fuse_log(FUSE_LOG_DEBUG,
"FUSE library version: %s\n", PACKAGE_VERSION);
4229 list_init_req(&se->list);
4230 list_init_req(&se->interrupts);
4231 list_init_nreq(&se->notify_list);
4233 pthread_mutex_init(&se->lock, NULL);
4234 sem_init(&se->mt_finish, 0, 0);
4235 pthread_mutex_init(&se->mt_lock, NULL);
4237 err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
4239 fuse_log(FUSE_LOG_ERR,
"fuse: failed to create thread specific key: %s\n",
4244 memcpy(&se->op, op, op_size);
4245 se->owner = getuid();
4246 se->userdata = userdata;
4255 se->version = *version;
4260 sem_destroy(&se->mt_finish);
4261 pthread_mutex_destroy(&se->mt_lock);
4262 pthread_mutex_destroy(&se->lock);
4267 destroy_mount_opts(mo);
4274struct fuse_session *fuse_session_new_30(
struct fuse_args *args,
4276 size_t op_size,
void *userdata);
4277struct fuse_session *fuse_session_new_30(
struct fuse_args *args,
4295 op_size =
sizeof(null_ops);
4298 return fuse_session_new_versioned(args, op, op_size, &version,
4302FUSE_SYMVER(
"fuse_session_custom_io_317",
"fuse_session_custom_io@@FUSE_3.17")
4303int fuse_session_custom_io_317(struct fuse_session *se,
4304 const struct fuse_custom_io *io,
size_t op_size,
int fd)
4306#ifndef HAVE_CUSTOM_IO
4311 fuse_log(FUSE_LOG_ERR,
"fuse: custom io is not enabled in this build\n");
4314 if (
sizeof(
struct fuse_custom_io) < op_size) {
4315 fuse_log(FUSE_LOG_ERR,
"fuse: warning: library too old, some operations may not work\n");
4316 op_size =
sizeof(
struct fuse_custom_io);
4320 fuse_log(FUSE_LOG_ERR,
"Invalid file descriptor value %d passed to "
4321 "fuse_session_custom_io()\n", fd);
4325 fuse_log(FUSE_LOG_ERR,
"No custom IO passed to "
4326 "fuse_session_custom_io()\n");
4328 }
else if (io->read == NULL || io->writev == NULL) {
4333 fuse_log(FUSE_LOG_ERR,
"io passed to fuse_session_custom_io() must "
4334 "implement both io->read() and io->writev\n");
4338 se->io = calloc(1,
sizeof(
struct fuse_custom_io));
4339 if (se->io == NULL) {
4340 fuse_log(FUSE_LOG_ERR,
"Failed to allocate memory for custom io. "
4341 "Error: %s\n", strerror(errno));
4346 memcpy(se->io, io, op_size);
4351int fuse_session_custom_io_30(
struct fuse_session *se,
4352 const struct fuse_custom_io *io,
int fd);
4353FUSE_SYMVER(
"fuse_session_custom_io_30",
"fuse_session_custom_io@FUSE_3.0")
4354int fuse_session_custom_io_30(struct fuse_session *se,
4355 const struct fuse_custom_io *io,
int fd)
4357 return fuse_session_custom_io_317(se, io,
4358 offsetof(
struct fuse_custom_io, clone_fd), fd);
4366 if (_mountpoint == NULL) {
4367 fuse_log(FUSE_LOG_ERR,
"Invalid null-ptr mountpoint!\n");
4371 mountpoint = strdup(_mountpoint);
4372 if (mountpoint == NULL) {
4373 fuse_log(FUSE_LOG_ERR,
"Failed to allocate memory for mountpoint. Error: %s\n",
4383 fd = open(
"/dev/null", O_RDWR);
4386 }
while (fd >= 0 && fd <= 2);
4394 fd = fuse_mnt_parse_fuse_fd(mountpoint);
4396 if (fcntl(fd, F_GETFD) == -1) {
4398 "fuse: Invalid file descriptor /dev/fd/%u\n",
4406 fd = fuse_kern_mount(mountpoint, se->mo);
4412 se->mountpoint = mountpoint;
4428 if (se->mountpoint != NULL) {
4429 char *mountpoint = atomic_exchange(&se->mountpoint, NULL);
4431 fuse_kern_unmount(mountpoint, se->fd);
4441 size_t bufsize = 1024;
4445 unsigned long pid = req->ctx.
pid;
4448 sprintf(path,
"/proc/%lu/task/%lu/status", pid, pid);
4451 buf = malloc(bufsize);
4456 fd = open(path, O_RDONLY);
4460 ret = read(fd, buf, bufsize);
4467 if ((
size_t)ret == bufsize) {
4475 s = strstr(buf,
"\nGroups:");
4483 unsigned long val = strtoul(s, &end, 0);
4503 (void) req; (void) size; (void) list;
4510__attribute__((no_sanitize_thread))
4513 atomic_store_explicit(&se->mt_exited, 1, memory_order_relaxed);
4514 sem_post(&se->mt_finish);
4517__attribute__((no_sanitize_thread))
4520 se->mt_exited =
false;
4524__attribute__((no_sanitize_thread))
4528 atomic_load_explicit(&se->mt_exited, memory_order_relaxed);
4530 return exited ? 1 : 0;
#define FUSE_CAP_IOCTL_DIR
#define FUSE_CAP_DONT_MASK
void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
#define FUSE_CAP_HANDLE_KILLPRIV
#define FUSE_CAP_AUTO_INVAL_DATA
#define FUSE_CAP_HANDLE_KILLPRIV_V2
#define FUSE_CAP_SPLICE_READ
#define FUSE_CAP_PARALLEL_DIROPS
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
#define FUSE_CAP_WRITEBACK_CACHE
#define FUSE_CAP_EXPIRE_ONLY
#define FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ASYNC_READ
#define FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_CACHE_SYMLINKS
#define FUSE_CAP_POSIX_ACL
#define FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_EXPLICIT_INVAL_DATA
#define FUSE_CAP_READDIRPLUS_AUTO
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
#define FUSE_CAP_NO_OPENDIR_SUPPORT
#define FUSE_CAP_ASYNC_DIO
#define FUSE_CAP_OVER_IO_URING
bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
#define FUSE_CAP_PASSTHROUGH
#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP
#define FUSE_CAP_NO_OPEN_SUPPORT
#define FUSE_CAP_READDIRPLUS
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
@ FUSE_BUF_SPLICE_NONBLOCK
#define FUSE_CAP_SETXATTR_EXT
#define FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_NO_EXPORT_SUPPORT
#define FUSE_CAP_FLOCK_LOCKS
void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
void fuse_session_destroy(struct fuse_session *se)
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
void fuse_session_exit(struct fuse_session *se)
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
int fuse_reply_poll(fuse_req_t req, unsigned revents)
int fuse_reply_err(fuse_req_t req, int err)
bool fuse_req_is_uring(fuse_req_t req)
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
void * fuse_req_userdata(fuse_req_t req)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
struct fuse_req * fuse_req_t
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
int fuse_session_exited(struct fuse_session *se)
int fuse_session_fd(struct fuse_session *se)
int fuse_req_interrupted(fuse_req_t req)
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
int fuse_reply_readlink(fuse_req_t req, const char *link)
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
void fuse_session_unmount(struct fuse_session *se)
void fuse_reply_none(fuse_req_t req)
int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr)
int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
void fuse_lowlevel_help(void)
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
int fuse_reply_write(fuse_req_t req, size_t count)
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
void fuse_session_reset(struct fuse_session *se)
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
int fuse_reply_lseek(fuse_req_t req, off_t off)
void fuse_lowlevel_version(void)
int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
int fuse_passthrough_open(fuse_req_t req, int fd)
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_reply_xattr(fuse_req_t req, size_t count)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
void fuse_opt_free_args(struct fuse_args *args)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
enum fuse_buf_flags flags
uint32_t parallel_direct_writes
void(* fsync)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
void(* unlink)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
void(* rename)(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags)
void(* releasedir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
void(* symlink)(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
void(* statfs)(fuse_req_t req, fuse_ino_t ino)
void(* tmpfile)(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)
void(* release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
void(* create)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)
void(* link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
void(* write)(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi)
void(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)
void(* getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
void(* setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
void(* open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name)
void(* forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
void(* poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)
void(* ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)
void(* rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
void(* fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
void(* statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)
void(* access)(fuse_req_t req, fuse_ino_t ino, int mask)
void(* mknod)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
void(* lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)
void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
void(* readlink)(fuse_req_t req, fuse_ino_t ino)
void(* read)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* flush)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size)
void(* opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* forget_multi)(fuse_req_t req, size_t count, struct fuse_forget_data *forgets)