All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Dr. David Alan Gilbert (git)" <dgilbert@redhat.com>
To: qemu-devel@nongnu.org, stefanha@redhat.com, vgoyal@redhat.com
Subject: [PATCH 005/104] virtiofsd: Add passthrough_ll
Date: Thu, 12 Dec 2019 16:37:25 +0000	[thread overview]
Message-ID: <20191212163904.159893-6-dgilbert@redhat.com> (raw)
In-Reply-To: <20191212163904.159893-1-dgilbert@redhat.com>

From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>

passthrough_ll is one of the examples in the upstream fuse project
and is the main part of our daemon here.  It passes through requests
from fuse to the underlying filesystem, using syscalls as directly
as possible.

From libfuse fuse-3.8.0

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 tools/virtiofsd/passthrough_ll.c | 1338 ++++++++++++++++++++++++++++++
 1 file changed, 1338 insertions(+)
 create mode 100644 tools/virtiofsd/passthrough_ll.c

diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
new file mode 100644
index 0000000000..5372d02934
--- /dev/null
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -0,0 +1,1338 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU GPL.
+  See the file COPYING.
+*/
+
+/** @file
+ *
+ * This file system mirrors the existing file system hierarchy of the
+ * system, starting at the root file system. This is implemented by
+ * just "passing through" all requests to the corresponding user-space
+ * libc functions. In contrast to passthrough.c and passthrough_fh.c,
+ * this implementation uses the low-level API. Its performance should
+ * be the least bad among the three, but many operations are not
+ * implemented. In particular, it is not possible to remove files (or
+ * directories) because the code necessary to defer actual removal
+ * until the file is not opened anymore would make the example much
+ * more complicated.
+ *
+ * When writeback caching is enabled (-o writeback mount option), it
+ * is only possible to write to files for which the mounting user has
+ * read permissions. This is because the writeback cache requires the
+ * kernel to be able to issue read requests for all files (which the
+ * passthrough filesystem cannot satisfy if it can't read the file in
+ * the underlying filesystem).
+ *
+ * Compile with:
+ *
+ *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
+ *
+ * ## Source code ##
+ * \include passthrough_ll.c
+ */
+
+#define _GNU_SOURCE
+#define FUSE_USE_VERSION 31
+
+#include "config.h"
+
+#include <fuse_lowlevel.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/file.h>
+#include <sys/xattr.h>
+
+#include "passthrough_helpers.h"
+
+/* We are re-using pointers to our `struct lo_inode` and `struct
+   lo_dirp` elements as inodes. This means that we must be able to
+   store uintptr_t values in a fuse_ino_t variable. The following
+   incantation checks this condition at compile time. */
+#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
+_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
+	       "fuse_ino_t too small to hold uintptr_t values!");
+#else
+struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
+	{ unsigned _uintptr_to_must_hold_fuse_ino_t:
+			((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
+#endif
+
+struct lo_inode {
+	struct lo_inode *next; /* protected by lo->mutex */
+	struct lo_inode *prev; /* protected by lo->mutex */
+	int fd;
+	bool is_symlink;
+	ino_t ino;
+	dev_t dev;
+	uint64_t refcount; /* protected by lo->mutex */
+};
+
+enum {
+	CACHE_NEVER,
+	CACHE_NORMAL,
+	CACHE_ALWAYS,
+};
+
+struct lo_data {
+	pthread_mutex_t mutex;
+	int debug;
+	int writeback;
+	int flock;
+	int xattr;
+	const char *source;
+	double timeout;
+	int cache;
+	int timeout_set;
+	struct lo_inode root; /* protected by lo->mutex */
+};
+
+static const struct fuse_opt lo_opts[] = {
+	{ "writeback",
+	  offsetof(struct lo_data, writeback), 1 },
+	{ "no_writeback",
+	  offsetof(struct lo_data, writeback), 0 },
+	{ "source=%s",
+	  offsetof(struct lo_data, source), 0 },
+	{ "flock",
+	  offsetof(struct lo_data, flock), 1 },
+	{ "no_flock",
+	  offsetof(struct lo_data, flock), 0 },
+	{ "xattr",
+	  offsetof(struct lo_data, xattr), 1 },
+	{ "no_xattr",
+	  offsetof(struct lo_data, xattr), 0 },
+	{ "timeout=%lf",
+	  offsetof(struct lo_data, timeout), 0 },
+	{ "timeout=",
+	  offsetof(struct lo_data, timeout_set), 1 },
+	{ "cache=never",
+	  offsetof(struct lo_data, cache), CACHE_NEVER },
+	{ "cache=auto",
+	  offsetof(struct lo_data, cache), CACHE_NORMAL },
+	{ "cache=always",
+	  offsetof(struct lo_data, cache), CACHE_ALWAYS },
+
+	FUSE_OPT_END
+};
+
+static struct lo_data *lo_data(fuse_req_t req)
+{
+	return (struct lo_data *) fuse_req_userdata(req);
+}
+
+static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
+{
+	if (ino == FUSE_ROOT_ID)
+		return &lo_data(req)->root;
+	else
+		return (struct lo_inode *) (uintptr_t) ino;
+}
+
+static int lo_fd(fuse_req_t req, fuse_ino_t ino)
+{
+	return lo_inode(req, ino)->fd;
+}
+
+static bool lo_debug(fuse_req_t req)
+{
+	return lo_data(req)->debug != 0;
+}
+
+static void lo_init(void *userdata,
+		    struct fuse_conn_info *conn)
+{
+	struct lo_data *lo = (struct lo_data*) userdata;
+
+	if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
+		conn->want |= FUSE_CAP_EXPORT_SUPPORT;
+
+	if (lo->writeback &&
+	    conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
+		if (lo->debug)
+			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
+		conn->want |= FUSE_CAP_WRITEBACK_CACHE;
+	}
+	if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
+		if (lo->debug)
+			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
+		conn->want |= FUSE_CAP_FLOCK_LOCKS;
+	}
+}
+
+static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
+			     struct fuse_file_info *fi)
+{
+	int res;
+	struct stat buf;
+	struct lo_data *lo = lo_data(req);
+
+	(void) fi;
+
+	res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+	if (res == -1)
+		return (void) fuse_reply_err(req, errno);
+
+	fuse_reply_attr(req, &buf, lo->timeout);
+}
+
+static int utimensat_empty_nofollow(struct lo_inode *inode,
+				    const struct timespec *tv)
+{
+	int res;
+	char procname[64];
+
+	if (inode->is_symlink) {
+		res = utimensat(inode->fd, "", tv,
+				AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+		if (res == -1 && errno == EINVAL) {
+			/* Sorry, no race free way to set times on symlink. */
+			errno = EPERM;
+		}
+		return res;
+	}
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	return utimensat(AT_FDCWD, procname, tv, 0);
+}
+
+static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+		       int valid, struct fuse_file_info *fi)
+{
+	int saverr;
+	char procname[64];
+	struct lo_inode *inode = lo_inode(req, ino);
+	int ifd = inode->fd;
+	int res;
+
+	if (valid & FUSE_SET_ATTR_MODE) {
+		if (fi) {
+			res = fchmod(fi->fh, attr->st_mode);
+		} else {
+			sprintf(procname, "/proc/self/fd/%i", ifd);
+			res = chmod(procname, attr->st_mode);
+		}
+		if (res == -1)
+			goto out_err;
+	}
+	if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
+		uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
+			attr->st_uid : (uid_t) -1;
+		gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
+			attr->st_gid : (gid_t) -1;
+
+		res = fchownat(ifd, "", uid, gid,
+			       AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+		if (res == -1)
+			goto out_err;
+	}
+	if (valid & FUSE_SET_ATTR_SIZE) {
+		if (fi) {
+			res = ftruncate(fi->fh, attr->st_size);
+		} else {
+			sprintf(procname, "/proc/self/fd/%i", ifd);
+			res = truncate(procname, attr->st_size);
+		}
+		if (res == -1)
+			goto out_err;
+	}
+	if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
+		struct timespec tv[2];
+
+		tv[0].tv_sec = 0;
+		tv[1].tv_sec = 0;
+		tv[0].tv_nsec = UTIME_OMIT;
+		tv[1].tv_nsec = UTIME_OMIT;
+
+		if (valid & FUSE_SET_ATTR_ATIME_NOW)
+			tv[0].tv_nsec = UTIME_NOW;
+		else if (valid & FUSE_SET_ATTR_ATIME)
+			tv[0] = attr->st_atim;
+
+		if (valid & FUSE_SET_ATTR_MTIME_NOW)
+			tv[1].tv_nsec = UTIME_NOW;
+		else if (valid & FUSE_SET_ATTR_MTIME)
+			tv[1] = attr->st_mtim;
+
+		if (fi)
+			res = futimens(fi->fh, tv);
+		else
+			res = utimensat_empty_nofollow(inode, tv);
+		if (res == -1)
+			goto out_err;
+	}
+
+	return lo_getattr(req, ino, fi);
+
+out_err:
+	saverr = errno;
+	fuse_reply_err(req, saverr);
+}
+
+static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
+{
+	struct lo_inode *p;
+	struct lo_inode *ret = NULL;
+
+	pthread_mutex_lock(&lo->mutex);
+	for (p = lo->root.next; p != &lo->root; p = p->next) {
+		if (p->ino == st->st_ino && p->dev == st->st_dev) {
+			assert(p->refcount > 0);
+			ret = p;
+			ret->refcount++;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&lo->mutex);
+	return ret;
+}
+
+static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
+			 struct fuse_entry_param *e)
+{
+	int newfd;
+	int res;
+	int saverr;
+	struct lo_data *lo = lo_data(req);
+	struct lo_inode *inode;
+
+	memset(e, 0, sizeof(*e));
+	e->attr_timeout = lo->timeout;
+	e->entry_timeout = lo->timeout;
+
+	newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
+	if (newfd == -1)
+		goto out_err;
+
+	res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+	if (res == -1)
+		goto out_err;
+
+	inode = lo_find(lo_data(req), &e->attr);
+	if (inode) {
+		close(newfd);
+		newfd = -1;
+	} else {
+		struct lo_inode *prev, *next;
+
+		saverr = ENOMEM;
+		inode = calloc(1, sizeof(struct lo_inode));
+		if (!inode)
+			goto out_err;
+
+		inode->is_symlink = S_ISLNK(e->attr.st_mode);
+		inode->refcount = 1;
+		inode->fd = newfd;
+		inode->ino = e->attr.st_ino;
+		inode->dev = e->attr.st_dev;
+
+		pthread_mutex_lock(&lo->mutex);
+		prev = &lo->root;
+		next = prev->next;
+		next->prev = inode;
+		inode->next = next;
+		inode->prev = prev;
+		prev->next = inode;
+		pthread_mutex_unlock(&lo->mutex);
+	}
+	e->ino = (uintptr_t) inode;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+			(unsigned long long) parent, name, (unsigned long long) e->ino);
+
+	return 0;
+
+out_err:
+	saverr = errno;
+	if (newfd != -1)
+		close(newfd);
+	return saverr;
+}
+
+static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+	struct fuse_entry_param e;
+	int err;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
+			parent, name);
+
+	err = lo_do_lookup(req, parent, name, &e);
+	if (err)
+		fuse_reply_err(req, err);
+	else
+		fuse_reply_entry(req, &e);
+}
+
+static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
+			     const char *name, mode_t mode, dev_t rdev,
+			     const char *link)
+{
+	int res;
+	int saverr;
+	struct lo_inode *dir = lo_inode(req, parent);
+	struct fuse_entry_param e;
+
+	saverr = ENOMEM;
+
+	res = mknod_wrapper(dir->fd, name, link, mode, rdev);
+
+	saverr = errno;
+	if (res == -1)
+		goto out;
+
+	saverr = lo_do_lookup(req, parent, name, &e);
+	if (saverr)
+		goto out;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+			(unsigned long long) parent, name, (unsigned long long) e.ino);
+
+	fuse_reply_entry(req, &e);
+	return;
+
+out:
+	fuse_reply_err(req, saverr);
+}
+
+static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
+		     const char *name, mode_t mode, dev_t rdev)
+{
+	lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
+}
+
+static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
+		     mode_t mode)
+{
+	lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
+}
+
+static void lo_symlink(fuse_req_t req, const char *link,
+		       fuse_ino_t parent, const char *name)
+{
+	lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
+}
+
+static int linkat_empty_nofollow(struct lo_inode *inode, int dfd,
+				 const char *name)
+{
+	int res;
+	char procname[64];
+
+	if (inode->is_symlink) {
+		res = linkat(inode->fd, "", dfd, name, AT_EMPTY_PATH);
+		if (res == -1 && (errno == ENOENT || errno == EINVAL)) {
+			/* Sorry, no race free way to hard-link a symlink. */
+			errno = EPERM;
+		}
+		return res;
+	}
+
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	return linkat(AT_FDCWD, procname, dfd, name, AT_SYMLINK_FOLLOW);
+}
+
+static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
+		    const char *name)
+{
+	int res;
+	struct lo_data *lo = lo_data(req);
+	struct lo_inode *inode = lo_inode(req, ino);
+	struct fuse_entry_param e;
+	int saverr;
+
+	memset(&e, 0, sizeof(struct fuse_entry_param));
+	e.attr_timeout = lo->timeout;
+	e.entry_timeout = lo->timeout;
+
+	res = linkat_empty_nofollow(inode, lo_fd(req, parent), name);
+	if (res == -1)
+		goto out_err;
+
+	res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
+	if (res == -1)
+		goto out_err;
+
+	pthread_mutex_lock(&lo->mutex);
+	inode->refcount++;
+	pthread_mutex_unlock(&lo->mutex);
+	e.ino = (uintptr_t) inode;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
+			(unsigned long long) parent, name,
+			(unsigned long long) e.ino);
+
+	fuse_reply_entry(req, &e);
+	return;
+
+out_err:
+	saverr = errno;
+	fuse_reply_err(req, saverr);
+}
+
+static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+	int res;
+
+	res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
+
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
+		      fuse_ino_t newparent, const char *newname,
+		      unsigned int flags)
+{
+	int res;
+
+	if (flags) {
+		fuse_reply_err(req, EINVAL);
+		return;
+	}
+
+	res = renameat(lo_fd(req, parent), name,
+			lo_fd(req, newparent), newname);
+
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+	int res;
+
+	res = unlinkat(lo_fd(req, parent), name, 0);
+
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
+{
+	if (!inode)
+		return;
+
+	pthread_mutex_lock(&lo->mutex);
+	assert(inode->refcount >= n);
+	inode->refcount -= n;
+	if (!inode->refcount) {
+		struct lo_inode *prev, *next;
+
+		prev = inode->prev;
+		next = inode->next;
+		next->prev = prev;
+		prev->next = next;
+
+		pthread_mutex_unlock(&lo->mutex);
+		close(inode->fd);
+		free(inode);
+
+	} else {
+		pthread_mutex_unlock(&lo->mutex);
+	}
+}
+
+static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+{
+	struct lo_data *lo = lo_data(req);
+	struct lo_inode *inode = lo_inode(req, ino);
+
+	if (lo_debug(req)) {
+		fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
+			(unsigned long long) ino,
+			(unsigned long long) inode->refcount,
+			(unsigned long long) nlookup);
+	}
+
+	unref_inode(lo, inode, nlookup);
+}
+
+static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
+{
+	lo_forget_one(req, ino, nlookup);
+	fuse_reply_none(req);
+}
+
+static void lo_forget_multi(fuse_req_t req, size_t count,
+				struct fuse_forget_data *forgets)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
+	fuse_reply_none(req);
+}
+
+static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
+{
+	char buf[PATH_MAX + 1];
+	int res;
+
+	res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
+	if (res == -1)
+		return (void) fuse_reply_err(req, errno);
+
+	if (res == sizeof(buf))
+		return (void) fuse_reply_err(req, ENAMETOOLONG);
+
+	buf[res] = '\0';
+
+	fuse_reply_readlink(req, buf);
+}
+
+struct lo_dirp {
+	DIR *dp;
+	struct dirent *entry;
+	off_t offset;
+};
+
+static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
+{
+	return (struct lo_dirp *) (uintptr_t) fi->fh;
+}
+
+static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+{
+	int error = ENOMEM;
+	struct lo_data *lo = lo_data(req);
+	struct lo_dirp *d;
+	int fd;
+
+	d = calloc(1, sizeof(struct lo_dirp));
+	if (d == NULL)
+		goto out_err;
+
+	fd = openat(lo_fd(req, ino), ".", O_RDONLY);
+	if (fd == -1)
+		goto out_errno;
+
+	d->dp = fdopendir(fd);
+	if (d->dp == NULL)
+		goto out_errno;
+
+	d->offset = 0;
+	d->entry = NULL;
+
+	fi->fh = (uintptr_t) d;
+	if (lo->cache == CACHE_ALWAYS)
+		fi->keep_cache = 1;
+	fuse_reply_open(req, fi);
+	return;
+
+out_errno:
+	error = errno;
+out_err:
+	if (d) {
+		if (fd != -1)
+			close(fd);
+		free(d);
+	}
+	fuse_reply_err(req, error);
+}
+
+static int is_dot_or_dotdot(const char *name)
+{
+	return name[0] == '.' && (name[1] == '\0' ||
+				  (name[1] == '.' && name[2] == '\0'));
+}
+
+static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+			  off_t offset, struct fuse_file_info *fi, int plus)
+{
+	struct lo_dirp *d = lo_dirp(fi);
+	char *buf;
+	char *p;
+	size_t rem = size;
+	int err;
+
+	(void) ino;
+
+	buf = calloc(1, size);
+	if (!buf) {
+		err = ENOMEM;
+		goto error;
+	}
+	p = buf;
+
+	if (offset != d->offset) {
+		seekdir(d->dp, offset);
+		d->entry = NULL;
+		d->offset = offset;
+	}
+	while (1) {
+		size_t entsize;
+		off_t nextoff;
+		const char *name;
+
+		if (!d->entry) {
+			errno = 0;
+			d->entry = readdir(d->dp);
+			if (!d->entry) {
+				if (errno) {  // Error
+					err = errno;
+					goto error;
+				} else {  // End of stream
+					break; 
+				}
+			}
+		}
+		nextoff = d->entry->d_off;
+		name = d->entry->d_name;
+		fuse_ino_t entry_ino = 0;
+		if (plus) {
+			struct fuse_entry_param e;
+			if (is_dot_or_dotdot(name)) {
+				e = (struct fuse_entry_param) {
+					.attr.st_ino = d->entry->d_ino,
+					.attr.st_mode = d->entry->d_type << 12,
+				};
+			} else {
+				err = lo_do_lookup(req, ino, name, &e);
+				if (err)
+					goto error;
+				entry_ino = e.ino;
+			}
+
+			entsize = fuse_add_direntry_plus(req, p, rem, name,
+							 &e, nextoff);
+		} else {
+			struct stat st = {
+				.st_ino = d->entry->d_ino,
+				.st_mode = d->entry->d_type << 12,
+			};
+			entsize = fuse_add_direntry(req, p, rem, name,
+						    &st, nextoff);
+		}
+		if (entsize > rem) {
+			if (entry_ino != 0) 
+				lo_forget_one(req, entry_ino, 1);
+			break;
+		}
+		
+		p += entsize;
+		rem -= entsize;
+
+		d->entry = NULL;
+		d->offset = nextoff;
+	}
+
+    err = 0;
+error:
+    // If there's an error, we can only signal it if we haven't stored
+    // any entries yet - otherwise we'd end up with wrong lookup
+    // counts for the entries that are already in the buffer. So we
+    // return what we've collected until that point.
+    if (err && rem == size)
+	    fuse_reply_err(req, err);
+    else
+	    fuse_reply_buf(req, buf, size - rem);
+    free(buf);
+}
+
+static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+		       off_t offset, struct fuse_file_info *fi)
+{
+	lo_do_readdir(req, ino, size, offset, fi, 0);
+}
+
+static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
+			   off_t offset, struct fuse_file_info *fi)
+{
+	lo_do_readdir(req, ino, size, offset, fi, 1);
+}
+
+static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+{
+	struct lo_dirp *d = lo_dirp(fi);
+	(void) ino;
+	closedir(d->dp);
+	free(d);
+	fuse_reply_err(req, 0);
+}
+
+static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
+		      mode_t mode, struct fuse_file_info *fi)
+{
+	int fd;
+	struct lo_data *lo = lo_data(req);
+	struct fuse_entry_param e;
+	int err;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
+			parent, name);
+
+	fd = openat(lo_fd(req, parent), name,
+		    (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
+	if (fd == -1)
+		return (void) fuse_reply_err(req, errno);
+
+	fi->fh = fd;
+	if (lo->cache == CACHE_NEVER)
+		fi->direct_io = 1;
+	else if (lo->cache == CACHE_ALWAYS)
+		fi->keep_cache = 1;
+
+	err = lo_do_lookup(req, parent, name, &e);
+	if (err)
+		fuse_reply_err(req, err);
+	else
+		fuse_reply_create(req, &e, fi);
+}
+
+static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+			struct fuse_file_info *fi)
+{
+	int res;
+	int fd = dirfd(lo_dirp(fi)->dp);
+	(void) ino;
+	if (datasync)
+		res = fdatasync(fd);
+	else
+		res = fsync(fd);
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+{
+	int fd;
+	char buf[64];
+	struct lo_data *lo = lo_data(req);
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
+			ino, fi->flags);
+
+	/* With writeback cache, kernel may send read requests even
+	   when userspace opened write-only */
+	if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
+		fi->flags &= ~O_ACCMODE;
+		fi->flags |= O_RDWR;
+	}
+
+	/* With writeback cache, O_APPEND is handled by the kernel.
+	   This breaks atomicity (since the file may change in the
+	   underlying filesystem, so that the kernel's idea of the
+	   end of the file isn't accurate anymore). In this example,
+	   we just accept that. A more rigorous filesystem may want
+	   to return an error here */
+	if (lo->writeback && (fi->flags & O_APPEND))
+		fi->flags &= ~O_APPEND;
+
+	sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
+	fd = open(buf, fi->flags & ~O_NOFOLLOW);
+	if (fd == -1)
+		return (void) fuse_reply_err(req, errno);
+
+	fi->fh = fd;
+	if (lo->cache == CACHE_NEVER)
+		fi->direct_io = 1;
+	else if (lo->cache == CACHE_ALWAYS)
+		fi->keep_cache = 1;
+	fuse_reply_open(req, fi);
+}
+
+static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+{
+	(void) ino;
+
+	close(fi->fh);
+	fuse_reply_err(req, 0);
+}
+
+static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+{
+	int res;
+	(void) ino;
+	res = close(dup(fi->fh));
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+		     struct fuse_file_info *fi)
+{
+	int res;
+	(void) ino;
+	if (datasync)
+		res = fdatasync(fi->fh);
+	else
+		res = fsync(fi->fh);
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+		    off_t offset, struct fuse_file_info *fi)
+{
+	struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
+			"off=%lu)\n", ino, size, (unsigned long) offset);
+
+	buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+	buf.buf[0].fd = fi->fh;
+	buf.buf[0].pos = offset;
+
+	fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
+}
+
+static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
+			 struct fuse_bufvec *in_buf, off_t off,
+			 struct fuse_file_info *fi)
+{
+	(void) ino;
+	ssize_t res;
+	struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
+
+	out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
+	out_buf.buf[0].fd = fi->fh;
+	out_buf.buf[0].pos = off;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
+			ino, out_buf.buf[0].size, (unsigned long) off);
+
+	res = fuse_buf_copy(&out_buf, in_buf, 0);
+	if(res < 0)
+		fuse_reply_err(req, -res);
+	else
+		fuse_reply_write(req, (size_t) res);
+}
+
+static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
+{
+	int res;
+	struct statvfs stbuf;
+
+	res = fstatvfs(lo_fd(req, ino), &stbuf);
+	if (res == -1)
+		fuse_reply_err(req, errno);
+	else
+		fuse_reply_statfs(req, &stbuf);
+}
+
+static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
+			 off_t offset, off_t length, struct fuse_file_info *fi)
+{
+	int err = EOPNOTSUPP;
+	(void) ino;
+
+#ifdef HAVE_FALLOCATE
+	err = fallocate(fi->fh, mode, offset, length);
+	if (err < 0)
+		err = errno;
+
+#elif defined(HAVE_POSIX_FALLOCATE)
+	if (mode) {
+		fuse_reply_err(req, EOPNOTSUPP);
+		return;
+	}
+
+	err = posix_fallocate(fi->fh, offset, length);
+#endif
+
+	fuse_reply_err(req, err);
+}
+
+static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
+		     int op)
+{
+	int res;
+	(void) ino;
+
+	res = flock(fi->fh, op);
+
+	fuse_reply_err(req, res == -1 ? errno : 0);
+}
+
+static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+			size_t size)
+{
+	char *value = NULL;
+	char procname[64];
+	struct lo_inode *inode = lo_inode(req, ino);
+	ssize_t ret;
+	int saverr;
+
+	saverr = ENOSYS;
+	if (!lo_data(req)->xattr)
+		goto out;
+
+	if (lo_debug(req)) {
+		fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
+			ino, name, size);
+	}
+
+	if (inode->is_symlink) {
+		/* Sorry, no race free way to getxattr on symlink. */
+		saverr = EPERM;
+		goto out;
+	}
+
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	if (size) {
+		value = malloc(size);
+		if (!value)
+			goto out_err;
+
+		ret = getxattr(procname, name, value, size);
+		if (ret == -1)
+			goto out_err;
+		saverr = 0;
+		if (ret == 0)
+			goto out;
+
+		fuse_reply_buf(req, value, ret);
+	} else {
+		ret = getxattr(procname, name, NULL, 0);
+		if (ret == -1)
+			goto out_err;
+
+		fuse_reply_xattr(req, ret);
+	}
+out_free:
+	free(value);
+	return;
+
+out_err:
+	saverr = errno;
+out:
+	fuse_reply_err(req, saverr);
+	goto out_free;
+}
+
+static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+{
+	char *value = NULL;
+	char procname[64];
+	struct lo_inode *inode = lo_inode(req, ino);
+	ssize_t ret;
+	int saverr;
+
+	saverr = ENOSYS;
+	if (!lo_data(req)->xattr)
+		goto out;
+
+	if (lo_debug(req)) {
+		fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
+			ino, size);
+	}
+
+	if (inode->is_symlink) {
+		/* Sorry, no race free way to listxattr on symlink. */
+		saverr = EPERM;
+		goto out;
+	}
+
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	if (size) {
+		value = malloc(size);
+		if (!value)
+			goto out_err;
+
+		ret = listxattr(procname, value, size);
+		if (ret == -1)
+			goto out_err;
+		saverr = 0;
+		if (ret == 0)
+			goto out;
+
+		fuse_reply_buf(req, value, ret);
+	} else {
+		ret = listxattr(procname, NULL, 0);
+		if (ret == -1)
+			goto out_err;
+
+		fuse_reply_xattr(req, ret);
+	}
+out_free:
+	free(value);
+	return;
+
+out_err:
+	saverr = errno;
+out:
+	fuse_reply_err(req, saverr);
+	goto out_free;
+}
+
+static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+			const char *value, size_t size, int flags)
+{
+	char procname[64];
+	struct lo_inode *inode = lo_inode(req, ino);
+	ssize_t ret;
+	int saverr;
+
+	saverr = ENOSYS;
+	if (!lo_data(req)->xattr)
+		goto out;
+
+	if (lo_debug(req)) {
+		fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
+			ino, name, value, size);
+	}
+
+	if (inode->is_symlink) {
+		/* Sorry, no race free way to setxattr on symlink. */
+		saverr = EPERM;
+		goto out;
+	}
+
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	ret = setxattr(procname, name, value, size, flags);
+	saverr = ret == -1 ? errno : 0;
+
+out:
+	fuse_reply_err(req, saverr);
+}
+
+static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
+{
+	char procname[64];
+	struct lo_inode *inode = lo_inode(req, ino);
+	ssize_t ret;
+	int saverr;
+
+	saverr = ENOSYS;
+	if (!lo_data(req)->xattr)
+		goto out;
+
+	if (lo_debug(req)) {
+		fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
+			ino, name);
+	}
+
+	if (inode->is_symlink) {
+		/* Sorry, no race free way to setxattr on symlink. */
+		saverr = EPERM;
+		goto out;
+	}
+
+	sprintf(procname, "/proc/self/fd/%i", inode->fd);
+
+	ret = removexattr(procname, name);
+	saverr = ret == -1 ? errno : 0;
+
+out:
+	fuse_reply_err(req, saverr);
+}
+
+#ifdef HAVE_COPY_FILE_RANGE
+static void lo_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)
+{
+	ssize_t res;
+
+	if (lo_debug(req))
+		fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
+				"off=%lu, ino=%" PRIu64 "/fd=%lu, "
+				"off=%lu, size=%zd, flags=0x%x)\n",
+			ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
+			len, flags);
+
+	res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
+			      flags);
+	if (res < 0)
+		fuse_reply_err(req, -errno);
+	else
+		fuse_reply_write(req, res);
+}
+#endif
+
+static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
+		     struct fuse_file_info *fi)
+{
+	off_t res;
+
+	(void)ino;
+	res = lseek(fi->fh, off, whence);
+	if (res != -1)
+		fuse_reply_lseek(req, res);
+	else
+		fuse_reply_err(req, errno);
+}
+
+static struct fuse_lowlevel_ops lo_oper = {
+	.init		= lo_init,
+	.lookup		= lo_lookup,
+	.mkdir		= lo_mkdir,
+	.mknod		= lo_mknod,
+	.symlink	= lo_symlink,
+	.link		= lo_link,
+	.unlink		= lo_unlink,
+	.rmdir		= lo_rmdir,
+	.rename		= lo_rename,
+	.forget		= lo_forget,
+	.forget_multi	= lo_forget_multi,
+	.getattr	= lo_getattr,
+	.setattr	= lo_setattr,
+	.readlink	= lo_readlink,
+	.opendir	= lo_opendir,
+	.readdir	= lo_readdir,
+	.readdirplus	= lo_readdirplus,
+	.releasedir	= lo_releasedir,
+	.fsyncdir	= lo_fsyncdir,
+	.create		= lo_create,
+	.open		= lo_open,
+	.release	= lo_release,
+	.flush		= lo_flush,
+	.fsync		= lo_fsync,
+	.read		= lo_read,
+	.write_buf      = lo_write_buf,
+	.statfs		= lo_statfs,
+	.fallocate	= lo_fallocate,
+	.flock		= lo_flock,
+	.getxattr	= lo_getxattr,
+	.listxattr	= lo_listxattr,
+	.setxattr	= lo_setxattr,
+	.removexattr	= lo_removexattr,
+#ifdef HAVE_COPY_FILE_RANGE
+	.copy_file_range = lo_copy_file_range,
+#endif
+	.lseek		= lo_lseek,
+};
+
+int main(int argc, char *argv[])
+{
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+	struct fuse_session *se;
+	struct fuse_cmdline_opts opts;
+	struct lo_data lo = { .debug = 0,
+	                      .writeback = 0 };
+	int ret = -1;
+
+	/* Don't mask creation mode, kernel already did that */
+	umask(0);
+
+	pthread_mutex_init(&lo.mutex, NULL);
+	lo.root.next = lo.root.prev = &lo.root;
+	lo.root.fd = -1;
+	lo.cache = CACHE_NORMAL;
+
+	if (fuse_parse_cmdline(&args, &opts) != 0)
+		return 1;
+	if (opts.show_help) {
+		printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
+		fuse_cmdline_help();
+		fuse_lowlevel_help();
+		ret = 0;
+		goto err_out1;
+	} else if (opts.show_version) {
+		printf("FUSE library version %s\n", fuse_pkgversion());
+		fuse_lowlevel_version();
+		ret = 0;
+		goto err_out1;
+	}
+
+	if(opts.mountpoint == NULL) {
+		printf("usage: %s [options] <mountpoint>\n", argv[0]);
+		printf("       %s --help\n", argv[0]);
+		ret = 1;
+		goto err_out1;
+	}
+
+	if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
+		return 1;
+
+	lo.debug = opts.debug;
+	lo.root.refcount = 2;
+	if (lo.source) {
+		struct stat stat;
+		int res;
+
+		res = lstat(lo.source, &stat);
+		if (res == -1) {
+			fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
+				 lo.source);
+			exit(1);
+		}
+		if (!S_ISDIR(stat.st_mode)) {
+			fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
+			exit(1);
+		}
+
+	} else {
+		lo.source = "/";
+	}
+	lo.root.is_symlink = false;
+	if (!lo.timeout_set) {
+		switch (lo.cache) {
+		case CACHE_NEVER:
+			lo.timeout = 0.0;
+			break;
+
+		case CACHE_NORMAL:
+			lo.timeout = 1.0;
+			break;
+
+		case CACHE_ALWAYS:
+			lo.timeout = 86400.0;
+			break;
+		}
+	} else if (lo.timeout < 0) {
+		fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
+			 lo.timeout);
+		exit(1);
+	}
+
+	lo.root.fd = open(lo.source, O_PATH);
+	if (lo.root.fd == -1) {
+		fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
+			 lo.source);
+		exit(1);
+	}
+
+	se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
+	if (se == NULL)
+	    goto err_out1;
+
+	if (fuse_set_signal_handlers(se) != 0)
+	    goto err_out2;
+
+	if (fuse_session_mount(se, opts.mountpoint) != 0)
+	    goto err_out3;
+
+	fuse_daemonize(opts.foreground);
+
+	/* Block until ctrl+c or fusermount -u */
+	if (opts.singlethread)
+		ret = fuse_session_loop(se);
+	else
+		ret = fuse_session_loop_mt(se, opts.clone_fd);
+
+	fuse_session_unmount(se);
+err_out3:
+	fuse_remove_signal_handlers(se);
+err_out2:
+	fuse_session_destroy(se);
+err_out1:
+	free(opts.mountpoint);
+	fuse_opt_free_args(&args);
+
+	if (lo.root.fd >= 0)
+		close(lo.root.fd);
+
+	return ret ? 1 : 0;
+}
-- 
2.23.0



  parent reply	other threads:[~2019-12-12 16:43 UTC|newest]

Thread overview: 307+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-12 16:37 [PATCH 000/104] virtiofs daemon [all] Dr. David Alan Gilbert (git)
2019-12-12 16:37 ` [PATCH 001/104] virtiofsd: Pull in upstream headers Dr. David Alan Gilbert (git)
2020-01-03 11:54   ` Daniel P. Berrangé
2020-01-15 17:38   ` Philippe Mathieu-Daudé
2019-12-12 16:37 ` [PATCH 002/104] virtiofsd: Pull in kernel's fuse.h Dr. David Alan Gilbert (git)
2020-01-03 11:56   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 003/104] virtiofsd: Add auxiliary .c's Dr. David Alan Gilbert (git)
2020-01-03 11:57   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 004/104] virtiofsd: Add fuse_lowlevel.c Dr. David Alan Gilbert (git)
2020-01-03 11:58   ` Daniel P. Berrangé
2019-12-12 16:37 ` Dr. David Alan Gilbert (git) [this message]
2020-01-03 12:01   ` [PATCH 005/104] virtiofsd: Add passthrough_ll Daniel P. Berrangé
2020-01-03 12:15     ` Dr. David Alan Gilbert
2020-01-03 12:33       ` Daniel P. Berrangé
2020-01-03 14:37         ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 006/104] virtiofsd: Trim down imported files Dr. David Alan Gilbert (git)
2020-01-03 12:02   ` Daniel P. Berrangé
2020-01-21  9:58   ` Xiao Yang
2020-01-21 10:51     ` Dr. David Alan Gilbert
2020-01-22  0:57       ` Xiao Yang
2019-12-12 16:37 ` [PATCH 007/104] virtiofsd: Format imported files to qemu style Dr. David Alan Gilbert (git)
2020-01-03 12:04   ` Daniel P. Berrangé
2020-01-09 12:21   ` Aleksandar Markovic
2019-12-12 16:37 ` [PATCH 008/104] virtiofsd: remove mountpoint dummy argument Dr. David Alan Gilbert (git)
2020-01-03 12:12   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 009/104] virtiofsd: remove unused notify reply support Dr. David Alan Gilbert (git)
2020-01-03 12:14   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 010/104] virtiofsd: Fix fuse_daemonize ignored return values Dr. David Alan Gilbert (git)
2020-01-03 12:18   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 011/104] virtiofsd: Fix common header and define for QEMU builds Dr. David Alan Gilbert (git)
2020-01-03 12:22   ` Daniel P. Berrangé
2020-01-06 16:29     ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 012/104] virtiofsd: Trim out compatibility code Dr. David Alan Gilbert (git)
2020-01-03 12:26   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 013/104] virtiofsd: Make fsync work even if only inode is passed in Dr. David Alan Gilbert (git)
2020-01-03 15:13   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 014/104] virtiofsd: Add options for virtio Dr. David Alan Gilbert (git)
2020-01-03 15:18   ` Daniel P. Berrangé
2020-01-10 16:01     ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 015/104] virtiofsd: add -o source=PATH to help output Dr. David Alan Gilbert (git)
2020-01-03 15:18   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 016/104] virtiofsd: Open vhost connection instead of mounting Dr. David Alan Gilbert (git)
2020-01-03 15:21   ` Daniel P. Berrangé
2020-01-21  6:57   ` Misono Tomohiro
2020-01-21 11:38     ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 017/104] virtiofsd: Start wiring up vhost-user Dr. David Alan Gilbert (git)
2020-01-03 15:25   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 018/104] virtiofsd: Add main virtio loop Dr. David Alan Gilbert (git)
2020-01-03 15:26   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 019/104] virtiofsd: get/set features callbacks Dr. David Alan Gilbert (git)
2020-01-03 15:26   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 020/104] virtiofsd: Start queue threads Dr. David Alan Gilbert (git)
2020-01-03 15:27   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 021/104] virtiofsd: Poll kick_fd for queue Dr. David Alan Gilbert (git)
2020-01-03 15:33   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 022/104] virtiofsd: Start reading commands from queue Dr. David Alan Gilbert (git)
2020-01-03 15:34   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 023/104] virtiofsd: Send replies to messages Dr. David Alan Gilbert (git)
2020-01-03 15:36   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 024/104] virtiofsd: Keep track of replies Dr. David Alan Gilbert (git)
2020-01-03 15:41   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 025/104] virtiofsd: Add Makefile wiring for virtiofsd contrib Dr. David Alan Gilbert (git)
2019-12-13 16:02   ` Liam Merwick
2019-12-13 16:56     ` Dr. David Alan Gilbert
2020-01-03 15:41   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 026/104] virtiofsd: Fast path for virtio read Dr. David Alan Gilbert (git)
2020-01-17 18:54   ` Masayoshi Mizuma
2020-01-20 12:32     ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 027/104] virtiofsd: add --fd=FDNUM fd passing option Dr. David Alan Gilbert (git)
2020-01-06 14:12   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 028/104] virtiofsd: make -f (foreground) the default Dr. David Alan Gilbert (git)
2020-01-06 14:19   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 029/104] virtiofsd: add vhost-user.json file Dr. David Alan Gilbert (git)
2020-01-06 14:19   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 030/104] virtiofsd: add --print-capabilities option Dr. David Alan Gilbert (git)
2020-01-06 14:20   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 031/104] virtiofs: Add maintainers entry Dr. David Alan Gilbert (git)
2020-01-06 14:21   ` Daniel P. Berrangé
2020-01-15 17:19   ` Philippe Mathieu-Daudé
2019-12-12 16:37 ` [PATCH 032/104] virtiofsd: passthrough_ll: create new files in caller's context Dr. David Alan Gilbert (git)
2020-01-06 14:30   ` Daniel P. Berrangé
2020-01-06 19:00     ` Dr. David Alan Gilbert
2020-01-06 19:08       ` Dr. David Alan Gilbert
2020-01-07  9:22         ` Daniel P. Berrangé
2020-01-10 13:05           ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 033/104] virtiofsd: passthrough_ll: add lo_map for ino/fh indirection Dr. David Alan Gilbert (git)
2020-01-17 21:44   ` Masayoshi Mizuma
2019-12-12 16:37 ` [PATCH 034/104] virtiofsd: passthrough_ll: add ino_map to hide lo_inode pointers Dr. David Alan Gilbert (git)
2020-01-17 21:45   ` Masayoshi Mizuma
2019-12-12 16:37 ` [PATCH 035/104] virtiofsd: passthrough_ll: add dirp_map to hide lo_dirp pointers Dr. David Alan Gilbert (git)
2020-01-17 13:58   ` Philippe Mathieu-Daudé
2019-12-12 16:37 ` [PATCH 036/104] virtiofsd: passthrough_ll: add fd_map to hide file descriptors Dr. David Alan Gilbert (git)
2020-01-17 22:32   ` Masayoshi Mizuma
2019-12-12 16:37 ` [PATCH 037/104] virtiofsd: passthrough_ll: add fallback for racy ops Dr. David Alan Gilbert (git)
2020-01-18 16:22   ` Masayoshi Mizuma
2020-01-20 13:26     ` Dr. David Alan Gilbert
2019-12-12 16:37 ` [PATCH 038/104] virtiofsd: validate path components Dr. David Alan Gilbert (git)
2020-01-06 14:32   ` Daniel P. Berrangé
2019-12-12 16:37 ` [PATCH 039/104] virtiofsd: Plumb fuse_bufvec through to do_write_buf Dr. David Alan Gilbert (git)
2020-01-17 21:01   ` Masayoshi Mizuma
2019-12-12 16:38 ` [PATCH 040/104] virtiofsd: Pass write iov's all the way through Dr. David Alan Gilbert (git)
2020-01-19  8:08   ` Xiao Yang
2020-01-20  8:24     ` Philippe Mathieu-Daudé
2020-01-20 13:28       ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 041/104] virtiofsd: add fuse_mbuf_iter API Dr. David Alan Gilbert (git)
2020-01-16 14:17   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 042/104] virtiofsd: validate input buffer sizes in do_write_buf() Dr. David Alan Gilbert (git)
2020-01-16 14:19   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 043/104] virtiofsd: check input buffer size in fuse_lowlevel.c ops Dr. David Alan Gilbert (git)
2020-01-16 14:25   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 044/104] virtiofsd: prevent ".." escape in lo_do_lookup() Dr. David Alan Gilbert (git)
2020-01-16 14:33   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 045/104] virtiofsd: prevent ".." escape in lo_do_readdir() Dr. David Alan Gilbert (git)
2020-01-16 14:35   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 046/104] virtiofsd: use /proc/self/fd/ O_PATH file descriptor Dr. David Alan Gilbert (git)
2020-01-15 18:09   ` Philippe Mathieu-Daudé
2020-01-17  9:42     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 047/104] virtiofsd: sandbox mount namespace Dr. David Alan Gilbert (git)
2020-01-06 14:36   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 048/104] virtiofsd: move to an empty network namespace Dr. David Alan Gilbert (git)
2020-01-06 14:37   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 049/104] virtiofsd: move to a new pid namespace Dr. David Alan Gilbert (git)
2020-01-06 14:40   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 050/104] virtiofsd: add seccomp whitelist Dr. David Alan Gilbert (git)
2020-01-06 14:56   ` Daniel P. Berrangé
2020-01-06 18:54     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 051/104] virtiofsd: Parse flag FUSE_WRITE_KILL_PRIV Dr. David Alan Gilbert (git)
2020-01-15 12:06   ` Misono Tomohiro
2020-01-15 14:34     ` Dr. David Alan Gilbert
2020-01-16 14:37   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 052/104] virtiofsd: cap-ng helpers Dr. David Alan Gilbert (git)
2020-01-06 14:58   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 053/104] virtiofsd: Drop CAP_FSETID if client asked for it Dr. David Alan Gilbert (git)
2020-01-16  4:41   ` Misono Tomohiro
2020-01-16 15:21   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 054/104] virtiofsd: set maximum RLIMIT_NOFILE limit Dr. David Alan Gilbert (git)
2020-01-06 15:00   ` Daniel P. Berrangé
2020-01-15 17:09   ` Philippe Mathieu-Daudé
2020-01-15 17:38     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 055/104] virtiofsd: fix libfuse information leaks Dr. David Alan Gilbert (git)
2020-01-06 15:01   ` Daniel P. Berrangé
2020-01-15 17:07   ` Philippe Mathieu-Daudé
2019-12-12 16:38 ` [PATCH 056/104] virtiofsd: add security guide document Dr. David Alan Gilbert (git)
2020-01-06 15:03   ` Daniel P. Berrangé
2020-01-06 17:53     ` Dr. David Alan Gilbert
2020-01-07 10:05       ` Daniel P. Berrangé
2020-01-09 17:02         ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 057/104] virtiofsd: add --syslog command-line option Dr. David Alan Gilbert (git)
2020-01-06 15:05   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 058/104] virtiofsd: print log only when priority is high enough Dr. David Alan Gilbert (git)
2020-01-06 15:10   ` Daniel P. Berrangé
2020-01-06 17:05     ` Dr. David Alan Gilbert
2020-01-06 17:20       ` Daniel P. Berrangé
2020-01-06 17:27         ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 059/104] virtiofsd: Add ID to the log with FUSE_LOG_DEBUG level Dr. David Alan Gilbert (git)
2020-01-06 15:18   ` Daniel P. Berrangé
2020-01-06 17:47     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 060/104] virtiofsd: Add timestamp " Dr. David Alan Gilbert (git)
2020-01-07 11:11   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 061/104] virtiofsd: Handle reinit Dr. David Alan Gilbert (git)
2020-01-07 11:12   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 062/104] virtiofsd: Handle hard reboot Dr. David Alan Gilbert (git)
2020-01-07 11:14   ` Daniel P. Berrangé
2020-01-10 15:43     ` Dr. David Alan Gilbert
2020-01-20  6:46   ` Misono Tomohiro
2020-01-22 18:28     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 063/104] virtiofsd: Kill threads when queues are stopped Dr. David Alan Gilbert (git)
2020-01-07 11:16   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 064/104] vhost-user: Print unexpected slave message types Dr. David Alan Gilbert (git)
2020-01-07 11:18   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 065/104] contrib/libvhost-user: Protect slave fd with mutex Dr. David Alan Gilbert (git)
2020-01-07 11:19   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 066/104] virtiofsd: passthrough_ll: add renameat2 support Dr. David Alan Gilbert (git)
2020-01-07 11:21   ` Daniel P. Berrangé
2020-01-10  9:52     ` Dr. David Alan Gilbert
2020-01-13 20:06       ` Dr. David Alan Gilbert
2020-01-14  8:29         ` Daniel P. Berrangé
2020-01-14 10:07           ` Dr. David Alan Gilbert
2020-01-14 10:12             ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 067/104] virtiofsd: passthrough_ll: disable readdirplus on cache=never Dr. David Alan Gilbert (git)
2020-01-07 11:22   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 068/104] virtiofsd: passthrough_ll: control readdirplus Dr. David Alan Gilbert (git)
2020-01-07 11:23   ` Daniel P. Berrangé
2020-01-10 15:04     ` Dr. David Alan Gilbert
2020-01-10 15:13       ` Miklos Szeredi
2020-01-10 15:18         ` Daniel P. Berrangé
2020-01-10 15:30           ` Miklos Szeredi
2020-01-10 15:40             ` Vivek Goyal
2020-01-10 16:00               ` Miklos Szeredi
2019-12-12 16:38 ` [PATCH 069/104] virtiofsd: rename unref_inode() to unref_inode_lolocked() Dr. David Alan Gilbert (git)
2020-01-07 11:23   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 070/104] virtiofsd: fail when parent inode isn't known in lo_do_lookup() Dr. David Alan Gilbert (git)
2020-01-16  7:17   ` Misono Tomohiro
2020-01-20 10:08   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 071/104] virtiofsd: extract root inode init into setup_root() Dr. David Alan Gilbert (git)
2020-01-16  7:20   ` Misono Tomohiro
2020-01-16 15:51     ` Dr. David Alan Gilbert
2020-01-20 10:09   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 072/104] virtiofsd: passthrough_ll: fix refcounting on remove/rename Dr. David Alan Gilbert (git)
2020-01-16 11:56   ` Misono Tomohiro
2020-01-16 16:45     ` Dr. David Alan Gilbert
2020-01-17 10:19       ` Miklos Szeredi
2020-01-17 11:37         ` Dr. David Alan Gilbert
2020-01-17 18:43         ` Dr. David Alan Gilbert
2020-01-20 10:17   ` Sergio Lopez
2020-01-20 10:56     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 073/104] virtiofsd: passthrough_ll: clean up cache related options Dr. David Alan Gilbert (git)
2020-01-07 11:24   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 074/104] virtiofsd: passthrough_ll: use hashtable Dr. David Alan Gilbert (git)
2020-01-07 11:28   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 075/104] virtiofsd: Clean up inodes on destroy Dr. David Alan Gilbert (git)
2020-01-07 11:29   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 076/104] virtiofsd: support nanosecond resolution for file timestamp Dr. David Alan Gilbert (git)
2020-01-07 11:30   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 077/104] virtiofsd: fix error handling in main() Dr. David Alan Gilbert (git)
2020-01-07 11:30   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 078/104] virtiofsd: cleanup allocated resource in se Dr. David Alan Gilbert (git)
2020-01-07 11:34   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 079/104] virtiofsd: fix memory leak on lo.source Dr. David Alan Gilbert (git)
2020-01-07 11:37   ` Daniel P. Berrangé
2020-01-09 17:38     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 080/104] virtiofsd: add helper for lo_data cleanup Dr. David Alan Gilbert (git)
2020-01-07 11:40   ` Daniel P. Berrangé
2020-01-09 17:41     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 081/104] virtiofsd: Prevent multiply running with same vhost_user_socket Dr. David Alan Gilbert (git)
2020-01-07 11:43   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 082/104] virtiofsd: enable PARALLEL_DIROPS during INIT Dr. David Alan Gilbert (git)
2020-01-07 11:44   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 083/104] virtiofsd: fix incorrect error handling in lo_do_lookup Dr. David Alan Gilbert (git)
2020-01-07 11:45   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 084/104] Virtiofsd: fix memory leak on fuse queueinfo Dr. David Alan Gilbert (git)
2020-01-15 11:20   ` Misono Tomohiro
2020-01-15 16:57     ` Dr. David Alan Gilbert
2020-01-16  0:54       ` misono.tomohiro
2020-01-16 12:19         ` Dr. David Alan Gilbert
2020-01-20 10:24   ` Sergio Lopez
2020-01-20 10:54     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 085/104] virtiofsd: Support remote posix locks Dr. David Alan Gilbert (git)
2020-01-15 23:38   ` Masayoshi Mizuma
2020-01-16 13:26     ` Vivek Goyal
2020-01-17  9:27       ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 086/104] virtiofsd: use fuse_lowlevel_is_virtio() in fuse_session_destroy() Dr. David Alan Gilbert (git)
2020-01-07 12:01   ` Daniel P. Berrangé
2020-01-07 13:24     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 087/104] virtiofsd: prevent fv_queue_thread() vs virtio_loop() races Dr. David Alan Gilbert (git)
2020-01-07 12:02   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 088/104] virtiofsd: make lo_release() atomic Dr. David Alan Gilbert (git)
2020-01-07 12:03   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 089/104] virtiofsd: prevent races with lo_dirp_put() Dr. David Alan Gilbert (git)
2020-01-17 13:52   ` Philippe Mathieu-Daudé
2019-12-12 16:38 ` [PATCH 090/104] virtiofsd: rename inode->refcount to inode->nlookup Dr. David Alan Gilbert (git)
2020-01-17 13:54   ` Philippe Mathieu-Daudé
2019-12-12 16:38 ` [PATCH 091/104] libvhost-user: Fix some memtable remap cases Dr. David Alan Gilbert (git)
2020-01-17 13:58   ` Marc-André Lureau
2020-01-20 15:50     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 092/104] virtiofsd: add man page Dr. David Alan Gilbert (git)
2019-12-13 14:33   ` Liam Merwick
2019-12-13 15:26     ` Dr. David Alan Gilbert
2020-01-07 12:13   ` Daniel P. Berrangé
2020-01-09 20:02     ` Dr. David Alan Gilbert
2020-01-10  9:30       ` Daniel P. Berrangé
2020-01-10 11:06         ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 093/104] virtiofsd: introduce inode refcount to prevent use-after-free Dr. David Alan Gilbert (git)
2020-01-16 12:25   ` Misono Tomohiro
2020-01-16 17:21     ` Stefan Hajnoczi
2020-01-16 17:42       ` Dr. David Alan Gilbert
2020-01-17  0:47         ` misono.tomohiro
2020-01-20 10:28   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 094/104] virtiofsd: do not always set FUSE_FLOCK_LOCKS Dr. David Alan Gilbert (git)
2020-01-17  8:50   ` Misono Tomohiro
2020-01-20 10:31   ` Sergio Lopez
2019-12-12 16:38 ` [PATCH 095/104] virtiofsd: convert more fprintf and perror to use fuse log infra Dr. David Alan Gilbert (git)
2020-01-07 12:16   ` Daniel P. Berrangé
2020-01-16 12:29   ` Misono Tomohiro
2020-01-16 16:32     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 096/104] virtiofsd: Reset O_DIRECT flag during file open Dr. David Alan Gilbert (git)
2020-01-07 12:17   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 097/104] virtiofsd: Fix data corruption with O_APPEND wirte in writeback mode Dr. David Alan Gilbert (git)
2020-01-07 12:20   ` Daniel P. Berrangé
2020-01-07 13:27     ` Dr. David Alan Gilbert
2019-12-12 16:38 ` [PATCH 098/104] virtiofsd: add definition of fuse_buf_writev() Dr. David Alan Gilbert (git)
2020-01-07 12:21   ` Daniel P. Berrangé
2019-12-12 16:38 ` [PATCH 099/104] virtiofsd: use fuse_buf_writev to replace fuse_buf_write for better performance Dr. David Alan Gilbert (git)
2020-01-07 12:23   ` Daniel P. Berrangé
2020-01-10 13:15     ` Dr. David Alan Gilbert
2019-12-12 16:39 ` [PATCH 100/104] virtiofsd: process requests in a thread pool Dr. David Alan Gilbert (git)
2020-01-20 12:54   ` Misono Tomohiro
2019-12-12 16:39 ` [PATCH 101/104] virtiofsd: prevent FUSE_INIT/FUSE_DESTROY races Dr. David Alan Gilbert (git)
2020-01-15 23:05   ` Masayoshi Mizuma
2020-01-16 12:24     ` Dr. David Alan Gilbert
2020-01-17 13:40   ` Philippe Mathieu-Daudé
2020-01-17 15:28     ` Dr. David Alan Gilbert
2020-01-17 15:30       ` Philippe Mathieu-Daudé
2019-12-12 16:39 ` [PATCH 102/104] virtiofsd: fix lo_destroy() resource leaks Dr. David Alan Gilbert (git)
2020-01-17 13:43   ` Philippe Mathieu-Daudé
2019-12-12 16:39 ` [PATCH 103/104] virtiofsd: add --thread-pool-size=NUM option Dr. David Alan Gilbert (git)
2020-01-07 12:25   ` Daniel P. Berrangé
2020-01-17 13:35   ` Philippe Mathieu-Daudé
2019-12-12 16:39 ` [PATCH 104/104] virtiofsd: Convert lo_destroy to take the lo->mutex lock itself Dr. David Alan Gilbert (git)
2020-01-17 13:33   ` Philippe Mathieu-Daudé
2019-12-12 18:21 ` [PATCH 000/104] virtiofs daemon [all] no-reply
2020-01-17 11:32 ` Dr. David Alan Gilbert
2020-01-17 13:32 ` [PATCH 105/104] virtiofsd: Unref old/new inodes with the same mutex lock in lo_rename() Philippe Mathieu-Daudé
2020-01-19  8:35   ` Xiao Yang
2020-01-20  8:27     ` Philippe Mathieu-Daudé
2020-01-20 18:52   ` Dr. David Alan Gilbert
2020-01-20 18:55     ` Philippe Mathieu-Daudé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191212163904.159893-6-dgilbert@redhat.com \
    --to=dgilbert@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=vgoyal@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.