All of lore.kernel.org
 help / color / mirror / Atom feed
From: Miklos Szeredi <miklos@szeredi.hu>
To: Anand Avati <avati@redhat.com>
Cc: Ric Wheeler <rwheeler@redhat.com>,
	Al Viro <viro@zeniv.linux.org.uk>,
	Brian Foster <bfoster@redhat.com>,
	David Howells <dhowells@redhat.com>,
	Eric Paris <eparis@redhat.com>,
	Linux-Fsdevel <linux-fsdevel@vger.kernel.org>,
	Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Linux NFS list <linux-nfs@vger.kernel.org>,
	Trond Myklebust <Trond.Myklebust@netapp.com>,
	Steven Whitehouse <swhiteho@redhat.com>,
	"mszeredi@suse.cz" <mszeredi@suse.cz>
Subject: Re: [PATCH 4/4] fuse: drop dentry on failed revalidate
Date: Thu, 8 Aug 2013 16:46:54 +0200	[thread overview]
Message-ID: <CAJfpegsGJHxRyi64QYV+BehR7U_g6Hy00fFHOO_moxF0R=zWig@mail.gmail.com> (raw)
In-Reply-To: <5202764C.2000709@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 959 bytes --]

On Wed, Aug 7, 2013 at 6:31 PM, Anand Avati <avati@redhat.com> wrote:
> Thanks for attaching the thread. Was very educative! I still do not quite
> understand - will umount() still work when inode_permission()[->getattr()]
> on the ancestors fail (with ESTALE etc.)?

Several cases:

1) mountpoint was removed
2) mountpoint's ancestor removed
3) mountpoint or ancestor moved

1) and 3) would only cause revalidate to fail, not inode operations
(permission or getattr) since the inodes of ancestors still exist.

2) could error out if the ->permission got to the server.  I'm not
sure it will and I don't have an NFS setup handy to test.

So it doesn't necessarily work but it can be made to work, and as
Linus pointed out, it might still be the least worst option.

BTW, attaching a little fuse filesystem that I've been testing this
with.  It's read-only, but the point here is that the tree is modified
*externally*, so that's not an issue.

Thanks,
Miklos

[-- Attachment #2: fuse_lo.c --]
[-- Type: text/x-csrc, Size: 8227 bytes --]

/*
  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.
*/

/* gcc -Wall fuse_lo.c `pkg-config fuse --cflags --libs` -o fuse_lo */

#define _GNU_SOURCE
#define FUSE_USE_VERSION 30

#include <fuse_lowlevel.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <err.h>

struct lo_inode {
	struct lo_inode *next;
	struct lo_inode *prev;
	int fd;
	ino_t ino;
	dev_t dev;
	uint64_t nlookup;
};

struct lo_data {
	int debug;
	struct lo_inode root;
};

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_getattr(fuse_req_t req, fuse_ino_t ino,
			     struct fuse_file_info *fi)
{
	int res;
	struct stat buf;

	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, 1.0);
}

static struct lo_inode *lo_find(fuse_req_t req, struct stat *st)
{
	struct lo_data *lo = lo_data(req);
	struct lo_inode *p;

	for (p = lo->root.next; p != &lo->root; p = p->next) {
		if (p->ino == st->st_ino && p->dev == st->st_dev)
			return p;
	}
	return NULL;
}

static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
	int newfd;
	int res;
	int saverr;
	struct lo_inode *inode;
	struct fuse_entry_param e = {
		e.attr_timeout = 1.0,
		e.entry_timeout = 1.0,
	};

	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(req, &e.attr);
	if (inode) {
		close(newfd);
		newfd = -1;
	} else {
		struct lo_inode *prev = &lo_data(req)->root;
		struct lo_inode *next = prev->next;
		saverr = ENOMEM;
		inode = calloc(1, sizeof(struct lo_inode));
		if (!inode)
			goto out_err;

		inode->fd = newfd;
		inode->ino = e.attr.st_ino;
		inode->dev = e.attr.st_dev;

		next->prev = inode;
		inode->next = next;
		inode->prev = prev;
		prev->next = inode;
	}
	inode->nlookup++;
	e.ino = (uintptr_t) inode;

	if (lo_debug(req))
		fprintf(stderr, "  %lli/%s -> %lli\n",
			(unsigned long long) parent, name, (unsigned long long) e.ino);

	fuse_reply_entry(req, &e);
	return;

out_err:
	saverr = errno;
	if (newfd != -1)
		close(newfd);
	fuse_reply_err(req, saverr);
}

static void lo_free(struct lo_inode *inode)
{
	struct lo_inode *prev = inode->prev;
	struct lo_inode *next = inode->next;

	next->prev = prev;
	prev->next = next;
	close(inode->fd);
	free(inode);
}

static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
	struct lo_inode *inode = lo_inode(req, ino);

	if (lo_debug(req)) {
		fprintf(stderr, "  forget %lli %lli -%lli\n",
			(unsigned long long) ino, (unsigned long long) inode->nlookup,
			(unsigned long long) nlookup);
	}

	assert(inode->nlookup >= nlookup);
	inode->nlookup -= nlookup;

	if (!inode->nlookup)
		lo_free(inode);

	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 fd = -1;
	int error = ENOMEM;
	struct lo_dirp *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;
	fuse_reply_open(req, fi);
	return;

out_errno:
	error = errno;
out_err:
	free(d);
	if (fd != -1)
		close(fd);
	fuse_reply_err(req, error);
}

static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
		       struct fuse_file_info *fi)
{
	struct lo_dirp *d = lo_dirp(fi);
	char *buf;
	char *p;
	size_t rem;

	(void) ino;

	buf = calloc(size, 1);
	if (!buf)
		return (void) fuse_reply_err(req, ENOMEM);

	if (offset != d->offset) {
		seekdir(d->dp, offset);
		d->entry = NULL;
		d->offset = offset;
	}
	p = buf;
	rem = size;
	while (1) {
		size_t entsize;
		struct stat st;
		off_t nextoff;

		if (!d->entry) {
			errno = 0;
			d->entry = readdir(d->dp);
			if (!d->entry) {
				if (errno && rem == size) {
					int saverr = errno;
					free(buf);
					return (void) fuse_reply_err(req, saverr);
				}

				break;
			}
		}

		memset(&st, 0, sizeof(st));
		st.st_ino = d->entry->d_ino;
		st.st_mode = d->entry->d_type << 12;
		nextoff = telldir(d->dp);

		entsize = fuse_add_direntry(req, p, rem, d->entry->d_name, &st, nextoff);
		if (entsize > rem)
			break;

		p += entsize;
		rem -= entsize;

		d->entry = NULL;
		d->offset = nextoff;
	}

	fuse_reply_buf(req, buf, size - rem);
	free(buf);
}

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_open(fuse_req_t req, fuse_ino_t ino,
			  struct fuse_file_info *fi)
{
	int fd;
	char buf[64];

	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;
	fuse_reply_open(req, fi);
}

static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
	close(fi->fh);
	fuse_reply_err(req, 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);

	(void) ino;

	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 struct fuse_lowlevel_ops lo_oper = {
	.lookup		= lo_lookup,
	.forget		= lo_forget,
	.getattr	= lo_getattr,
	.readlink	= lo_readlink,
	.opendir	= lo_opendir,
	.readdir	= lo_readdir,
	.releasedir	= lo_releasedir,
	.open		= lo_open,
	.release	= lo_release,
	.read		= lo_read,
};

#define LO_OPT(t, p, v) { t, offsetof(struct lo_data, p), v }

static const struct fuse_opt lo_opts[] = {
	FUSE_OPT_KEY("debug",		      FUSE_OPT_KEY_KEEP),
	FUSE_OPT_KEY("-d",		      FUSE_OPT_KEY_KEEP),
	LO_OPT("debug",		      debug, 1),
	LO_OPT("-d",		      debug, 1),
	FUSE_OPT_END
};

int main(int argc, char *argv[])
{
	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
	struct fuse_chan *ch;
	char *mountpoint;
	int ret = -1;
	struct lo_data lo = { };

	if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1)
		exit(1);
	lo.root.next = lo.root.prev = &lo.root;
	lo.root.fd = open("/", O_PATH);
	lo.root.nlookup = 2;
	if (lo.root.fd == -1)
		err(1, "open(\"/\", O_PATH)");

	if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 &&
	    (ch = fuse_mount(mountpoint, &args)) != NULL) {
		struct fuse_session *se;
		se = fuse_lowlevel_new(&args, &lo_oper, sizeof(lo_oper), &lo);
		if (se != NULL) {
			if (fuse_set_signal_handlers(se) != -1) {
				fuse_session_add_chan(se, ch);
				ret = fuse_session_loop(se);
				fuse_remove_signal_handlers(se);
				fuse_session_remove_chan(ch);
			}
			fuse_session_destroy(se);
		}
		fuse_unmount(mountpoint, ch);
		free(mountpoint);
	}
	fuse_opt_free_args(&args);

	while (lo.root.next != &lo.root)
		lo_free(lo.root.next);

	return ret ? 1 : 0;
}

WARNING: multiple messages have this Message-ID (diff)
From: Miklos Szeredi <miklos-sUDqSbJrdHQHWmgEVkV9KA@public.gmane.org>
To: Anand Avati <avati-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Ric Wheeler <rwheeler-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	Al Viro <viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn@public.gmane.org>,
	Brian Foster <bfoster-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	Eric Paris <eparis-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	Linux-Fsdevel
	<linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Kernel Mailing List
	<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Linux NFS list
	<linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Trond Myklebust
	<Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org>,
	Steven Whitehouse
	<swhiteho-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	"mszeredi-AlSwsSmVLrQ@public.gmane.org"
	<mszeredi-AlSwsSmVLrQ@public.gmane.org>
Subject: Re: [PATCH 4/4] fuse: drop dentry on failed revalidate
Date: Thu, 8 Aug 2013 16:46:54 +0200	[thread overview]
Message-ID: <CAJfpegsGJHxRyi64QYV+BehR7U_g6Hy00fFHOO_moxF0R=zWig@mail.gmail.com> (raw)
In-Reply-To: <5202764C.2000709-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 988 bytes --]

On Wed, Aug 7, 2013 at 6:31 PM, Anand Avati <avati-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> Thanks for attaching the thread. Was very educative! I still do not quite
> understand - will umount() still work when inode_permission()[->getattr()]
> on the ancestors fail (with ESTALE etc.)?

Several cases:

1) mountpoint was removed
2) mountpoint's ancestor removed
3) mountpoint or ancestor moved

1) and 3) would only cause revalidate to fail, not inode operations
(permission or getattr) since the inodes of ancestors still exist.

2) could error out if the ->permission got to the server.  I'm not
sure it will and I don't have an NFS setup handy to test.

So it doesn't necessarily work but it can be made to work, and as
Linus pointed out, it might still be the least worst option.

BTW, attaching a little fuse filesystem that I've been testing this
with.  It's read-only, but the point here is that the tree is modified
*externally*, so that's not an issue.

Thanks,
Miklos

[-- Attachment #2: fuse_lo.c --]
[-- Type: text/x-csrc, Size: 8227 bytes --]

/*
  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.
*/

/* gcc -Wall fuse_lo.c `pkg-config fuse --cflags --libs` -o fuse_lo */

#define _GNU_SOURCE
#define FUSE_USE_VERSION 30

#include <fuse_lowlevel.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <dirent.h>
#include <assert.h>
#include <errno.h>
#include <err.h>

struct lo_inode {
	struct lo_inode *next;
	struct lo_inode *prev;
	int fd;
	ino_t ino;
	dev_t dev;
	uint64_t nlookup;
};

struct lo_data {
	int debug;
	struct lo_inode root;
};

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_getattr(fuse_req_t req, fuse_ino_t ino,
			     struct fuse_file_info *fi)
{
	int res;
	struct stat buf;

	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, 1.0);
}

static struct lo_inode *lo_find(fuse_req_t req, struct stat *st)
{
	struct lo_data *lo = lo_data(req);
	struct lo_inode *p;

	for (p = lo->root.next; p != &lo->root; p = p->next) {
		if (p->ino == st->st_ino && p->dev == st->st_dev)
			return p;
	}
	return NULL;
}

static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
	int newfd;
	int res;
	int saverr;
	struct lo_inode *inode;
	struct fuse_entry_param e = {
		e.attr_timeout = 1.0,
		e.entry_timeout = 1.0,
	};

	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(req, &e.attr);
	if (inode) {
		close(newfd);
		newfd = -1;
	} else {
		struct lo_inode *prev = &lo_data(req)->root;
		struct lo_inode *next = prev->next;
		saverr = ENOMEM;
		inode = calloc(1, sizeof(struct lo_inode));
		if (!inode)
			goto out_err;

		inode->fd = newfd;
		inode->ino = e.attr.st_ino;
		inode->dev = e.attr.st_dev;

		next->prev = inode;
		inode->next = next;
		inode->prev = prev;
		prev->next = inode;
	}
	inode->nlookup++;
	e.ino = (uintptr_t) inode;

	if (lo_debug(req))
		fprintf(stderr, "  %lli/%s -> %lli\n",
			(unsigned long long) parent, name, (unsigned long long) e.ino);

	fuse_reply_entry(req, &e);
	return;

out_err:
	saverr = errno;
	if (newfd != -1)
		close(newfd);
	fuse_reply_err(req, saverr);
}

static void lo_free(struct lo_inode *inode)
{
	struct lo_inode *prev = inode->prev;
	struct lo_inode *next = inode->next;

	next->prev = prev;
	prev->next = next;
	close(inode->fd);
	free(inode);
}

static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
{
	struct lo_inode *inode = lo_inode(req, ino);

	if (lo_debug(req)) {
		fprintf(stderr, "  forget %lli %lli -%lli\n",
			(unsigned long long) ino, (unsigned long long) inode->nlookup,
			(unsigned long long) nlookup);
	}

	assert(inode->nlookup >= nlookup);
	inode->nlookup -= nlookup;

	if (!inode->nlookup)
		lo_free(inode);

	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 fd = -1;
	int error = ENOMEM;
	struct lo_dirp *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;
	fuse_reply_open(req, fi);
	return;

out_errno:
	error = errno;
out_err:
	free(d);
	if (fd != -1)
		close(fd);
	fuse_reply_err(req, error);
}

static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset,
		       struct fuse_file_info *fi)
{
	struct lo_dirp *d = lo_dirp(fi);
	char *buf;
	char *p;
	size_t rem;

	(void) ino;

	buf = calloc(size, 1);
	if (!buf)
		return (void) fuse_reply_err(req, ENOMEM);

	if (offset != d->offset) {
		seekdir(d->dp, offset);
		d->entry = NULL;
		d->offset = offset;
	}
	p = buf;
	rem = size;
	while (1) {
		size_t entsize;
		struct stat st;
		off_t nextoff;

		if (!d->entry) {
			errno = 0;
			d->entry = readdir(d->dp);
			if (!d->entry) {
				if (errno && rem == size) {
					int saverr = errno;
					free(buf);
					return (void) fuse_reply_err(req, saverr);
				}

				break;
			}
		}

		memset(&st, 0, sizeof(st));
		st.st_ino = d->entry->d_ino;
		st.st_mode = d->entry->d_type << 12;
		nextoff = telldir(d->dp);

		entsize = fuse_add_direntry(req, p, rem, d->entry->d_name, &st, nextoff);
		if (entsize > rem)
			break;

		p += entsize;
		rem -= entsize;

		d->entry = NULL;
		d->offset = nextoff;
	}

	fuse_reply_buf(req, buf, size - rem);
	free(buf);
}

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_open(fuse_req_t req, fuse_ino_t ino,
			  struct fuse_file_info *fi)
{
	int fd;
	char buf[64];

	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;
	fuse_reply_open(req, fi);
}

static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
	close(fi->fh);
	fuse_reply_err(req, 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);

	(void) ino;

	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 struct fuse_lowlevel_ops lo_oper = {
	.lookup		= lo_lookup,
	.forget		= lo_forget,
	.getattr	= lo_getattr,
	.readlink	= lo_readlink,
	.opendir	= lo_opendir,
	.readdir	= lo_readdir,
	.releasedir	= lo_releasedir,
	.open		= lo_open,
	.release	= lo_release,
	.read		= lo_read,
};

#define LO_OPT(t, p, v) { t, offsetof(struct lo_data, p), v }

static const struct fuse_opt lo_opts[] = {
	FUSE_OPT_KEY("debug",		      FUSE_OPT_KEY_KEEP),
	FUSE_OPT_KEY("-d",		      FUSE_OPT_KEY_KEEP),
	LO_OPT("debug",		      debug, 1),
	LO_OPT("-d",		      debug, 1),
	FUSE_OPT_END
};

int main(int argc, char *argv[])
{
	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
	struct fuse_chan *ch;
	char *mountpoint;
	int ret = -1;
	struct lo_data lo = { };

	if (fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1)
		exit(1);
	lo.root.next = lo.root.prev = &lo.root;
	lo.root.fd = open("/", O_PATH);
	lo.root.nlookup = 2;
	if (lo.root.fd == -1)
		err(1, "open(\"/\", O_PATH)");

	if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 &&
	    (ch = fuse_mount(mountpoint, &args)) != NULL) {
		struct fuse_session *se;
		se = fuse_lowlevel_new(&args, &lo_oper, sizeof(lo_oper), &lo);
		if (se != NULL) {
			if (fuse_set_signal_handlers(se) != -1) {
				fuse_session_add_chan(se, ch);
				ret = fuse_session_loop(se);
				fuse_remove_signal_handlers(se);
				fuse_session_remove_chan(ch);
			}
			fuse_session_destroy(se);
		}
		fuse_unmount(mountpoint, ch);
		free(mountpoint);
	}
	fuse_opt_free_args(&args);

	while (lo.root.next != &lo.root)
		lo_free(lo.root.next);

	return ret ? 1 : 0;
}

  reply	other threads:[~2013-08-08 14:53 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-06 14:29 [PATCH 0/4] [RFC] safely drop directory dentry on failed revalidate Miklos Szeredi
2013-08-06 14:29 ` Miklos Szeredi
2013-08-06 14:30 ` [PATCH 1/4] vfs: check submounts and drop atomically Miklos Szeredi
2013-08-06 14:30 ` [PATCH 2/4] vfs: check unlinked ancestors before mount Miklos Szeredi
2013-08-06 14:30   ` Miklos Szeredi
2013-08-06 16:08   ` Miklos Szeredi
2013-08-06 14:30 ` [PATCH 3/4] fuse: use d_materialise_unique() Miklos Szeredi
2013-08-06 14:30 ` [PATCH 4/4] fuse: drop dentry on failed revalidate Miklos Szeredi
2013-08-06 14:30   ` Miklos Szeredi
2013-08-06 20:06   ` Anand Avati
2013-08-07 15:44     ` Miklos Szeredi
2013-08-07 15:44       ` Miklos Szeredi
2013-08-07 16:31       ` Anand Avati
2013-08-07 16:31         ` Anand Avati
2013-08-08 14:46         ` Miklos Szeredi [this message]
2013-08-08 14:46           ` Miklos Szeredi

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='CAJfpegsGJHxRyi64QYV+BehR7U_g6Hy00fFHOO_moxF0R=zWig@mail.gmail.com' \
    --to=miklos@szeredi.hu \
    --cc=Trond.Myklebust@netapp.com \
    --cc=avati@redhat.com \
    --cc=bfoster@redhat.com \
    --cc=dhowells@redhat.com \
    --cc=eparis@redhat.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=mszeredi@suse.cz \
    --cc=rwheeler@redhat.com \
    --cc=swhiteho@redhat.com \
    --cc=viro@zeniv.linux.org.uk \
    /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.