mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-virtiofs-20200123b' into staging
virtiofsd first pull v2 Import our virtiofsd. This pulls in the daemon to drive a file system connected to the existing qemu virtiofsd device. It's derived from upstream libfuse with lots of changes (and a lot trimmed out). The daemon lives in the newly created qemu/tools/virtiofsd Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> v2 drop the docs while we discuss where they should live and we need to redo the manpage in anything but texi # gpg: Signature made Thu 23 Jan 2020 16:45:18 GMT # gpg: using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7 # gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full] # Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7 * remotes/dgilbert-gitlab/tags/pull-virtiofs-20200123b: (108 commits) virtiofsd: add some options to the help message virtiofsd: stop all queue threads on exit in virtio_loop() virtiofsd/passthrough_ll: Pass errno to fuse_reply_err() virtiofsd: Convert lo_destroy to take the lo->mutex lock itself virtiofsd: add --thread-pool-size=NUM option virtiofsd: fix lo_destroy() resource leaks virtiofsd: prevent FUSE_INIT/FUSE_DESTROY races virtiofsd: process requests in a thread pool virtiofsd: use fuse_buf_writev to replace fuse_buf_write for better performance virtiofsd: add definition of fuse_buf_writev() virtiofsd: passthrough_ll: Use cache_readdir for directory open virtiofsd: Fix data corruption with O_APPEND write in writeback mode virtiofsd: Reset O_DIRECT flag during file open virtiofsd: convert more fprintf and perror to use fuse log infra virtiofsd: do not always set FUSE_FLOCK_LOCKS virtiofsd: introduce inode refcount to prevent use-after-free virtiofsd: passthrough_ll: fix refcounting on remove/rename libvhost-user: Fix some memtable remap cases virtiofsd: rename inode->refcount to inode->nlookup virtiofsd: prevent races with lo_dirp_put() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
/elf2dmp
|
||||
/trace-events-all
|
||||
/trace/generated-events.h
|
||||
|
||||
@@ -1595,6 +1595,14 @@ T: git https://github.com/cohuck/qemu.git s390-next
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
virtiofs
|
||||
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Supported
|
||||
F: tools/virtiofsd/*
|
||||
F: hw/virtio/vhost-user-fs*
|
||||
F: include/hw/virtio/vhost-user-fs.h
|
||||
|
||||
virtio-input
|
||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -327,6 +327,11 @@ HELPERS-y += vhost-user-gpu$(EXESUF)
|
||||
vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
HELPERS-y += virtiofsd$(EXESUF)
|
||||
vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
endif
|
||||
|
||||
# Sphinx does not allow building manuals into the same directory as
|
||||
# the source files, so if we're doing an in-tree QEMU build we must
|
||||
# build the manuals into a subdirectory (and then install them from
|
||||
@@ -431,6 +436,7 @@ dummy := $(call unnest-vars,, \
|
||||
elf2dmp-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
virtiofsd-obj-y \
|
||||
rdmacm-mux-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
@@ -670,6 +676,12 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
|
||||
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
# relies on Linux-specific syscalls
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
endif
|
||||
|
||||
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
|
||||
$(call LINK, $^)
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||
vhost-user-input-obj-y = contrib/vhost-user-input/
|
||||
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
|
||||
virtiofsd-obj-y = tools/virtiofsd/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
|
||||
@@ -5197,6 +5197,19 @@ if compile_prog "" "" ; then
|
||||
strchrnul=yes
|
||||
fi
|
||||
|
||||
#########################################
|
||||
# check if we have st_atim
|
||||
|
||||
st_atim=no
|
||||
cat > $TMPC << EOF
|
||||
#include <sys/stat.h>
|
||||
#include <stddef.h>
|
||||
int main(void) { return offsetof(struct stat, st_atim); }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
st_atim=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# check if trace backend exists
|
||||
|
||||
@@ -6895,6 +6908,9 @@ fi
|
||||
if test "$strchrnul" = "yes" ; then
|
||||
echo "HAVE_STRCHRNUL=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$st_atim" = "yes" ; then
|
||||
echo "HAVE_STRUCT_STAT_ST_ATIM=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$byteswap_h" = "yes" ; then
|
||||
echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
@@ -392,26 +392,37 @@ vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
|
||||
return vu_message_write(dev, conn_fd, vmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes a reply on the slave channel.
|
||||
* Entered with slave_mutex held and releases it before exit.
|
||||
* Returns true on success.
|
||||
*/
|
||||
static bool
|
||||
vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg)
|
||||
{
|
||||
VhostUserMsg msg_reply;
|
||||
bool result = false;
|
||||
|
||||
if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
|
||||
return true;
|
||||
result = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) {
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (msg_reply.request != vmsg->request) {
|
||||
DPRINT("Received unexpected msg type. Expected %d received %d",
|
||||
vmsg->request, msg_reply.request);
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return msg_reply.payload.u64 == 0;
|
||||
result = msg_reply.payload.u64 == 0;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dev->slave_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Kick the log_call_fd if required. */
|
||||
@@ -553,6 +564,21 @@ vu_reset_device_exec(VuDev *dev, VhostUserMsg *vmsg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
map_ring(VuDev *dev, VuVirtq *vq)
|
||||
{
|
||||
vq->vring.desc = qva_to_va(dev, vq->vra.desc_user_addr);
|
||||
vq->vring.used = qva_to_va(dev, vq->vra.used_user_addr);
|
||||
vq->vring.avail = qva_to_va(dev, vq->vra.avail_user_addr);
|
||||
|
||||
DPRINT("Setting virtq addresses:\n");
|
||||
DPRINT(" vring_desc at %p\n", vq->vring.desc);
|
||||
DPRINT(" vring_used at %p\n", vq->vring.used);
|
||||
DPRINT(" vring_avail at %p\n", vq->vring.avail);
|
||||
|
||||
return !(vq->vring.desc && vq->vring.used && vq->vring.avail);
|
||||
}
|
||||
|
||||
static bool
|
||||
vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
|
||||
{
|
||||
@@ -756,6 +782,14 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
|
||||
close(vmsg->fds[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->max_queues; i++) {
|
||||
if (dev->vq[i].vring.desc) {
|
||||
if (map_ring(dev, &dev->vq[i])) {
|
||||
vu_panic(dev, "remaping queue %d during setmemtable", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -842,18 +876,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg)
|
||||
DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", vra->avail_user_addr);
|
||||
DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", vra->log_guest_addr);
|
||||
|
||||
vq->vra = *vra;
|
||||
vq->vring.flags = vra->flags;
|
||||
vq->vring.desc = qva_to_va(dev, vra->desc_user_addr);
|
||||
vq->vring.used = qva_to_va(dev, vra->used_user_addr);
|
||||
vq->vring.avail = qva_to_va(dev, vra->avail_user_addr);
|
||||
vq->vring.log_guest_addr = vra->log_guest_addr;
|
||||
|
||||
DPRINT("Setting virtq addresses:\n");
|
||||
DPRINT(" vring_desc at %p\n", vq->vring.desc);
|
||||
DPRINT(" vring_used at %p\n", vq->vring.used);
|
||||
DPRINT(" vring_avail at %p\n", vq->vring.avail);
|
||||
|
||||
if (!(vq->vring.desc && vq->vring.used && vq->vring.avail)) {
|
||||
if (map_ring(dev, vq)) {
|
||||
vu_panic(dev, "Invalid vring_addr message");
|
||||
return false;
|
||||
}
|
||||
@@ -1105,10 +1133,13 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd,
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&dev->slave_mutex);
|
||||
if (!vu_message_write(dev, dev->slave_fd, &vmsg)) {
|
||||
pthread_mutex_unlock(&dev->slave_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Also unlocks the slave_mutex */
|
||||
return vu_process_message_reply(dev, &vmsg);
|
||||
}
|
||||
|
||||
@@ -1628,6 +1659,7 @@ vu_deinit(VuDev *dev)
|
||||
close(dev->slave_fd);
|
||||
dev->slave_fd = -1;
|
||||
}
|
||||
pthread_mutex_destroy(&dev->slave_mutex);
|
||||
|
||||
if (dev->sock != -1) {
|
||||
close(dev->sock);
|
||||
@@ -1663,6 +1695,7 @@ vu_init(VuDev *dev,
|
||||
dev->remove_watch = remove_watch;
|
||||
dev->iface = iface;
|
||||
dev->log_call_fd = -1;
|
||||
pthread_mutex_init(&dev->slave_mutex, NULL);
|
||||
dev->slave_fd = -1;
|
||||
dev->max_queues = max_queues;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/vhost.h>
|
||||
#include <pthread.h>
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
|
||||
/* Based on qemu/hw/virtio/vhost-user.c */
|
||||
@@ -326,6 +327,9 @@ typedef struct VuVirtq {
|
||||
int err_fd;
|
||||
unsigned int enable;
|
||||
bool started;
|
||||
|
||||
/* Guest addresses of our ring */
|
||||
struct vhost_vring_addr vra;
|
||||
} VuVirtq;
|
||||
|
||||
enum VuWatchCondtion {
|
||||
@@ -355,6 +359,8 @@ struct VuDev {
|
||||
VuVirtq *vq;
|
||||
VuDevInflightInfo inflight_info;
|
||||
int log_call_fd;
|
||||
/* Must be held while using slave_fd */
|
||||
pthread_mutex_t slave_mutex;
|
||||
int slave_fd;
|
||||
uint64_t log_size;
|
||||
uint8_t *log_table;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
# @rproc-serial: virtio remoteproc serial link
|
||||
# @scsi: virtio scsi
|
||||
# @vsock: virtio vsock transport
|
||||
# @fs: virtio fs (since 4.2)
|
||||
#
|
||||
# Since: 4.0
|
||||
##
|
||||
@@ -50,7 +51,8 @@
|
||||
'rpmsg',
|
||||
'rproc-serial',
|
||||
'scsi',
|
||||
'vsock'
|
||||
'vsock',
|
||||
'fs'
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,7 +1061,7 @@ static void slave_read(void *opaque)
|
||||
fd[0]);
|
||||
break;
|
||||
default:
|
||||
error_report("Received unexpected msg type.");
|
||||
error_report("Received unexpected msg type: %d.", hdr.request);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -186,6 +186,7 @@ rm -rf "$output/include/standard-headers/linux"
|
||||
mkdir -p "$output/include/standard-headers/linux"
|
||||
for i in "$tmpdir"/include/linux/*virtio*.h \
|
||||
"$tmpdir/include/linux/qemu_fw_cfg.h" \
|
||||
"$tmpdir/include/linux/fuse.h" \
|
||||
"$tmpdir/include/linux/input.h" \
|
||||
"$tmpdir/include/linux/input-event-codes.h" \
|
||||
"$tmpdir/include/linux/pci_regs.h" \
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"description": "QEMU virtiofsd vhost-user-fs",
|
||||
"type": "fs",
|
||||
"binary": "@libexecdir@/virtiofsd"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
virtiofsd-obj-y = buffer.o \
|
||||
fuse_opt.o \
|
||||
fuse_log.o \
|
||||
fuse_lowlevel.o \
|
||||
fuse_signals.o \
|
||||
fuse_virtio.o \
|
||||
helper.o \
|
||||
passthrough_ll.o \
|
||||
seccomp.o
|
||||
|
||||
seccomp.o-cflags := $(SECCOMP_CFLAGS)
|
||||
seccomp.o-libs := $(SECCOMP_LIBS)
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
|
||||
*
|
||||
* Functions for dealing with `struct fuse_buf` and `struct
|
||||
* fuse_bufvec`.
|
||||
*
|
||||
* This program can be distributed under the terms of the GNU LGPLv2.
|
||||
* See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
|
||||
{
|
||||
size_t i;
|
||||
size_t size = 0;
|
||||
|
||||
for (i = 0; i < bufv->count; i++) {
|
||||
if (bufv->buf[i].size == SIZE_MAX) {
|
||||
size = SIZE_MAX;
|
||||
} else {
|
||||
size += bufv->buf[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t fuse_buf_writev(struct fuse_buf *out_buf,
|
||||
struct fuse_bufvec *in_buf)
|
||||
{
|
||||
ssize_t res, i, j;
|
||||
size_t iovcnt = in_buf->count;
|
||||
struct iovec *iov;
|
||||
int fd = out_buf->fd;
|
||||
|
||||
iov = calloc(iovcnt, sizeof(struct iovec));
|
||||
if (!iov) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < iovcnt; i++) {
|
||||
/* Skip the buf with 0 size */
|
||||
if (in_buf->buf[i].size) {
|
||||
iov[j].iov_base = in_buf->buf[i].mem;
|
||||
iov[j].iov_len = in_buf->buf[i].size;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_buf->flags & FUSE_BUF_FD_SEEK) {
|
||||
res = pwritev(fd, iov, iovcnt, out_buf->pos);
|
||||
} else {
|
||||
res = writev(fd, iov, iovcnt);
|
||||
}
|
||||
|
||||
if (res == -1) {
|
||||
res = -errno;
|
||||
}
|
||||
|
||||
free(iov);
|
||||
return res;
|
||||
}
|
||||
|
||||
static size_t min_size(size_t s1, size_t s2)
|
||||
{
|
||||
return s1 < s2 ? s1 : s2;
|
||||
}
|
||||
|
||||
static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
|
||||
const struct fuse_buf *src, size_t src_off,
|
||||
size_t len)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
size_t copied = 0;
|
||||
|
||||
while (len) {
|
||||
if (dst->flags & FUSE_BUF_FD_SEEK) {
|
||||
res = pwrite(dst->fd, (char *)src->mem + src_off, len,
|
||||
dst->pos + dst_off);
|
||||
} else {
|
||||
res = write(dst->fd, (char *)src->mem + src_off, len);
|
||||
}
|
||||
if (res == -1) {
|
||||
if (!copied) {
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
copied += res;
|
||||
if (!(dst->flags & FUSE_BUF_FD_RETRY)) {
|
||||
break;
|
||||
}
|
||||
|
||||
src_off += res;
|
||||
dst_off += res;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
|
||||
const struct fuse_buf *src, size_t src_off,
|
||||
size_t len)
|
||||
{
|
||||
ssize_t res = 0;
|
||||
size_t copied = 0;
|
||||
|
||||
while (len) {
|
||||
if (src->flags & FUSE_BUF_FD_SEEK) {
|
||||
res = pread(src->fd, (char *)dst->mem + dst_off, len,
|
||||
src->pos + src_off);
|
||||
} else {
|
||||
res = read(src->fd, (char *)dst->mem + dst_off, len);
|
||||
}
|
||||
if (res == -1) {
|
||||
if (!copied) {
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
copied += res;
|
||||
if (!(src->flags & FUSE_BUF_FD_RETRY)) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst_off += res;
|
||||
src_off += res;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
|
||||
const struct fuse_buf *src, size_t src_off,
|
||||
size_t len)
|
||||
{
|
||||
char buf[4096];
|
||||
struct fuse_buf tmp = {
|
||||
.size = sizeof(buf),
|
||||
.flags = 0,
|
||||
};
|
||||
ssize_t res;
|
||||
size_t copied = 0;
|
||||
|
||||
tmp.mem = buf;
|
||||
|
||||
while (len) {
|
||||
size_t this_len = min_size(tmp.size, len);
|
||||
size_t read_len;
|
||||
|
||||
res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
|
||||
if (res < 0) {
|
||||
if (!copied) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
read_len = res;
|
||||
res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
|
||||
if (res < 0) {
|
||||
if (!copied) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
copied += res;
|
||||
|
||||
if (res < this_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst_off += res;
|
||||
src_off += res;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
|
||||
const struct fuse_buf *src, size_t src_off,
|
||||
size_t len)
|
||||
{
|
||||
int src_is_fd = src->flags & FUSE_BUF_IS_FD;
|
||||
int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
|
||||
|
||||
if (!src_is_fd && !dst_is_fd) {
|
||||
char *dstmem = (char *)dst->mem + dst_off;
|
||||
char *srcmem = (char *)src->mem + src_off;
|
||||
|
||||
if (dstmem != srcmem) {
|
||||
if (dstmem + len <= srcmem || srcmem + len <= dstmem) {
|
||||
memcpy(dstmem, srcmem, len);
|
||||
} else {
|
||||
memmove(dstmem, srcmem, len);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
} else if (!src_is_fd) {
|
||||
return fuse_buf_write(dst, dst_off, src, src_off, len);
|
||||
} else if (!dst_is_fd) {
|
||||
return fuse_buf_read(dst, dst_off, src, src_off, len);
|
||||
} else {
|
||||
return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
|
||||
{
|
||||
if (bufv->idx < bufv->count) {
|
||||
return &bufv->buf[bufv->idx];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
|
||||
{
|
||||
const struct fuse_buf *buf = fuse_bufvec_current(bufv);
|
||||
|
||||
bufv->off += len;
|
||||
assert(bufv->off <= buf->size);
|
||||
if (bufv->off == buf->size) {
|
||||
assert(bufv->idx < bufv->count);
|
||||
bufv->idx++;
|
||||
if (bufv->idx == bufv->count) {
|
||||
return 0;
|
||||
}
|
||||
bufv->off = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv)
|
||||
{
|
||||
size_t copied = 0, i;
|
||||
|
||||
if (dstv == srcv) {
|
||||
return fuse_buf_size(dstv);
|
||||
}
|
||||
|
||||
/*
|
||||
* use writev to improve bandwidth when all the
|
||||
* src buffers already mapped by the daemon
|
||||
* process
|
||||
*/
|
||||
for (i = 0; i < srcv->count; i++) {
|
||||
if (srcv->buf[i].flags & FUSE_BUF_IS_FD) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i == srcv->count) && (dstv->count == 1) &&
|
||||
(dstv->idx == 0) &&
|
||||
(dstv->buf[0].flags & FUSE_BUF_IS_FD)) {
|
||||
dstv->buf[0].pos += dstv->off;
|
||||
return fuse_buf_writev(&dstv->buf[0], srcv);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const struct fuse_buf *src = fuse_bufvec_current(srcv);
|
||||
const struct fuse_buf *dst = fuse_bufvec_current(dstv);
|
||||
size_t src_len;
|
||||
size_t dst_len;
|
||||
size_t len;
|
||||
ssize_t res;
|
||||
|
||||
if (src == NULL || dst == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
src_len = src->size - srcv->off;
|
||||
dst_len = dst->size - dstv->off;
|
||||
len = min_size(src_len, dst_len);
|
||||
|
||||
res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len);
|
||||
if (res < 0) {
|
||||
if (!copied) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
copied += res;
|
||||
|
||||
if (!fuse_bufvec_advance(srcv, res) ||
|
||||
!fuse_bufvec_advance(dstv, res)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (res < len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
void *fuse_mbuf_iter_advance(struct fuse_mbuf_iter *iter, size_t len)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (len > iter->size - iter->pos) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = iter->mem + iter->pos;
|
||||
iter->pos += len;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const char *fuse_mbuf_iter_advance_str(struct fuse_mbuf_iter *iter)
|
||||
{
|
||||
const char *str = iter->mem + iter->pos;
|
||||
size_t remaining = iter->size - iter->pos;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < remaining; i++) {
|
||||
if (str[i] == '\0') {
|
||||
iter->pos += i + 1;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
|
||||
*
|
||||
* This program can be distributed under the terms of the GNU LGPLv2.
|
||||
* See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#ifndef FUSE_I_H
|
||||
#define FUSE_I_H
|
||||
|
||||
#define FUSE_USE_VERSION 31
|
||||
#include "fuse.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
struct fv_VuDev;
|
||||
struct fv_QueueInfo;
|
||||
|
||||
struct fuse_req {
|
||||
struct fuse_session *se;
|
||||
uint64_t unique;
|
||||
int ctr;
|
||||
pthread_mutex_t lock;
|
||||
struct fuse_ctx ctx;
|
||||
struct fuse_chan *ch;
|
||||
int interrupted;
|
||||
unsigned int ioctl_64bit:1;
|
||||
union {
|
||||
struct {
|
||||
uint64_t unique;
|
||||
} i;
|
||||
struct {
|
||||
fuse_interrupt_func_t func;
|
||||
void *data;
|
||||
} ni;
|
||||
} u;
|
||||
struct fuse_req *next;
|
||||
struct fuse_req *prev;
|
||||
};
|
||||
|
||||
struct fuse_notify_req {
|
||||
uint64_t unique;
|
||||
void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
|
||||
const void *, const struct fuse_buf *);
|
||||
struct fuse_notify_req *next;
|
||||
struct fuse_notify_req *prev;
|
||||
};
|
||||
|
||||
struct fuse_session {
|
||||
char *mountpoint;
|
||||
volatile int exited;
|
||||
int fd;
|
||||
int debug;
|
||||
int deny_others;
|
||||
struct fuse_lowlevel_ops op;
|
||||
int got_init;
|
||||
struct cuse_data *cuse_data;
|
||||
void *userdata;
|
||||
uid_t owner;
|
||||
struct fuse_conn_info conn;
|
||||
struct fuse_req list;
|
||||
struct fuse_req interrupts;
|
||||
pthread_mutex_t lock;
|
||||
pthread_rwlock_t init_rwlock;
|
||||
int got_destroy;
|
||||
int broken_splice_nonblock;
|
||||
uint64_t notify_ctr;
|
||||
struct fuse_notify_req notify_list;
|
||||
size_t bufsize;
|
||||
int error;
|
||||
char *vu_socket_path;
|
||||
int vu_listen_fd;
|
||||
int vu_socketfd;
|
||||
struct fv_VuDev *virtio_dev;
|
||||
int thread_pool_size;
|
||||
};
|
||||
|
||||
struct fuse_chan {
|
||||
pthread_mutex_t lock;
|
||||
int ctr;
|
||||
int fd;
|
||||
struct fv_QueueInfo *qi;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filesystem module
|
||||
*
|
||||
* Filesystem modules are registered with the FUSE_REGISTER_MODULE()
|
||||
* macro.
|
||||
*
|
||||
*/
|
||||
struct fuse_module {
|
||||
char *name;
|
||||
fuse_module_factory_t factory;
|
||||
struct fuse_module *next;
|
||||
struct fusemod_so *so;
|
||||
int ctr;
|
||||
};
|
||||
|
||||
int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
|
||||
int count);
|
||||
void fuse_free_req(fuse_req_t req);
|
||||
|
||||
void fuse_session_process_buf_int(struct fuse_session *se,
|
||||
struct fuse_bufvec *bufv,
|
||||
struct fuse_chan *ch);
|
||||
|
||||
|
||||
#define FUSE_MAX_MAX_PAGES 256
|
||||
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
|
||||
|
||||
/* room needed in buffer to accommodate header */
|
||||
#define FUSE_BUFFER_HEADER_SIZE 0x1000
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* Logging API.
|
||||
*
|
||||
* This program can be distributed under the terms of the GNU LGPLv2.
|
||||
* See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "fuse_log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void default_log_func(__attribute__((unused)) enum fuse_log_level level,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
|
||||
static fuse_log_func_t log_func = default_log_func;
|
||||
|
||||
void fuse_set_log_func(fuse_log_func_t func)
|
||||
{
|
||||
if (!func) {
|
||||
func = default_log_func;
|
||||
}
|
||||
|
||||
log_func = func;
|
||||
}
|
||||
|
||||
void fuse_log(enum fuse_log_level level, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_func(level, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* FUSE: Filesystem in Userspace
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* This program can be distributed under the terms of the GNU LGPLv2.
|
||||
* See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#ifndef FUSE_LOG_H_
|
||||
#define FUSE_LOG_H_
|
||||
|
||||
/** @file
|
||||
*
|
||||
* This file defines the logging interface of FUSE
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Log severity level
|
||||
*
|
||||
* These levels correspond to syslog(2) log levels since they are widely used.
|
||||
*/
|
||||
enum fuse_log_level {
|
||||
FUSE_LOG_EMERG,
|
||||
FUSE_LOG_ALERT,
|
||||
FUSE_LOG_CRIT,
|
||||
FUSE_LOG_ERR,
|
||||
FUSE_LOG_WARNING,
|
||||
FUSE_LOG_NOTICE,
|
||||
FUSE_LOG_INFO,
|
||||
FUSE_LOG_DEBUG
|
||||
};
|
||||
|
||||
/**
|
||||
* Log message handler function.
|
||||
*
|
||||
* This function must be thread-safe. It may be called from any libfuse
|
||||
* function, including fuse_parse_cmdline() and other functions invoked before
|
||||
* a FUSE filesystem is created.
|
||||
*
|
||||
* Install a custom log message handler function using fuse_set_log_func().
|
||||
*
|
||||
* @param level log severity level
|
||||
* @param fmt sprintf-style format string including newline
|
||||
* @param ap format string arguments
|
||||
*/
|
||||
typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt,
|
||||
va_list ap);
|
||||
|
||||
/**
|
||||
* Install a custom log handler function.
|
||||
*
|
||||
* Log messages are emitted by libfuse functions to report errors and debug
|
||||
* information. Messages are printed to stderr by default but this can be
|
||||
* overridden by installing a custom log message handler function.
|
||||
*
|
||||
* The log message handler function is global and affects all FUSE filesystems
|
||||
* created within this process.
|
||||
*
|
||||
* @param func a custom log message handler function or NULL to revert to
|
||||
* the default
|
||||
*/
|
||||
void fuse_set_log_func(fuse_log_func_t func);
|
||||
|
||||
/**
|
||||
* Emit a log message
|
||||
*
|
||||
* @param level severity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc)
|
||||
* @param fmt sprintf-style format string including newline
|
||||
*/
|
||||
void fuse_log(enum fuse_log_level level, const char *fmt, ...);
|
||||
|
||||
#endif /* FUSE_LOG_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user