Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Fuse (and sshfs) support for OpenBSD

196 views
Skip to first unread message

Sylvestre Gallon

unread,
Mar 5, 2013, 7:43:24 AM3/5/13
to
Hi tech@

I send you this mail because a few months ago I tried to dabble with fuse
filesystem and OpenBSD. After some time working on this subject I have
succeeded to create something that works. It is not even near to be perfect
but with some changes and adaptions I think it could do the job.

In order to use these patches you will need to follow this procedure:

* apply the ports patch :
root # cd /usr/ports
root # ftp http://www.pmbsd.org/patch-fuse-ports
root # patch -p0 < patch-fuse-ports

* apply the src patch
root # cd /usr/src
root # ftp http://www.pmbsd.org/patch-fuse-src
root # patch -p0 < patch-fuse-src

* upgrade your system mount.h
root # cp /usr/src/sys/sys/mount.h /usr/include/sys/mount.h

* compile all mount and umount binaries
root # cd /usr/src/sbin/mount && make && make install
root # cd /usr/src/sbin/mount_ffs && make && make install
root # cd /usr/src/sbin/mount_fusefs && make && make install (there are
warning for a missing manpage)
...
root # cd /usr/src/sbin/umount && make && make install

* build a new kernel
root # cd /usr/src/sys/arch/i386/conf
root # config GENERIC
root # cd ../compile/GENERIC
root # make && make install

* update MAKEDEV script and launch it to create the fuse device
root # cd /dev
root # ftp http://www.pmbsd.org/patch-fuse-MAKEDEV
root # patch MAKEDEV < patch-fuse-MAKEDEV
root # ./MAKEDEV
root # ./MAKEDEV fuse

* install devel/fuse and sysutils/sshfs-fuse packages
root # cd /usr/ports/devel/fuse && make && make install
root # cd /usr/ports/sysutils/sshfs-fuse && make && make install

* reboot and try sshfs
root # reboot
root # sshfs s...@pmbsd.org:/home/syl/code /mnt
root # ls /mnt


As I said before, this is not perfect... There are some outstanding
features to implement and bugs or architectural mistakes to solve...

There is some work to do to implement these missing vnops and vfs features :

* vptof
* fhtovp
* checkexp
* sysctl
* strategy
* fsync
* symlink
* rename vnop
* you could only mount one filesystem at once.

I think some security improvement could be done on these patches like :
- fix some panics and tsleep hole that could produce DoS...
- allow the use of fuse with a securelevel equal to -1...
- other security stuff that I'm surely missing :)

I will not explain all the fuse protocol in this mail but if you want
information on how it works I will answer your questions in a private mail.

If you have any questions about these patches or want me to change or
rework something in this code I will be happy to do it.

Thanks for your time,

Cheers,

--
Sylvestre Gallon

Antoine Jacoutot

unread,
Mar 5, 2013, 7:49:20 AM3/5/13
to
On Tue, Mar 05, 2013 at 01:43:24PM +0100, Sylvestre Gallon wrote:
> Hi tech@
>
> I send you this mail because a few months ago I tried to dabble with fuse
> filesystem and OpenBSD. After some time working on this subject I have
> succeeded to create something that works. It is not even near to be perfect
> but with some changes and adaptions I think it could do the job.

Before anyone flame you for whatever reason, let me say that I am *very* happy that some work in done in this area.
I'll try and play with this and see what comes out of it; may take a little bit of time though.
--
Antoine

Gilles Chehade

unread,
Mar 5, 2013, 8:11:41 AM3/5/13
to
On Tue, Mar 05, 2013 at 01:49:20PM +0100, Antoine Jacoutot wrote:
> On Tue, Mar 05, 2013 at 01:43:24PM +0100, Sylvestre Gallon wrote:
> > Hi tech@
> >
> > I send you this mail because a few months ago I tried to dabble with fuse
> > filesystem and OpenBSD. After some time working on this subject I have
> > succeeded to create something that works. It is not even near to be perfect
> > but with some changes and adaptions I think it could do the job.
>
> Before anyone flame you for whatever reason, let me say that I am *very* happy that some work in done in this area.
> I'll try and play with this and see what comes out of it; may take a little bit of time though.
>

Yup, same here

--
Gilles Chehade

https://www.poolp.org @poolpOrg

Bob Beck

unread,
Mar 5, 2013, 8:44:59 AM3/5/13
to
Sylvestre, one of the problems with fuse itself is that it's GPL
licensed, and not appropriate
for inclusion in base. If you've got interets and talent in this area,
you might want to consider
having a peek at puffs (and refuse) from netbsd which has a workable
license and could
be included in base. I would definitely help if you're interested...

-Bob


On Tue, Mar 5, 2013 at 5:43 AM, Sylvestre Gallon <ccna...@gmail.com> wrote:
> Hi tech@
>
> I send you this mail because a few months ago I tried to dabble with fuse
> filesystem and OpenBSD. After some time working on this subject I have
> succeeded to create something that works. It is not even near to be perfect
> but with some changes and adaptions I think it could do the job.
>

Jiri B

unread,
Mar 5, 2013, 9:10:47 AM3/5/13
to
On Tue, Mar 05, 2013 at 02:11:41PM +0100, Gilles Chehade wrote:
> On Tue, Mar 05, 2013 at 01:49:20PM +0100, Antoine Jacoutot wrote:
> > On Tue, Mar 05, 2013 at 01:43:24PM +0100, Sylvestre Gallon wrote:
> > > Hi tech@
> > >
> > > I send you this mail because a few months ago I tried to dabble with fuse
> > > filesystem and OpenBSD. After some time working on this subject I have
> > > succeeded to create something that works. It is not even near to be perfect
> > > but with some changes and adaptions I think it could do the job.
> >
> > Before anyone flame you for whatever reason, let me say that I am *very* happy that some work in done in this area.
> > I'll try and play with this and see what comes out of it; may take a little bit of time though.
> >
>
> Yup, same here

Yes, it would be nice to have libguestfs which uses FUSE
working on OpenBSD so one could modify qemu/kvm OpenBSD images
directly ;)

jirib

Martin Pieuchot

unread,
Mar 5, 2013, 9:12:13 AM3/5/13
to
On 05/03/13(Tue) 06:44, Bob Beck wrote:
> Sylvestre, one of the problems with fuse itself is that it's GPL
> licensed, and not appropriate for inclusion in base. If you've got
> interets and talent in this area, you might want to consider
> having a peek at puffs (and refuse) from netbsd which has a workable
> license and could be included in base.
> I would definitely help if you're interested...

It looks to me that Sylvestre wrote it's own ISC-licensed implementation.

Sylvestre that's a lot of work, and a lot of new code :) I'd suggest you
to send your diff inline (maybe splitting the userland and kernel parts)
so that people can comment on them.

M.

Sylvestre Gallon

unread,
Mar 5, 2013, 9:24:06 AM3/5/13
to
On Tue, Mar 5, 2013 at 2:44 PM, Bob Beck <be...@openbsd.org> wrote:

> Sylvestre, one of the problems with fuse itself is that it's GPL
> licensed, and not appropriate
> for inclusion in base. If you've got interets and talent in this area,
> you might want to consider
> having a peek at puffs (and refuse) from netbsd which has a workable
> license and could
> be included in base. I would definitely help if you're interested...
>
> -Bob
>
>
Bob,

I am not quite sure but I think that only libfuse and sshfs are GPL
licenced. The patches for those two items are only present in ports.

All the code present in src is ISC licenced. The kernel communicate with
libfuse througth a device (ie /dev/fuse) and only share a header with the
libfuse (fuse_kernel.h) which is BSD licenced. FreeBSD used the same way to
implement it. (I do not know if it is a good example)

Anyway, It could be fun to have a peek at puffs/refuse and have your help :)

Cheers,

--
Sylvestre Gallon

Sylvestre Gallon

unread,
Mar 5, 2013, 10:29:52 AM3/5/13
to
On Tue, Mar 5, 2013 at 3:12 PM, Martin Pieuchot <mpie...@nolizard.org> wrote:
> It looks to me that Sylvestre wrote it's own ISC-licensed implementation.
>
> Sylvestre that's a lot of work, and a lot of new code :) I'd suggest you
> to send your diff inline (maybe splitting the userland and kernel parts)
> so that people can comment on them.
>
> M.

Martin,

You will find inline the kernel patch

Index: arch/i386/i386/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/conf.c,v
retrieving revision 1.141
diff -u -p -u -p -r1.141 conf.c
--- arch/i386/i386/conf.c 23 Aug 2012 06:12:49 -0000 1.141
+++ arch/i386/i386/conf.c 5 Mar 2013 15:16:08 -0000
@@ -185,6 +185,7 @@ cdev_decl(pci);
#include "amdmsr.h"
#include "vscsi.h"
#include "pppx.h"
+#include "fuse.h"

struct cdevsw cdevsw[] =
{
@@ -293,6 +294,7 @@ struct cdevsw cdevsw[] =
cdev_vscsi_init(NVSCSI,vscsi), /* 90: vscsi */
cdev_disk_init(1,diskmap), /* 91: disk mapper */
cdev_pppx_init(NPPPX,pppx), /* 92: pppx */
+ cdev_fuse_init(NFUSE, fuse), /* 93: fuse */
};
int nchrdev = nitems(cdevsw);

Index: conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/conf/GENERIC,v
retrieving revision 1.194
diff -u -p -u -p -r1.194 GENERIC
--- conf/GENERIC 1 Mar 2013 21:06:04 -0000 1.194
+++ conf/GENERIC 5 Mar 2013 15:16:08 -0000
@@ -45,6 +45,7 @@ option NFSSERVER # Network File System
option CD9660 # ISO 9660 + Rock Ridge file system
option UDF # UDF (DVD) file system
option MSDOSFS # MS-DOS file system
+option FUSE # Userland file system
option FIFO # FIFOs; RECOMMENDED

option SOCKET_SPLICE # Socket Splicing for TCP
@@ -73,6 +74,8 @@ scsibus* at softraid?

vscsi0 at root # Userland backed Virtual SCSI
scsibus* at vscsi?
+
+pseudo-device fuse # filesystem in user land

pseudo-device pf # packet filter
pseudo-device pflog # pf log if
Index: conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.540
diff -u -p -u -p -r1.540 files
--- conf/files 21 Jan 2013 11:17:48 -0000 1.540
+++ conf/files 5 Mar 2013 15:16:09 -0000
@@ -544,6 +544,15 @@ pseudo-device systrace
pseudo-device ksyms
file dev/ksyms.c ksyms needs-flag

+pseudo-device fuse
+file miscfs/fuse/fuse_device.c fuse needs-flag
+file miscfs/fuse/fuse_file.c fuse
+file miscfs/fuse/fuse_lookup.c fuse
+file miscfs/fuse/fuse_node.c fuse
+file miscfs/fuse/fuse_vfsops.c fuse
+file miscfs/fuse/fuse_vnops.c fuse
+file miscfs/fuse/fuse_subr.c fuse
+
pseudo-device pf: ifnet
file net/pf.c pf needs-flag
file net/pf_norm.c pf
Index: kern/vfs_init.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_init.c,v
retrieving revision 1.30
diff -u -p -u -p -r1.30 vfs_init.c
--- kern/vfs_init.c 23 Aug 2012 06:12:49 -0000 1.30
+++ kern/vfs_init.c 5 Mar 2013 15:16:09 -0000
@@ -85,6 +85,10 @@ extern const struct vfsops ntfs_vfsops;
extern const struct vfsops udf_vfsops;
#endif

+#ifdef FUSE
+extern const struct vfsops fusefs_vfsops;
+#endif
+
/* Set up the filesystem operations for vnodes. */
static struct vfsconf vfsconflist[] = {
#ifdef FFS
@@ -121,6 +125,10 @@ static struct vfsconf vfsconflist[] = {

#ifdef UDF
{ &udf_vfsops, MOUNT_UDF, 13, 0, MNT_LOCAL, NULL },
+#endif
+
+#ifdef FUSE
+ { &fusefs_vfsops, MOUNT_FUSEFS, 42, 0, MNT_LOCAL, NULL }, /* put
42 as type, I don't know witch number I can use*/
#endif
};

Index: miscfs/fuse/fuse_device.c
===================================================================
RCS file: miscfs/fuse/fuse_device.c
diff -N miscfs/fuse/fuse_device.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_device.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+struct fuse_dev {
+ int opened;
+ int end;
+};
+
+#define FUSE_OPEN 1
+#define FUSE_CLOSE 0
+#define FUSE_DONE 2
+
+static struct fuse_dev *fuse_devs[MAX_FUSE_DEV];
+
+void fuseattach(int);
+int fuseopen(dev_t, int, int, struct proc *);
+int fuseclose(dev_t, int, int, struct proc *);
+int fuseioctl(dev_t, u_long, caddr_t, int, struct proc *);
+int fuseread(dev_t, struct uio *, int);
+int fusewrite(dev_t, struct uio *, int);
+int fusepoll(dev_t, int, struct proc *);
+
+struct fuse_msg_head fmq_in;
+struct fuse_msg_head fmq_wait;
+
+#ifdef FUSE_DEV_DEBUG
+static void
+dump_buff(char *buff, int len)
+{
+ char text[17];
+ int i;
+
+ bzero(text, 17);
+ for (i = 0; i < len ; i++) {
+
+ if (i != 0 && (i % 16) == 0) {
+ printf(": %s\n", text);
+ bzero(text, 17);
+ }
+
+ printf("%.2x ", buff[i] & 0xff);
+
+ if (buff[i] > ' ' && buff[i] < '~')
+ text[i%16] = buff[i] & 0xff;
+ else
+ text[i%16] = '.';
+ }
+
+ if ((i % 16) != 0) {
+ while ((i % 16) != 0) {
+ printf(" ");
+ i++;
+ }
+ }
+ printf(": %s\n", text);
+}
+#endif
+
+void
+fuseattach(int num)
+{
+#ifdef FUSE_DEV_DEBUG
+ printf("fuse0 at root\n");
+#endif
+}
+
+int
+fuseopen(dev_t dev, int flags, int fmt, struct proc * p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV &&
+ fuse_devs[minor(dev)]->opened != FUSE_CLOSE)
+ return (ENXIO);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("open dev %i\n", minor(dev));
+#endif
+
+ fuse_devs[minor(dev)] = malloc(sizeof(*fuse_devs[minor(dev)]),
+ M_FUSEFS, M_WAITOK | M_ZERO);
+ fuse_devs[minor(dev)]->opened = FUSE_OPEN;
+
+ return (0);
+}
+
+int
+fuseclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV)
+ return (ENXIO);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("close dev %i\n", minor(dev));
+#endif
+
+ fuse_devs[minor(dev)]->opened = FUSE_CLOSE;
+ free(fuse_devs[minor(dev)], M_FUSEFS);
+ fuse_devs[minor(dev)] = NULL;
+ return (0);
+}
+
+int
+fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+{
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ printf("bad ioctl number %d\n", cmd);
+ return ENODEV;
+ }
+
+ return error;
+}
+
+int
+fuseread(dev_t dev, struct uio *uio, int ioflag)
+{
+ int error = 0;
+ struct fuse_msg *msg;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("read 0x%x\n", dev);
+#endif
+
+ if (fuse_devs[minor(dev)]->opened != FUSE_OPEN) {
+ return ENODEV;
+ }
+
+again:
+ if (TAILQ_EMPTY(&fmq_in)) {
+
+ if (ioflag & O_NONBLOCK) {
+ return (EAGAIN);
+ }
+
+ error = tsleep(&fmq_in, PWAIT, "fuse read", 0);
+
+ if (error)
+ return error;
+ }
+ if (TAILQ_EMPTY(&fmq_in))
+ goto again;
+
+ if (!TAILQ_EMPTY(&fmq_in)) {
+ msg = TAILQ_FIRST(&fmq_in);
+
+ if (msg->hdr->opcode == FUSE_DESTROY) {
+#ifdef FUSE_DEV_DEBUG
+ printf("catch done\n");
+#endif
+ fuse_devs[minor(dev)]->opened = FUSE_DONE;
+ }
+
+ error = uiomove(msg->hdr, sizeof(struct fuse_in_header), uio);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("hdr r:\n");
+ dump_buff((char *)msg->hdr, sizeof(struct fuse_in_header));
+#endif
+
+ if (msg->len > 0) {
+ error = uiomove(msg->data, msg->len, uio);
+#ifdef FUSE_DEV_DEBUG
+ printf("data r:\n");
+ dump_buff(msg->data, msg->len);
+#endif
+ }
+
+#ifdef FUSE_DEV_DEBUG
+ printf("msg send : %i\n", msg->len);
+#endif
+
+ if (error)
+ return error;
+
+ /*
+ * msg moves from a tailq to another
+ */
+ TAILQ_REMOVE(&fmq_in, msg, node);
+ TAILQ_INSERT_TAIL(&fmq_wait, msg, node);
+ }
+
+ return error;
+}
+
+int
+fusewrite(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct fuse_out_header hdr;
+ struct fuse_msg *msg;
+ int error = 0;
+ int catched = 0;
+ int len;
+ void *data;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("write %x bytes\n", uio->uio_resid);
+#endif
+
+ if (uio->uio_resid < sizeof(struct fuse_out_header)) {
+ printf("uio goes wrong\n");
+ return (EINVAL);
+ }
+
+ /*
+ * get out header
+ */
+
+ if ((error = uiomove(&hdr, sizeof(struct fuse_out_header), uio)) != 0){
+ printf("uiomove failed\n");
+ return (error);
+ }
+#ifdef FUSE_DEV_DEBUG
+ printf("hdr w:\n");
+ dump_buff((char *)&hdr, sizeof(struct fuse_out_header));
+#endif
+ /*
+ * check header validity
+ */
+ if (uio->uio_resid + sizeof(struct fuse_out_header) != hdr.len ||
+ (uio->uio_resid && hdr.error) || TAILQ_EMPTY(&fmq_wait) ) {
+ printf("corrupted fuse header or queue empty\n");
+ return (EINVAL);
+ }
+
+ /* fuse errno are negative */
+ if (hdr.error)
+ hdr.error = -(hdr.error);
+
+ TAILQ_FOREACH(msg, &fmq_wait, node) {
+ if (msg->hdr->unique == hdr.unique) {
+#ifdef FUSE_DEV_DEBUG
+ printf("catch unique %i\n", msg->hdr->unique);
+#endif
+ catched = 1;
+ break;
+ }
+ }
+
+ if (catched) {
+ if (uio->uio_resid > 0) {
+ len = uio->uio_resid;
+ data = malloc(len, M_FUSEFS, M_WAITOK);
+ error = uiomove(data, len, uio);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("data w:\n");
+ dump_buff(data, len);
+#endif
+
+ } else {
+ data = NULL;
+ }
+
+#ifdef FUSE_DEV_DEBUG
+ printf("call callback\n");
+#endif
+
+ if (!error)
+ msg->cb(msg, &hdr, data);
+
+ TAILQ_REMOVE(&fmq_wait, msg, node);
+
+ if (msg->type == msg_buff_async) {
+ free(msg->hdr, M_FUSEFS);
+ free(msg, M_FUSEFS);
+
+ if (data)
+ free(data, M_FUSEFS);
+ }
+
+ } else {
+ error = EINVAL;
+ }
+
+ return error;
+}
+
+int
+fusepoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("fuse poll\n");
+#endif
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (!TAILQ_EMPTY(&fmq_in))
+ revents |= events & (POLLIN | POLLRDNORM);
+ }
+
+ if (events & (POLLOUT | POLLWRNORM))
+ revents |= events & (POLLOUT | POLLWRNORM);
+
+ return (revents);
+}
Index: miscfs/fuse/fuse_file.c
===================================================================
RCS file: miscfs/fuse/fuse_file.c
diff -N miscfs/fuse/fuse_file.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_file.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+int
+fuse_file_open(struct fuse_mnt *fmp, struct fuse_node *ip,
+ enum fufh_type fufh_type, int flags, int isdir)
+{
+ struct fuse_open_out *open_out;
+ struct fuse_open_in open_in;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.data = &open_in;
+ msg.len = sizeof(open_in);
+ msg.cb = &fuse_sync_resp;
+ msg.fmp = fmp;
+ msg.type = msg_buff;
+
+ open_in.flags = flags;
+ open_in.mode = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*open_out);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, ((isdir)?FUSE_OPENDIR:FUSE_OPEN),
+ ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse open", 0);
+
+ if (error)
+ return error;
+
+ open_out = (struct fuse_open_out *)msg.rep.buff.data_rcv;
+
+ ip->fufh[fufh_type].fh_id = open_out->fh;
+ ip->fufh[fufh_type].fh_type = fufh_type;
+
+ free(open_out, M_FUSEFS);
+
+ return 0;
+}
+
+int
+fuse_file_close(struct fuse_mnt *fmp, struct fuse_node * ip,
+ enum fufh_type fufh_type, int flags, int isdir)
+{
+ struct fuse_release_in rel;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ bzero(&rel, sizeof(rel));
+ msg.hdr = &hdr;
+ msg.data = &rel;
+ msg.len = sizeof(rel);
+ msg.cb = &fuse_sync_it;
+ msg.fmp = fmp;
+ msg.type = msg_intr;
+
+ rel.fh = ip->fufh[fufh_type].fh_id;
+ rel.flags = flags;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len,
((isdir)?FUSE_RELEASEDIR:FUSE_RELEASE),
+ ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse close", 0);
+
+ if (error)
+ return error;
+
+ error = msg.rep.it_res;
+ if (error)
+ printf("error %d\n", error);
+
+ ip->fufh[fufh_type].fh_id = (uint64_t)-1;
+ ip->fufh[fufh_type].fh_type = FUFH_INVALID;
+
+ return (error);
+}
Index: miscfs/fuse/fuse_kernel.h
===================================================================
RCS file: miscfs/fuse/fuse_kernel.h
diff -N miscfs/fuse/fuse_kernel.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_kernel.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+#ifndef __FUSE_KERNEL_H__
+#define __FUSE_KERNEL_H__
+
+#define FUSE_KERNEL_VERSION 7
+#define FUSE_KERNEL_MINOR_VERSION 8
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+struct fuse_kstatfs {
+ uint64_t blocks;
+ uint64_t bfree;
+ uint64_t bavail;
+ uint64_t files;
+ uint64_t ffree;
+ uint32_t bsize;
+ uint32_t namelen;
+ uint32_t frsize;
+ uint32_t padding;
+ uint32_t spare[6];
+};
+
+enum fuse_opcode {
+ FUSE_LOOKUP = 1,
+ FUSE_FORGET = 2, /* no reply */
+ FUSE_GETATTR = 3,
+ FUSE_SETATTR = 4,
+ FUSE_READLINK = 5,
+ FUSE_SYMLINK = 6,
+ FUSE_MKNOD = 8,
+ FUSE_MKDIR = 9,
+ FUSE_UNLINK = 10,
+ FUSE_RMDIR = 11,
+ FUSE_RENAME = 12,
+ FUSE_LINK = 13,
+ FUSE_OPEN = 14,
+ FUSE_READ = 15,
+ FUSE_WRITE = 16,
+ FUSE_STATFS = 17,
+ FUSE_RELEASE = 18,
+ FUSE_FSYNC = 20,
+ FUSE_SETXATTR = 21,
+ FUSE_GETXATTR = 22,
+ FUSE_LISTXATTR = 23,
+ FUSE_REMOVEXATTR = 24,
+ FUSE_FLUSH = 25,
+ FUSE_INIT = 26,
+ FUSE_OPENDIR = 27,
+ FUSE_READDIR = 28,
+ FUSE_RELEASEDIR = 29,
+ FUSE_FSYNCDIR = 30,
+ FUSE_GETLK = 31,
+ FUSE_SETLK = 32,
+ FUSE_SETLKW = 33,
+ FUSE_ACCESS = 34,
+ FUSE_CREATE = 35,
+ FUSE_INTERRUPT = 36,
+ FUSE_BMAP = 37,
+ FUSE_DESTROY = 38,
+};
+
+struct fuse_in_header {
+ uint32_t len;
+ uint32_t opcode;
+ uint64_t unique;
+ uint64_t nodeid;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t pid;
+ uint32_t padding;
+};
+
+struct fuse_init_in {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
+};
+
+struct fuse_out_header {
+ uint32_t len;
+ uint32_t error;
+ uint64_t unique;
+};
+
+struct fuse_init_out {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
+ uint32_t unused;
+ uint32_t max_write;
+};
+
+struct fuse_statfs_out {
+ struct fuse_kstatfs st;
+};
+
+struct fuse_attr {
+ uint64_t ino;
+ uint64_t size;
+ uint64_t blocks;
+ uint64_t atime;
+ uint64_t mtime;
+ uint64_t ctime;
+ uint32_t atimensec;
+ uint32_t mtimensec;
+ uint32_t ctimensec;
+ uint32_t mode;
+ uint32_t nlink;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t rdev;
+};
+
+struct fuse_attr_in {
+ uint32_t getattr_flags;
+ uint32_t dummy;
+ uint32_t fh;
+};
+
+struct fuse_attr_out {
+ uint64_t attr_valid;
+ uint32_t attr_valid_nsec;
+ uint32_t dummy;
+ struct fuse_attr attr;
+};
+
+struct fuse_access_in {
+ uint32_t mask;
+ uint32_t padding;
+};
+
+struct fuse_open_in {
+ uint32_t flags;
+ uint32_t mode;
+};
+
+struct fuse_open_out {
+ uint64_t fh;
+ uint32_t open_flags;
+ uint32_t padding;
+};
+
+struct fuse_release_in {
+ uint64_t fh;
+ uint32_t flags;
+ uint32_t release_flags;
+ uint64_t lock_owner;
+};
+
+struct fuse_read_in {
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t padding;
+};
+
+struct fuse_dirent {
+ uint64_t ino;
+ uint64_t off;
+ uint32_t namelen;
+ uint32_t type;
+ char name[0];
+};
+
+struct pseudo_dirent {
+ uint32_t d_namlen;
+};
+
+struct fuse_entry_out {
+ uint64_t nodeid;
+ uint64_t generation;
+
+ uint64_t entry_valid; /* Cache timeout for the name */
+ uint64_t attr_valid; /* Cache timeout for the attributes */
+ uint32_t entry_valid_nsec;
+ uint32_t attr_valid_nsec;
+ struct fuse_attr attr;
+};
+
+struct fuse_mkdir_in {
+ uint32_t mode;
+ uint32_t padding;
+};
+
+struct fuse_link_in {
+ uint64_t oldnodeid;
+};
+
+struct fuse_write_in {
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t write_flags;
+};
+
+struct fuse_write_out {
+ uint32_t size;
+ uint32_t padding;
+};
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(uint64_t) - 1) &
~(sizeof(uint64_t) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
+
+#endif /* __FUSEFS_H__ */
Index: miscfs/fuse/fuse_lookup.c
===================================================================
RCS file: miscfs/fuse/fuse_lookup.c
diff -N miscfs/fuse/fuse_lookup.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_lookup.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+extern int fusefs_lookup(void *);
+
+int
+fusefs_lookup(void *v)
+{
+ struct vop_lookup_args *ap = v;
+ struct vnode *vdp; /* vnode for directory being searched */
+ struct fuse_node *dp; /* inode for directory being searched */
+ struct fuse_mnt *fmp; /* file system that directory is in */
+ int lockparent; /* 1 => lockparent flag is set */
+ struct vnode *tdp; /* returned by VOP_VGET */
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct ucred *cred = cnp->cn_cred;
+ struct fuse_entry_out *feo = NULL;
+ int flags;
+ int nameiop = cnp->cn_nameiop;
+ /*struct proc *p = cnp->cn_proc;*/
+ int error = 0;
+ uint64_t nid;
+
+ flags = cnp->cn_flags;
+ *vpp = NULL;
+ vdp = ap->a_dvp;
+ dp = VTOI(vdp);
+ fmp = dp->i_mnt;
+ lockparent = flags & LOCKPARENT;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("lookup path %s\n", cnp->cn_pnbuf);
+ printf("lookup file %s\n", cnp->cn_nameptr);
+#endif
+
+ if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
+ return (error);
+
+ if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
+
+ /* if we get ".." */
+ if (flags & ISDOTDOT) {
+ nid = dp->parent;
+ if (nid == 0) {
+ return ENOENT;
+ }
+ } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
/* if we get "." */
+ nid = dp->i_number;
+ } else { /* if we get a real entry */
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LOOKUP,
dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse lookup", 0);
+
+ if (error)
+ return (error);
+
+ if (msg.error) {
+ if ((nameiop == CREATE || nameiop == RENAME) && (flags &
ISLASTCN) ) {
+ if (vdp->v_mount->mnt_flag & MNT_RDONLY)
+ return EROFS;
+
+ cnp->cn_flags |= SAVENAME;
+
+ if (!lockparent) {
+ VOP_UNLOCK(vdp, 0, curproc);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+
+ error = EJUSTRETURN;
+ goto out;
+ }
+
+ error = ENOENT;
+ goto out;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+ nid = feo->nodeid;
+ }
+
+ if (nameiop == DELETE && (flags & ISLASTCN)) {
+ /*
+ * Write access to directory required to delete files.
+ */
+ if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
+ return (error);
+
+ cnp->cn_flags |= SAVENAME;
+ }
+
+ if (flags & ISDOTDOT) {
+ printf("lookup for ..\n");
+ VOP_UNLOCK(vdp, 0, curproc); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
+
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (error) {
+ if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, curproc) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
+
+ return (error);
+ }
+
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(vdp, LK_EXCLUSIVE, curproc))) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ *vpp = tdp;
+
+ } else if (nid == dp->i_number) {
+ vref(vdp);
+ *vpp = vdp;
+ error = 0;
+ } else {
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (!error) {
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+ }
+
+ fuse_internal_attr_fat2vat(fmp->mp, &feo->attr,
&(VTOI(tdp)->cached_attrs));
+ free(feo, M_FUSEFS);
+
+ if (error)
+ return (error);
+
+ if (vdp != NULL && vdp->v_type == VDIR) {
+ VTOI(tdp)->parent = dp->i_number;
+ }
+ if (!lockparent || !(flags & ISLASTCN)) {
+ VOP_UNLOCK(vdp, 0, curproc);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+
+ *vpp = tdp;
+ }
+
+out:
+ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE && nameiop != DELETE )
+ cache_enter(vdp, *vpp, cnp);
+
+ return (error);
+}
Index: miscfs/fuse/fuse_node.c
===================================================================
RCS file: miscfs/fuse/fuse_node.c
diff -N miscfs/fuse/fuse_node.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_node.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+LIST_HEAD(ihashhead, fuse_node) *fhashtbl;
+u_long fhash; /* size of hash table - 1 */
+#define INOHASH(fd, inum) (&fhashtbl[((fd) + (inum)) & fhash])
+
+void
+fusefs_ihashinit(void)
+{
+ fhashtbl = hashinit(desiredvnodes, M_FUSEFS, M_WAITOK, &fhash);
+}
+
+
+/*
+ * Use the fd/inum pair to find the incore inode, and return a pointer
+ * to it. If it is in core, but locked, wait for it.
+ */
+struct vnode *
+fusefs_ihashget(int fd, ino_t inum)
+{
+ struct proc *p = curproc;
+ struct fuse_node *ip;
+ struct vnode *vp;
+loop:
+ /* XXXLOCKING lock hash list */
+ LIST_FOREACH(ip, INOHASH(fd, inum), i_hash) {
+ if (inum == ip->i_number && fd == ip->i_fd) {
+ vp = ITOV(ip);
+ /* XXXLOCKING unlock hash list? */
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ return (vp);
+ }
+ }
+ /* XXXLOCKING unlock hash list? */
+ return (NULL);
+}
+
+int
+fusefs_ihashins(struct fuse_node *ip)
+{
+ struct fuse_node *curip;
+ struct ihashhead *ipp;
+ int fd = ip->i_fd;
+ ino_t inum = ip->i_number;
+
+ /* lock the inode, then put it on the appropriate hash list */
+ lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL);
+
+ /* XXXLOCKING lock hash list */
+
+ LIST_FOREACH(curip, INOHASH(fd, inum), i_hash) {
+ if (inum == curip->i_number && fd == curip->i_fd) {
+ /* XXXLOCKING unlock hash list? */
+ lockmgr(&ip->i_lock, LK_RELEASE, NULL);
+ return (EEXIST);
+ }
+ }
+
+ ipp = INOHASH(fd, inum);
+ LIST_INSERT_HEAD(ipp, ip, i_hash);
+ /* XXXLOCKING unlock hash list? */
+
+ return (0);
+}
+/*
+ * Remove the inode from the hash table.
+ */
+void
+fusefs_ihashrem(struct fuse_node *ip)
+{
+ /* XXXLOCKING lock hash list */
+
+ if (ip->i_hash.le_prev == NULL)
+ return;
+
+ LIST_REMOVE(ip, i_hash);
+#ifdef DIAGNOSTIC
+ ip->i_hash.le_next = NULL;
+ ip->i_hash.le_prev = NULL;
+#endif
+ /* XXXLOCKING unlock hash list? */
+}
Index: miscfs/fuse/fuse_node.h
===================================================================
RCS file: miscfs/fuse/fuse_node.h
diff -N miscfs/fuse/fuse_node.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_node.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSE_NODE_H__
+#define __FUSE_NODE_H__
+
+enum fufh_type {
+ FUFH_INVALID = -1,
+ FUFH_RDONLY = 0,
+ FUFH_WRONLY = 1,
+ FUFH_RDWR = 2,
+ FUFH_MAXTYPE = 3,
+};
+
+struct fuse_filehandle {
+ uint64_t fh_id;
+ enum fufh_type fh_type;
+};
+
+struct fuse_node {
+ LIST_ENTRY(fuse_node) i_hash; /* Hash chain */
+ struct vnode *i_vnode; /* vnode associated with this inode */
+ struct lockf *i_lockf; /* Head of byte-level lock list. */
+ struct lock i_lock; /* node lock */
+ ino_t i_number; /* the identity of the inode */
+ int i_fd; /* fd of fuse session */
+
+ struct fuse_mnt *i_mnt; /* filesystem associated with this inode */
+ uint64_t parent;
+
+ /** I/O **/
+ struct fuse_filehandle fufh[FUFH_MAXTYPE];
+
+ /** flags **/
+ uint32_t flag;
+
+ /** meta **/
+ struct vattr cached_attrs;
+ off_t filesize;
+ uint64_t nlookup;
+ enum vtype vtype;
+};
+
+extern struct fuse_node **fusehashtbl;
+extern u_long fusehash;
+
+void fusefs_ihashinit(void);
+struct vnode *fusefs_ihashget(int, ino_t);
+int fusefs_ihashins(struct fuse_node *ip);
+void fusefs_ihashrem(struct fuse_node *ip);
+#define ITOV(ip) ((ip)->i_vnode)
+#define VTOI(vp) ((struct fuse_node *)(vp)->v_data)
+
+#endif /* __FUSE_NODE_H__ */
Index: miscfs/fuse/fuse_subr.c
===================================================================
RCS file: miscfs/fuse/fuse_subr.c
diff -N miscfs/fuse/fuse_subr.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_subr.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+void
+fuse_make_in(struct mount *mp, struct fuse_in_header *hdr, int len,
+ enum fuse_opcode op, ino_t ino, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+
+ fmp = VFSTOFUSEFS(mp);
+
+ fmp->unique++;
+
+ hdr->len = sizeof(*hdr) + len;
+ hdr->opcode = op;
+ hdr->nodeid = ino;
+ hdr->unique = fmp->unique;
+#ifdef FUSE_DEBUG_MSG
+ printf("creat unique %i\n", hdr->unique);
+#endif
+
+ if (!p) {
+ hdr->pid = curproc->p_pid;
+ hdr->uid = 0;
+ hdr->gid = 0;
+ } else {
+ hdr->pid = p->p_pid;
+ hdr->uid = p->p_cred->p_ruid;
+ hdr->gid = p->p_cred->p_rgid;
+ }
+}
+
+void
+fuse_init_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+ struct fuse_init_out *out = data;
+
+#ifdef FUSE_DEBUG_MSG
+ printf("async init unique %i\n", msg->hdr->unique);
+ printf("init_out flags %i\n", out->flags);
+ printf("init_out major %i\n", out->major);
+ printf("init_out minor %i\n", out->minor);
+ printf("init_out max_readahead %i\n", out->max_readahead);
+ printf("init_out max_write %i\n", out->max_write);
+ printf("init_out unused %i\n", out->unused);
+#endif
+
+ msg->fmp->sess_init = 1;
+ msg->fmp->max_write = out->max_readahead;
+}
+
+void
+fuse_sync_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+ size_t len;
+
+#ifdef FUSE_DEBUG_MSG
+ printf("buf unique %i\n", msg->hdr->unique);
+#endif
+
+ if (msg->type != msg_buff)
+ printf("bad msg type\n");
+
+ if (data != NULL && msg->rep.buff.len != 0) {
+ len = hdr->len - sizeof(*hdr);
+ if (msg->rep.buff.len != len) {
+ printf("fusefs: packet size error on opcode %i\n",
msg->hdr->opcode);
+ }
+
+ if (msg->rep.buff.len > len)
+ printf("buff unused byte : 0x%x\n", msg->rep.buff.len - len);
+
+ msg->rep.buff.data_rcv = malloc(msg->rep.buff.len, M_FUSEFS,
M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, msg->rep.buff.len);
+
+ wakeup(msg);
+
+ } else if (data != NULL) {
+ len = hdr->len - sizeof(*hdr);
+ msg->rep.buff.data_rcv = malloc(len, M_FUSEFS, M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, len);
+ msg->rep.buff.len = len;
+
+ wakeup(msg);
+ } else if (hdr->error) {
+ msg->error = hdr->error;
+#ifdef FUSE_DEBUG_MSG
+ printf("error %i\n", msg->error);
+#endif
+ wakeup(msg);
+ } else {
+ msg->error = -1;
+#ifdef FUSE_DEBUG_MSG
+ printf("ack for msg\n");
+#endif
+ wakeup(msg);
+ }
+}
+
+void
+fuse_sync_it(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+#ifdef FUSE_DEBUG_MSG
+ printf("it unique %i\n", msg->hdr->unique);
+#endif
+
+ if (msg->type != msg_intr)
+ printf("bad msg type\n");
+
+ if (data != NULL)
+ printf("normally data should be Null\n");
+
+ msg->rep.it_res = hdr->error;
+#ifdef FUSE_DEBUG_MSG
+ printf("errno = %d\n");
+#endif
+
+ wakeup(msg);
+}
Index: miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: miscfs/fuse/fuse_vfsops.c
diff -N miscfs/fuse/fuse_vfsops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_vfsops.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+static int fusefs_mount(struct mount *mp, const char *path, void *data,
+ struct nameidata *ndp, struct proc *p);
+static int fusefs_start(struct mount *mp, int flags, struct proc *p);
+static int fusefs_unmount(struct mount *mp, int mntflags, struct proc *p);
+static int fusefs_root(struct mount *mp, struct vnode **vpp);
+static int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid,
+ caddr_t arg, struct proc *p);
+static int fusefs_statfs(struct mount *mp, struct statfs *sbp,
+ struct proc *p);
+static int fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
+ struct proc *p);
+static int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
+static int fusefs_fhtovp(struct mount *mp, struct fid *fhp,
+ struct vnode **vpp);
+static int fusefs_vptofh(struct vnode *vp, struct fid *fhp);
+static int fusefs_init(struct vfsconf *);
+static int fusefs_sysctl(int *, u_int, void *, size_t *, void *,
+ size_t, struct proc *);
+static int fusefs_checkexp(struct mount *mp, struct mbuf *nam,
+ int *extflagsp, struct ucred **credanonp);
+
+const struct vfsops fusefs_vfsops = {
+ fusefs_mount,
+ fusefs_start,
+ fusefs_unmount,
+ fusefs_root,
+ fusefs_quotactl,
+ fusefs_statfs,
+ fusefs_sync,
+ fusefs_vget,
+ fusefs_fhtovp,
+ fusefs_vptofh,
+ fusefs_init,
+ fusefs_sysctl,
+ fusefs_checkexp
+};
+
+int
+fusefs_mount(struct mount *mp, const char *path, void *data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_msg *msg;
+ struct fuse_init_in *init;
+ struct fusefs_args args;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("mount\n");
+#endif
+
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
+
+ error = copyin(data, &args, sizeof(struct fusefs_args));
+ if (error)
+ return error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("fd = %d\n", args.fd);
+#endif
+
+ fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
+ fmp->mp = mp;
+ fmp->sess_init = 0;
+ fmp->unique = 0;
+ fmp->fd = args.fd;
+ mp->mnt_data = (qaddr_t)fmp;
+
+ mp->mnt_flag |= MNT_LOCAL;
+ vfs_getnewfsid(mp);
+
+ bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
+ strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
+ bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
+ bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
+
+ msg = malloc(sizeof(struct fuse_msg), M_FUSEFS, M_WAITOK | M_ZERO);
+ msg->hdr = malloc(sizeof(struct fuse_in_header), M_FUSEFS,
M_WAITOK | M_ZERO);
+ init = malloc(sizeof(struct fuse_init_in), M_FUSEFS, M_WAITOK | M_ZERO);
+
+ init->major = FUSE_KERNEL_VERSION;
+ init->minor = FUSE_KERNEL_MINOR_VERSION;
+ init->max_readahead = 4096 * 16;
+ init->flags = 0;
+ msg->data = init;
+ msg->len = sizeof(*init);
+ msg->cb = &fuse_init_resp;
+ msg->fmp = fmp;
+ msg->type = msg_buff_async;
+
+ fuse_make_in(mp, msg->hdr, msg->len, FUSE_INIT, 0, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, msg, node);
+ wakeup(&fmq_in);
+
+ return (0);
+}
+
+int
+fusefs_start(struct mount *mp, int flags, struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("start\n");
+#endif
+ return (0);
+}
+
+int
+fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ extern int doforce;
+ struct fuse_msg *m;
+ int flags = 0;
+ int error;
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (!fmp->sess_init)
+ return 0;
+
+ fmp->sess_init = 0;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("unmount\n");
+#endif
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.type = msg_intr;
+ msg.data = NULL;
+ msg.cb = &fuse_sync_it;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_DESTROY, 0, curproc);
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse unmount", 0);
+
+ if (error)
+ return (error);
+
+ error = msg.rep.it_res;
+
+ if (error)
+ printf("error from fuse\n");
+
+ /* clear FIFO IN*/
+ while ((m = TAILQ_FIRST(&fmq_in))) {
+ printf("warning some msg where not processed....\n");
+ }
+
+ /* clear FIFO WAIT*/
+ while ((m = TAILQ_FIRST(&fmq_wait))) {
+ printf("warning some msg where not processed....\n");
+ }
+
+ if (mntflags & MNT_FORCE) {
+ /* fusefs can never be rootfs so don't check for it */
+ if (!doforce)
+ return (EINVAL);
+ flags |= FORCECLOSE;
+ }
+
+ if ((error = vflush(mp, 0, flags)))
+ return (error);
+
+ free(fmp, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_root(struct mount *mp, struct vnode **vpp)
+{
+ struct vnode *nvp;
+ struct fuse_node *ip;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("root\n");
+#endif
+
+ if ((error = VFS_VGET(mp, (ino_t)FUSE_ROOTINO, &nvp)) != 0)
+ return (error);
+
+ ip = VTOI(nvp);
+ nvp->v_type = VDIR;
+ ip->vtype = VDIR;
+
+ *vpp = nvp;
+ return (0);
+}
+
+int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
+ struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("quotactl\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
+{
+ struct fuse_statfs_out *stat;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("statfs\n");
+#endif
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (fmp->sess_init) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*stat);
+ msg.cb = &fuse_sync_resp;
+ msg.type = msg_buff;
+
+ fuse_make_in(mp, msg.hdr, msg.len, FUSE_STATFS, FUSE_ROOT_ID, NULL);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse stat", 0);
+ if (error) {
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return error;
+ }
+
+ stat = (struct fuse_statfs_out *)msg.rep.buff.data_rcv;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("statfs a: %i\n", stat->st.bavail);
+ printf("statfs a: %i\n", stat->st.bfree);
+ printf("statfs a: %i\n", stat->st.blocks);
+ printf("statfs a: %i\n", stat->st.bsize);
+ printf("statfs a: %i\n", stat->st.ffree);
+ printf("statfs a: %i\n", stat->st.files);
+ printf("statfs a: %i\n", stat->st.frsize);
+ printf("statfs a: %i\n", stat->st.namelen);
+ printf("statfs a: %i\n", stat->st.padding);
+#endif
+
+ sbp->f_bavail = stat->st.bavail;
+ sbp->f_bfree = stat->st.bfree;
+ sbp->f_blocks = stat->st.blocks;
+ sbp->f_ffree = stat->st.ffree;
+ sbp->f_files = stat->st.files;
+ sbp->f_bsize = stat->st.frsize;
+ sbp->f_namemax = stat->st.namelen;
+
+ free(stat, M_FUSEFS);
+ } else {
+ sbp->f_bavail = 0;
+ sbp->f_bfree = 0;
+ sbp->f_blocks = 0;
+ sbp->f_ffree = 0;
+ sbp->f_files = 0;
+ sbp->f_bsize = 0;
+ sbp->f_namemax = 0;
+ }
+
+
+ return (0);
+}
+
+int fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
+ struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("sync\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct vnode *nvp;
+ int i;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("vget\n");
+#endif
+retry:
+ fmp = VFSTOFUSEFS(mp);
+ /*
+ * check if vnode is in hash.
+ */
+ if ((*vpp = fusefs_ihashget(fmp->fd, ino)) != NULLVP)
+ return (0);
+
+ /*
+ * if not create it
+ */
+ if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
+ printf("getnewvnode error\n");
+ *vpp = NULLVP;
+ return (error);
+ }
+
+ ip = malloc(sizeof(*ip), M_FUSEFS, M_WAITOK | M_ZERO);
+ lockinit(&ip->i_lock, PINOD, "fuseinode", 0, 0);
+ nvp->v_data = ip;
+ ip->i_vnode = nvp;
+ ip->i_fd = fmp->fd;
+ ip->i_number = ino;
+ ip->parent = 0;
+
+ for (i = 0; i < FUFH_MAXTYPE; i++)
+ ip->fufh[i].fh_type = FUFH_INVALID;
+
+ error = fusefs_ihashins(ip);
+ if (error) {
+ vrele(nvp);
+
+ if (error == EEXIST)
+ goto retry;
+
+ return (error);
+ }
+
+ ip->i_mnt = fmp;
+
+ if (ino == FUSE_ROOTINO)
+ nvp->v_flag |= VROOT;
+
+ *vpp = nvp;
+
+ return (0);
+}
+
+int fusefs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("fhtovp\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_vptofh(struct vnode *vp, struct fid *fhp)
+{
+ #ifdef FUSE_DEBUG_VFS
+ printf("vptofh\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_init(struct vfsconf *vfc)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("init\n");
+#endif
+
+ TAILQ_INIT(&fmq_in);
+ TAILQ_INIT(&fmq_wait);
+
+ fusefs_ihashinit();
+ return (0);
+}
+
+int fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplen,
+ void *newp, size_t newlen, struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("sysctl\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
+ struct ucred **credanonp)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("checkexp\n");
+#endif
+
+ return (0);
+}
Index: miscfs/fuse/fuse_vnops.c
===================================================================
RCS file: miscfs/fuse/fuse_vnops.c
diff -N miscfs/fuse/fuse_vnops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_vnops.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,1341 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#include <sys/specdev.h>
+#include <sys/poll.h>
+#include <sys/lockf.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+/*
+ * Prototypes for fusefs vnode ops
+ */
+extern int fusefs_lookup(void *);
+int fusefs_open(void *);
+int fusefs_close(void *);
+int fusefs_access(void *);
+int fusefs_getattr(void *);
+int fusefs_setattr(void *);
+int fusefs_ioctl(void *);
+int fusefs_link(void *);
+int fusefs_symlink(void *);
+int fusefs_readdir(void *);
+int fusefs_readlink(void *);
+int fusefs_inactive(void *);
+int fusefs_reclaim(void *);
+int fusefs_print(void *);
+int fusefs_create(void *);
+int fusefs_mknod(void *);
+int fusefs_read(void *);
+int fusefs_write(void *);
+int fusefs_poll(void *);
+int fusefs_fsync(void *);
+int fusefs_remove(void *);
+int fusefs_rename(void *);
+int fusefs_mkdir(void *);
+int fusefs_rmdir(void *);
+int fusefs_strategy(void *);
+int fusefs_lock(void *);
+int fusefs_unlock(void *);
+int fusefs_islocked(void *);
+int fusefs_advlock(void *);
+int readdir_process_data(void *buff, int len, struct uio *uio);
+
+struct vops fusefs_vops = {
+ .vop_lookup = fusefs_lookup,
+ .vop_create = fusefs_create,
+ .vop_mknod = fusefs_mknod,
+ .vop_open = fusefs_open,
+ .vop_close = fusefs_close,
+ .vop_access = fusefs_access,
+ .vop_getattr = fusefs_getattr,
+ .vop_setattr = fusefs_setattr,
+ .vop_read = fusefs_read,
+ .vop_write = fusefs_write,
+ .vop_ioctl = fusefs_ioctl,
+ .vop_poll = fusefs_poll,
+ .vop_fsync = fusefs_fsync,
+ .vop_remove = fusefs_remove,
+ .vop_link = fusefs_link,
+ .vop_rename = fusefs_rename,
+ .vop_mkdir = fusefs_mkdir,
+ .vop_rmdir = fusefs_rmdir,
+ .vop_symlink = fusefs_symlink,
+ .vop_readdir = fusefs_readdir,
+ .vop_readlink = fusefs_readlink,
+ .vop_abortop = vop_generic_abortop,
+ .vop_inactive = fusefs_inactive,
+ .vop_reclaim = fusefs_reclaim,
+ .vop_lock = fusefs_lock,
+ .vop_unlock = fusefs_unlock,
+ .vop_bmap = vop_generic_bmap,
+ .vop_strategy = fusefs_strategy,
+ .vop_print = fusefs_print,
+ .vop_islocked = fusefs_islocked,
+ .vop_pathconf = spec_pathconf,
+ .vop_advlock = fusefs_advlock,
+};
+
+
+void
+fuse_internal_attr_fat2vat(struct mount *mp,
+ struct fuse_attr *fat,
+ struct vattr *vap)
+{
+ vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
+ vap->va_fileid = fat->ino;/* XXX cast from 64 bits to 32 */
+ vap->va_mode = fat->mode & ~S_IFMT;
+ vap->va_nlink = fat->nlink;
+ vap->va_uid = fat->uid;
+ vap->va_gid = fat->gid;
+ vap->va_rdev = fat->rdev;
+ vap->va_size = fat->size;
+ vap->va_atime.tv_sec = fat->atime;
+ vap->va_atime.tv_nsec = fat->atimensec;
+ vap->va_mtime.tv_sec = fat->mtime;
+ vap->va_mtime.tv_nsec = fat->mtimensec;
+ vap->va_ctime.tv_sec = fat->ctime;
+ vap->va_ctime.tv_nsec = fat->ctimensec;
+ vap->va_blocksize = PAGE_SIZE;
+ vap->va_type = IFTOVT(fat->mode);
+
+#if (S_BLKSIZE == 512)
+ /* Optimize this case */
+ vap->va_bytes = fat->blocks << 9;
+#else
+ vap->va_bytes = fat->blocks * S_BLKSIZE;
+#endif
+
+}
+
+int
+fusefs_open(void *v)
+{
+ struct vop_open_args *ap;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ enum fufh_type fufh_type;
+ int flags;
+ int error;
+ int isdir;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_open\n");
+#endif
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("inode = %i mode=0x%x\n", ip->i_number, ap->a_mode);
+#endif
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ isdir = 1;
+ } else {
+ if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) {
+ fufh_type = FUFH_RDWR;
+ flags = O_RDWR;
+ }
+ else if (ap->a_mode & (FWRITE)) {
+ fufh_type = FUFH_WRONLY;
+ flags = O_WRONLY;
+ }
+ else if (ap->a_mode & (FREAD)) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ }
+ }
+
+ /* already open i think all is ok */
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return 0;
+
+ error = fuse_file_open(fmp, ip, fufh_type, flags, isdir);
+
+ if (error)
+ return (error);
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("file open fd : %i\n", ip->fufh[fufh_type].fh_id);
+#endif
+ return (error);
+}
+
+int
+fusefs_close(void *v)
+{
+ struct vop_close_args *ap;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ enum fufh_type fufh_type;
+ int isdir, flags, i;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_close\n");
+#endif
+
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ isdir = 1;
+
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return fuse_file_close(fmp, ip, fufh_type, O_RDONLY, isdir);
+ } else {
+ if (ap->a_fflag & IO_NDELAY) {
+ return (0);
+ }
+
+ if ((ap->a_fflag & FREAD) && (ap->a_fflag & FWRITE)) {
+ fufh_type = FUFH_RDWR;
+ flags = O_RDWR;
+ }
+ else if (ap->a_fflag & (FWRITE)) {
+ fufh_type = FUFH_WRONLY;
+ flags = O_WRONLY;
+ }
+ else if (ap->a_fflag & (FREAD)) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ }
+ }
+
+ /*
+ * if fh not valid lookup for another valid fh in vnode.
+ * panic if there's not fh valid
+ */
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID) {
+ for (i = 0; i < FUFH_MAXTYPE; i++)
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ break;
+ return (0);
+ }
+
+ return (0);
+}
+
+int
+fusefs_access(void *v)
+{
+ struct fuse_access_in access;
+ struct vop_access_args *ap;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ uint32_t mask = 0;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_access\n");
+#endif
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_ACCESS))
+ goto system_check;
+
+ if (ap->a_vp->v_type == VLNK)
+ goto system_check;
+
+ if (ap->a_vp->v_type == VREG && (ap->a_mode & VWRITE & VEXEC))
+ goto system_check;
+
+ if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY))
+ return(EACCES);
+
+ if ((ap->a_mode & VWRITE) != 0) {
+ mask |= 0x2;
+ }
+ if ((ap->a_mode & VREAD) != 0) {
+ mask |= 0x4;
+ }
+ if ((ap->a_mode & VEXEC) != 0) {
+ mask |= 0x1;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ access.mask = mask;
+ msg.data = &access;
+ msg.len = sizeof(access);
+ msg.cb = &fuse_sync_it;
+ msg.fmp = fmp;
+ msg.type = msg_intr;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_ACCESS,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse access", 0);
+
+ if (error)
+ return error;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("it with value %x\n", msg.rep.it_res);
+#endif
+ error = msg.rep.it_res;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_ACCESS;
+ goto system_check;
+ }
+
+ return (error);
+
+system_check:
+#ifdef FUSE_DEBUG_VNOP
+ printf("Use kernel access\n");
+#endif
+ return (vaccess(ap->a_vp->v_type, ip->cached_attrs.va_mode & ALLPERMS,
+ ip->cached_attrs.va_uid, ip->cached_attrs.va_gid, ap->a_mode,
ap->a_cred));
+}
+
+int
+fusefs_getattr(void *v)
+{
+ struct vop_getattr_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_mnt *fmp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_in_header hdr;
+ struct fuse_attr_out *fat;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_getattr\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ goto fake;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.len = sizeof(*fat);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_GETATTR,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.data_rcv != NULL)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ fat = (struct fuse_attr_out *)msg.rep.buff.data_rcv;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("ino: %d\n", fat->attr.ino);
+ printf("size: %d\n", fat->attr.size);
+ printf("blocks: %d\n", fat->attr.blocks);
+ printf("atime: %d\n", fat->attr.atime);
+ printf("mtime: %d\n", fat->attr.mtime);
+ printf("ctime: %d\n", fat->attr.ctime);
+ printf("atimensec: %d\n", fat->attr.atimensec);
+ printf("mtimensec: %d\n", fat->attr.mtimensec);
+ printf("ctimensec: %d\n", fat->attr.ctimensec);
+ printf("mode: %d\n", fat->attr.mode);
+ printf("nlink: %d\n", fat->attr.nlink);
+ printf("uid: %d\n", fat->attr.uid);
+ printf("gid: %d\n", fat->attr.gid);
+ printf("rdev: %d\n", fat->attr.rdev);
+#endif
+
+ fuse_internal_attr_fat2vat(fmp->mp, &fat->attr, vap);
+
+ memcpy(&ip->cached_attrs, vap, sizeof(*vap));
+ free(fat, M_FUSEFS);
+
+ return (error);
+fake:
+ bzero(vap, sizeof(*vap));
+ vap->va_type = vp->v_type;
+ return (0);
+}
+
+int
+fusefs_setattr(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_setattr\n");
+#endif
+ return (0);
+}
+
+int
+fusefs_ioctl(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_ioctl\n");
+#endif
+ return (ENOTTY);
+}
+
+int
+fusefs_link(void *v)
+{
+ struct vop_link_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_link_in fli;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_link\n");
+#endif
+
+ if (vp->v_type == VDIR) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EISDIR;
+ goto out2;
+ }
+ if (dvp->v_mount != vp->v_mount) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EXDEV;
+ goto out2;
+ }
+ if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, curproc))) {
+ VOP_ABORTOP(dvp, cnp);
+ goto out2;
+ }
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_LINK))
+ goto out1;
+
+ fli.oldnodeid = ip->i_number;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fli);
+ msg.data = &fli;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LINK, ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse link", 0);
+
+ if (error) {
+ if (msg.rep.buff.data_rcv != NULL)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ goto out1;
+ }
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_LINK;
+ }
+
+ goto out1;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+ free(feo, M_FUSEFS);
+
+out1:
+ if (dvp != vp)
+ VOP_UNLOCK(vp, 0, curproc);
+out2:
+ vput(dvp);
+ return (error);
+}
+
+int
+fusefs_symlink(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_symlink\n");
+#endif
+ return (0);
+}
+
+#define GENERIC_DIRSIZ(dp) \
+ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+
+int
+readdir_process_data(void *buff, int len, struct uio *uio)
+{
+ struct fuse_dirent *fdir;
+ struct dirent dir;
+ int bytesavail;
+ int flen, error = 0;
+
+ if (len < FUSE_NAME_OFFSET) {
+ return 0;
+ }
+
+ while ( len > 0) {
+ if ( len < sizeof(*fdir)) {
+ error = 0;
+ break;
+ }
+
+ fdir = (struct fuse_dirent *)buff;
+ flen = FUSE_DIRENT_SIZE(fdir);
+
+ if (!fdir->namelen || fdir->namelen > MAXNAMLEN || len < flen) {
+ error = EINVAL;
+ break;
+ }
+
+ bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) &fdir->namelen);
+ if (bytesavail > uio->uio_resid) {
+ error = 0;
+ break;
+ }
+
+ bzero(&dir, sizeof(dir));
+ dir.d_fileno = fdir->ino;
+ dir.d_reclen = bytesavail;
+ dir.d_type = fdir->type;
+ dir.d_namlen = fdir->namelen;
+ bcopy(fdir->name, dir.d_name, fdir->namelen);
+
+ uiomove(&dir, bytesavail , uio);
+ len -= flen;
+ /* ugly pointer arithmetic must find something else ...*/
+ buff = (void *)(((char *) buff) + flen);
+ uio->uio_offset = fdir->off;
+ }
+
+ return (error);
+}
+
+int
+fusefs_readdir(void *v)
+{
+ struct vop_readdir_args *ap = v;
+ struct fuse_read_in read;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct vnode *vp;
+ struct uio *uio;
+ int error = 0;
+
+ vp = ap->a_vp;
+ uio = ap->a_uio;
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_readdir\n");
+ printf("uio resid 0x%x\n", uio->uio_resid);
+#endif
+ if (uio->uio_resid == 0)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(read);
+ msg.type = msg_buff;
+
+ msg.rep.buff.len= 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.data = &read;
+ msg.cb = &fuse_sync_resp;
+
+ if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) {
+ printf("dir not open\n");
+ /* TODO open the file */
+ return (error);
+ }
+ read.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ read.offset = uio->uio_offset;
+ read.size = MIN(uio->uio_resid, PAGE_SIZE);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READDIR,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ if (msg.error == -1) {
+ //ack for end of readdir
+ break;
+ }
+
+ if ((error = readdir_process_data(msg.rep.buff.data_rcv,
msg.rep.buff.len, uio))) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ break;
+ }
+
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ }
+
+ return (error);
+}
+
+int
+fusefs_inactive(void *v)
+{
+ struct vop_inactive_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ register struct fuse_node *ip = VTOI(vp);
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_inactive\n");
+#endif
+
+ ip->flag = 0;
+ VOP_UNLOCK(vp, 0, p);
+
+ /* not sure if it is ok to do like that ...*/
+ if (ip->cached_attrs.va_mode == 0)
+ vrecycle(vp, p);
+
+ return (error);
+}
+
+int
+fusefs_readlink(void *v)
+{
+ struct vop_readlink_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct uio *uio;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_readlink\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+ uio = ap->a_uio;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_READLINK)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READLINK,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse readlink", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_READLINK;
+ }
+ goto out;
+ }
+
+ error = uiomove(msg.rep.buff.data_rcv, msg.rep.buff.len, uio);
+
+out:
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_reclaim(void *v)
+{
+ struct vop_reclaim_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_node *ip = VTOI(vp);
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_reclaim\n");
+#endif
+ /*
+ * Purge old data structures associated with the inode.
+ */
+ ip->parent = 0;
+
+ /*
+ * Remove the inode from its hash chain.
+ */
+ fusefs_ihashrem(ip);
+ cache_purge(vp);
+
+ /*close file if exist
+ if (ip->i_fd) {
+ vrele(ip->i_devvp);
+ ip->i_devvp = 0;
+ }*/
+
+ free(ip, M_FUSEFS);
+ vp->v_data = NULL;
+ return (0);
+}
+
+int
+fusefs_print(void *v)
+{
+ struct vop_print_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_node *ip = VTOI(vp);
+
+ /*
+ * Complete the information given by vprint().
+ */
+ printf("tag VT_FUSE, hash id %u ", ip->i_number);
+ lockmgr_printinfo(&ip->i_lock);
+ printf("\n");
+ return (0);
+}
+
+int
+fusefs_create(void *v)
+{
+ struct vop_create_args *ap = v;
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_entry_out *feo;
+ struct fuse_in_header hdr;
+ struct vnode *tdp = NULL;
+ struct fuse_open_in foi;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+ mode_t mode;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_create(cnp %08x, vap %08x\n", cnp, vap);
+#endif
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_CREATE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(foi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out) + sizeof(struct
fuse_open_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ foi.mode = mode;
+ foi.flags = O_CREAT | O_RDWR;
+
+ memcpy(msg.data, &foi, sizeof(foi));
+ memcpy((char *)msg.data + sizeof(foi), cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(foi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_CREATE,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse create", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_CREATE;
+ }
+ goto out;
+ }
+
+ feo = msg.rep.buff.data_rcv;
+ if ((error = VFS_VGET(fmp->mp, feo->nodeid, &tdp)))
+ goto out;
+
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+
+ if (dvp != NULL && dvp->v_type == VDIR)
+ VTOI(tdp)->parent = ip->i_number;
+
+ *vpp = tdp;
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+
+out:
+ vput(ap->a_dvp);
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_mknod(void *v)
+{
+ struct vop_mknod_args *ap = v;
+
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+ vput(ap->a_dvp);
+ return (EINVAL);
+}
+
+int
+fusefs_read(void *v)
+{
+ struct vop_read_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct fuse_in_header hdr;
+ struct fuse_read_in fri;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error=0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_read\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+#ifdef FUSE_DEBUG_VNOP
+ printf("read inode=%i, offset=%p, resid=%p\n", ip->i_mnt,
+ uio->uio_offset, uio->uio_resid);
+#endif
+
+ if (uio->uio_resid == 0)
+ return (error);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fri);
+ msg.data = &fri;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fri.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ fri.offset = uio->uio_offset;
+ fri.size = MIN(uio->uio_resid, fmp->max_write);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READ,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse read", 0)))
+ break;
+
+ if ((error = uiomove(msg.rep.buff.data_rcv, MIN(fri.size,
msg.rep.buff.len), uio))) {
+ break;
+ }
+
+ if (msg.rep.buff.len < fri.size)
+ break;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_write(void *v)
+{
+ struct vop_write_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct fuse_in_header hdr;
+ struct fuse_write_in fwi;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ size_t len, diff;
+ int error=0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_write\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+#ifdef FUSE_DEBUG_VNOP
+ printf("write inode=%i, offset=%x, resid=%x\n", ip->i_mnt,
+ uio->uio_offset, uio->uio_resid);
+#endif
+
+ if (!uio->uio_resid)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ len = MIN(uio->uio_resid, fmp->max_write);
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fwi) + len;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_write_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fwi.fh = ip->fufh[FUFH_WRONLY].fh_id;
+ fwi.offset = uio->uio_offset;
+ fwi.size = len;
+
+ memcpy(msg.data, &fwi, sizeof(fwi));
+ if ((error = uiomove((char *)msg.data + sizeof(fwi), len, uio)))
+ break;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_WRITE,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse write", 0)))
+ break;
+
+ diff = len - ((struct fuse_write_out *)msg.rep.buff.data_rcv)->size;
+ if (diff < 0) {
+ error = EINVAL;
+ break;
+ }
+
+ uio->uio_resid += diff;
+ uio->uio_offset -= diff;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_poll(void *v)
+{
+ struct vop_poll_args *ap = v;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_poll\n");
+#endif
+
+ /*
+ * We should really check to see if I/O is possible.
+ */
+ return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
+}
+
+int
+fusefs_fsync(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_fsync\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_rename(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_rename\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_mkdir(void *v)
+{
+ struct vop_mkdir_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_mkdir_in fmdi;
+ struct vnode *tdp = NULL;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_mkdir %s\n", cnp->cn_nameptr);
+#endif
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKDIR)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fmdi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ memcpy(msg.data, &fmdi, sizeof(fmdi));
+ memcpy((char *)msg.data + sizeof(fmdi), cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(fmdi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_MKDIR, ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse mkdir", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_MKDIR;
+ }
+ goto out;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+
+ if ((error = VFS_VGET(fmp->mp, feo->nodeid, &tdp)))
+ goto out;
+
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+
+ if (dvp != NULL && dvp->v_type == VDIR)
+ VTOI(tdp)->parent = ip->i_number;
+
+ *vpp = tdp;
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
+
+out:
+ vput(dvp);
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_rmdir(void *v)
+{
+ struct vop_rmdir_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_node *ip, *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_rmdir\n");
+ printf("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0], cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+#endif
+ ip = VTOI(vp);
+ dp = VTOI(dvp);
+ fmp = ip->i_mnt;
+
+ /*
+ * No rmdir "." please.
+ */
+ if (dp == ip) {
+ vrele(dvp);
+ vput(vp);
+ return (EINVAL);
+ }
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_RMDIR)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_intr;
+ msg.cb = &fuse_sync_it;
+
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_RMDIR, dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse rmdir", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS)
+ fmp->undef_op |= UNDEF_RMDIR;
+ if (error != ENOTEMPTY)
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+ goto out;
+ }
+
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+
+ cache_purge(dvp);
+ vput(dvp);
+ dvp = NULL;
+
+ cache_purge(ITOV(ip));
+out:
+ if (dvp)
+ vput(dvp);
+ VN_KNOTE(vp, NOTE_DELETE);
+ vput(vp);
+ return (error);
+}
+
+int
+fusefs_remove(void *v)
+{
+ struct vop_remove_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_node *ip;
+ struct fuse_node *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_remove\n");
+ printf("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0], cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+#endif
+ ip = VTOI(vp);
+ dp = VTOI(dvp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_REMOVE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_intr;
+ msg.cb = &fuse_sync_it;
+
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_UNLINK,
dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+
+ if ((error = tsleep(&msg, PWAIT, "fuse remove", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS)
+ fmp->undef_op |= UNDEF_REMOVE;
+ goto out;
+ }
+
+
+ VN_KNOTE(vp, NOTE_DELETE);
+ VN_KNOTE(dvp, NOTE_WRITE);
+out:
+ if (dvp == vp)
+ vrele(vp);
+ else
+ vput(vp);
+ vput(dvp);
+ return (error);
+}
+
+int
+fusefs_strategy(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_strategy\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_lock(void *v)
+{
+ struct vop_lock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+#ifdef FUSE_LOCK
+ printf("fuse_lock\n");
+#endif
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, NULL));
+}
+
+int
+fusefs_unlock(void *v)
+{
+ struct vop_unlock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+#ifdef FUSE_LOCK
+ printf("fuse_unlock\n");
+#endif
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, NULL));
+}
+
+int
+fusefs_islocked(void *v)
+{
+ struct vop_islocked_args *ap = v;
+
+#ifdef FUSE_LOCK
+ printf("fuse_islock\n");
+#endif
+ return (lockstatus(&VTOI(ap->a_vp)->i_lock));
+}
+
+int
+fusefs_advlock(void *v)
+{
+ struct vop_advlock_args *ap = v;
+ struct fuse_node *ip = VTOI(ap->a_vp);
+
+#ifdef FUSE_LOCK
+ printf("fuse_advlock\n");
+#endif
+ return (lf_advlock(&ip->i_lockf, ip->filesize, ap->a_id, ap->a_op,
+ ap->a_fl, ap->a_flags));
+}
Index: miscfs/fuse/fusefs.h
===================================================================
RCS file: miscfs/fuse/fusefs.h
diff -N miscfs/fuse/fusefs.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fusefs.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSEFS_H__
+#define __FUSEFS_H__
+
+struct fuse_msg;
+
+struct fuse_mnt {
+ struct mount *mp;
+ uint32_t undef_op;
+ uint32_t max_write;
+ int sess_init;
+ int unique;
+ int fd;
+};
+
+#define UNDEF_ACCESS 1<<0
+#define UNDEF_MKDIR 1<<1
+#define UNDEF_CREATE 1<<2
+#define UNDEF_LINK 1<<3
+#define UNDEF_READLINK 1<<4
+#define UNDEF_RMDIR 1<<5
+#define UNDEF_REMOVE 1<<6
+
+typedef void (*fuse_cb)(struct fuse_msg *msg,struct fuse_out_header
*hdr, void *buf);
+
+struct rcv_buf {
+ void *data_rcv;
+ size_t len;
+};
+
+enum msg_type {
+ msg_intr,
+ msg_buff,
+ msg_buff_async,
+};
+
+struct fuse_msg {
+ struct fuse_in_header *hdr;
+ struct fuse_mnt *fmp;
+ void *data;
+ int len;
+ int error;
+
+ enum msg_type type;
+ union {
+ struct rcv_buf buff;
+ uint32_t it_res;
+ } rep;
+
+ fuse_cb cb;
+ TAILQ_ENTRY(fuse_msg) node;
+};
+
+extern struct vops fusefs_vops;
+
+/*
+ * In and Out fifo for fuse communication
+ */
+TAILQ_HEAD(fuse_msg_head, fuse_msg);
+
+extern struct fuse_msg_head fmq_in;
+extern struct fuse_msg_head fmq_wait;
+
+/*
+ * fuse helpers
+ */
+void fuse_make_in(struct mount *, struct fuse_in_header *, int,
+ enum fuse_opcode, ino_t, struct proc *);
+void fuse_init_resp(struct fuse_msg *, struct fuse_out_header *, void *);
+void fuse_sync_resp(struct fuse_msg *, struct fuse_out_header *, void *);
+void fuse_sync_it(struct fuse_msg *msg, struct fuse_out_header *hdr,
void *data);
+
+/*
+ * files helpers.
+ */
+
+int fuse_file_open(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int, int);
+int fuse_file_close(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int, int);
+
+void fuse_internal_attr_fat2vat(struct mount *, struct fuse_attr *,
struct vattr *);
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ */
+#define FUSE_ROOTINO ((ino_t)1)
+#define VFSTOFUSEFS(mp) ((struct fuse_mnt *)((mp)->mnt_data))
+
+#define MAX_FUSE_DEV 4
+/*
+#define FUSE_DEBUG_VNOP 42
+#define FUSE_DEBUG_VFS 42
+#define FUSE_DEBUG 42
+#define FUSE_DEV_DEBUG 42
+#define FUSE_DEBUG_MSG 42
+*/
+/*
+ * Helpers
+ */
+
+#endif /* __FUSEFS_H__ */
Index: sys/conf.h
===================================================================
RCS file: /cvs/src/sys/sys/conf.h,v
retrieving revision 1.119
diff -u -p -u -p -r1.119 conf.h
--- sys/conf.h 23 Aug 2012 06:12:49 -0000 1.119
+++ sys/conf.h 5 Mar 2013 15:16:09 -0000
@@ -509,6 +509,13 @@ extern struct cdevsw cdevsw[];
(dev_type_stop((*))) enodev, 0, selfalse, \
(dev_type_mmap((*))) enodev }

+/* open, close, read, write, poll, ioctl */
+#define cdev_fuse_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \
+ (dev_type_mmap((*))) enodev }
+
#endif

/*
@@ -657,6 +664,7 @@ cdev_decl(urio);
cdev_decl(hotplug);
cdev_decl(gpio);
cdev_decl(amdmsr);
+cdev_decl(fuse);

#endif

Index: sys/malloc.h
===================================================================
RCS file: /cvs/src/sys/sys/malloc.h,v
retrieving revision 1.101
diff -u -p -u -p -r1.101 malloc.h
--- sys/malloc.h 7 Feb 2013 11:06:42 -0000 1.101
+++ sys/malloc.h 5 Mar 2013 15:16:09 -0000
@@ -118,7 +118,8 @@
#define M_TTYS 62 /* allocated tty structures */
#define M_EXEC 63 /* argument lists & other mem used by exec */
#define M_MISCFSMNT 64 /* miscfs mount structures */
-/* 65-73 - free */
+#define M_FUSEFS 65 /* fusefs mount structures */
+/* 66-73 - free */
#define M_PFKEY 74 /* pfkey data */
#define M_TDB 75 /* Transforms database */
#define M_XDATA 76 /* IPsec data */
@@ -247,7 +248,7 @@
"ttys", /* 62 M_TTYS */ \
"exec", /* 63 M_EXEC */ \
"miscfs mount", /* 64 M_MISCFSMNT */ \
- NULL, \
+ "fusefs mount", /* 65 M_FUSEFS */ \
NULL, \
NULL, \
NULL, \
Index: sys/mount.h
===================================================================
RCS file: /cvs/src/sys/sys/mount.h,v
retrieving revision 1.108
diff -u -p -u -p -r1.108 mount.h
--- sys/mount.h 5 Sep 2012 17:01:06 -0000 1.108
+++ sys/mount.h 5 Mar 2013 15:16:09 -0000
@@ -258,6 +258,15 @@ struct procfs_args {
#define PROCFS_ARGSVERSION 1
#define PROCFSMNT_LINUXCOMPAT 0x01

+/*
+ * Arguments to mount fusefs filesystems
+ */
+struct fusefs_args {
+ char *name;
+ char *url;
+ int fd;
+ int flags;
+};

/*
* file system statistics
@@ -325,6 +334,7 @@ struct statfs {
#define MOUNT_NCPFS "ncpfs" /* NetWare Network File System */
#define MOUNT_NTFS "ntfs" /* NTFS */
#define MOUNT_UDF "udf" /* UDF */
+#define MOUNT_FUSEFS "fuse" /* FUSE */

/*
* Structure per mounted file system. Each mounted file system has an
Index: sys/vnode.h
===================================================================
RCS file: /cvs/src/sys/sys/vnode.h,v
retrieving revision 1.113
diff -u -p -u -p -r1.113 vnode.h
--- sys/vnode.h 8 Oct 2012 15:43:08 -0000 1.113
+++ sys/vnode.h 5 Mar 2013 15:16:09 -0000
@@ -71,13 +71,13 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCH
enum vtagtype {
VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS,
VT_PORTAL, VT_PROCFS, VT_AFS, VT_ISOFS, VT_ADOSFS,
- VT_EXT2FS, VT_VFS, VT_NTFS, VT_UDF,
+ VT_EXT2FS, VT_VFS, VT_NTFS, VT_UDF, VT_FUSEFS
};

#define VTAG_NAMES \
"NON", "UFS", "NFS", "MFS", "MSDOSFS", \
"PORTAL", "PROCFS", "AFS", "ISOFS", "ADOSFS", \
- "EXT2FS", "VFS", "NTFS", "UDF"
+ "EXT2FS", "VFS", "NTFS", "UDF", "FUSEFS"

/*
* Each underlying filesystem allocates its own private area and hangs

Sylvestre Gallon

unread,
Mar 5, 2013, 10:35:17 AM3/5/13
to
On Tue, Mar 5, 2013 at 4:29 PM, Sylvestre Gallon <ccna...@gmail.com> wrote:
>
> Martin,
>
> You will find inline the kernel patch
>

And here the userland :

Index: Makefile
===================================================================
RCS file: /cvs/src/sbin/Makefile,v
retrieving revision 1.97
diff -u -p -u -p -r1.97 Makefile
--- Makefile 23 Aug 2012 06:37:27 -0000 1.97
+++ Makefile 5 Mar 2013 15:21:12 -0000
@@ -5,7 +5,7 @@ SUBDIR= atactl badsect bioctl clri dhcli
fsck_msdos fsdb fsirand growfs ifconfig iked init iopctl ipsecctl \
isakmpd kbd ldattach lmccontrol mknod modload modunload mount \
mount_cd9660 mount_ext2fs mount_ffs mount_msdos \
- mount_nfs mount_ntfs mount_procfs mount_udf \
+ mount_nfs mount_ntfs mount_procfs mount_fusefs mount_udf \
mount_vnd mountd ncheck_ffs newfs newfs_ext2fs newfs_msdos \
nfsd nologin pdisk pfctl pflogd ping ping6 quotacheck \
reboot restore route rtsol savecore scan_ffs \
Index: mount_fusefs/Makefile
===================================================================
RCS file: mount_fusefs/Makefile
diff -N mount_fusefs/Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ mount_fusefs/Makefile 5 Mar 2013 15:21:18 -0000
@@ -0,0 +1,10 @@
+# $OpenBSD: src/sbin/mount_procfs/Makefile,v 1.7 2004/06/22
21:12:00 otto Exp $
+
+PROG= mount_fusefs
+SRCS= mount_fusefs.c getmntopts.c
+
+MOUNT= ${.CURDIR}/../mount
+CFLAGS+= -I${MOUNT}
+.PATH: ${MOUNT}
+
+.include <bsd.prog.mk>
Index: mount_fusefs/mount_fusefs.c
===================================================================
RCS file: mount_fusefs/mount_fusefs.c
diff -N mount_fusefs/mount_fusefs.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ mount_fusefs/mount_fusefs.c 5 Mar 2013 15:21:18 -0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mntopts.h"
+
+const struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ { "subtype", 0, MFLAG_SET | MFLAG_STRVAL | MFLAG_OPT },
+ { "fsname", 0, MFLAG_SET | MFLAG_STRVAL | MFLAG_OPT },
+ { NULL }
+};
+
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, mntflags, altflags;
+ struct fusefs_args args;
+ char path[MAXPATHLEN];
+
+ mntflags = altflags = 0;
+ while ((ch = getopt(argc, argv, "o:")) != -1)
+ switch (ch) {
+ case 'o':
+ altflags |= getmntopts(optarg, mopts, &mntflags);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ args.flags = altflags;
+ args.fd = atoi(argv[0]);
+
+ if (realpath(argv[1], path) == NULL)
+ err(1, "realpath %s", argv[1]);
+
+ if (mount(MOUNT_FUSEFS, path, mntflags, &args)) {
+ if (errno == EOPNOTSUPP)
+ errx(1, "%s: Filesystem not supported by kernel",
+ argv[1]);
+ else
+ err(1, "%s", argv[1]);
+ }
+ exit(0);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: mount_procfs [-o options] fd mount_point\n");
+ exit(1);
+}

Sylvestre Gallon

unread,
Mar 6, 2013, 4:27:09 PM3/6/13
to
Hi,

Martin suggested some ideas about my patches so I am sending you a new
inlined patch. This patch contains the following changes :

- code style changes
- I've fixed mount_fusefs usage() function
- By now I use DPRINTF for my debug messages
- I've got rid of curproc in vnops and vfsops.

Martin also told me that I could ask advises from vfs hackers about how
I can make a smarter patch. So here are my questions:

Do you know if miscfs is the best place to put my code ?
Do I keep the device code (fuse_device.c) in the same directory than the
filesystem code?
Do you know which fs type I can use in kern/vfs_init.c for fuse ? I've
taken 42 but I have no idea what I was doing when I choose this number :)

The things I will try to do during the next days are :

* Using a standard cfdriver/cfattach structure in fuse_device.c
* Writing a little documentation on the architecture of my fuse
implementation and on how the interaction between the vfs and the fuse
device works.
* Taking a look at bufq_* to replace my TAILQ_* fifos.
* Trying to use ufs_ihash* funcs instead of mine.11
* Fixing bugs

It could also be interesting for the people looking at my code to know
that I've looked on the FreeBSD fuse implementation instead of NetBSD.
And I've tried to be closer to that implementation than to Puffs. I was
thinking that copying the real fuse would be easier that copying the copy...

Here is the new src patch :

Index: sbin/Makefile
===================================================================
RCS file: /cvs/src/sbin/Makefile,v
retrieving revision 1.97
diff -u -p -r1.97 Makefile
--- sbin/Makefile 23 Aug 2012 06:37:27 -0000 1.97
+++ sbin/Makefile 6 Mar 2013 20:04:20 -0000
@@ -5,7 +5,7 @@ SUBDIR= atactl badsect bioctl clri dhcli
fsck_msdos fsdb fsirand growfs ifconfig iked init iopctl ipsecctl \
isakmpd kbd ldattach lmccontrol mknod modload modunload mount \
mount_cd9660 mount_ext2fs mount_ffs mount_msdos \
- mount_nfs mount_ntfs mount_procfs mount_udf \
+ mount_nfs mount_ntfs mount_procfs mount_fusefs mount_udf \
mount_vnd mountd ncheck_ffs newfs newfs_ext2fs newfs_msdos \
nfsd nologin pdisk pfctl pflogd ping ping6 quotacheck \
reboot restore route rtsol savecore scan_ffs \
Index: sbin/mount_fusefs/Makefile
===================================================================
RCS file: sbin/mount_fusefs/Makefile
diff -N sbin/mount_fusefs/Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sbin/mount_fusefs/Makefile 6 Mar 2013 20:04:21 -0000
@@ -0,0 +1,10 @@
+# $OpenBSD: src/sbin/mount_procfs/Makefile,v 1.7 2004/06/22 21:12:00
otto Exp $
+
+PROG= mount_fusefs
+SRCS= mount_fusefs.c getmntopts.c
+
+MOUNT= ${.CURDIR}/../mount
+CFLAGS+= -I${MOUNT}
+.PATH: ${MOUNT}
+
+.include <bsd.prog.mk>
Index: sbin/mount_fusefs/mount_fusefs.c
===================================================================
RCS file: sbin/mount_fusefs/mount_fusefs.c
diff -N sbin/mount_fusefs/mount_fusefs.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sbin/mount_fusefs/mount_fusefs.c 6 Mar 2013 20:04:21 -0000
+__dead void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: mount_fusefs [-o options] fd mount_point\n");
+ exit(1);
+}
Index: sys/arch/i386/i386/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/conf.c,v
retrieving revision 1.141
diff -u -p -r1.141 conf.c
--- sys/arch/i386/i386/conf.c 23 Aug 2012 06:12:49 -0000 1.141
+++ sys/arch/i386/i386/conf.c 6 Mar 2013 20:04:23 -0000
@@ -185,6 +185,7 @@ cdev_decl(pci);
#include "amdmsr.h"
#include "vscsi.h"
#include "pppx.h"
+#include "fuse.h"

struct cdevsw cdevsw[] =
{
@@ -293,6 +294,7 @@ struct cdevsw cdevsw[] =
cdev_vscsi_init(NVSCSI,vscsi), /* 90: vscsi */
cdev_disk_init(1,diskmap), /* 91: disk mapper */
cdev_pppx_init(NPPPX,pppx), /* 92: pppx */
+ cdev_fuse_init(NFUSE, fuse), /* 93: fuse */
};
int nchrdev = nitems(cdevsw);

Index: sys/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/conf/GENERIC,v
retrieving revision 1.194
diff -u -p -r1.194 GENERIC
--- sys/conf/GENERIC 1 Mar 2013 21:06:04 -0000 1.194
+++ sys/conf/GENERIC 6 Mar 2013 20:04:25 -0000
@@ -45,6 +45,7 @@ option NFSSERVER # Network File System
option CD9660 # ISO 9660 + Rock Ridge file system
option UDF # UDF (DVD) file system
option MSDOSFS # MS-DOS file system
+option FUSE # Userland file system
option FIFO # FIFOs; RECOMMENDED

option SOCKET_SPLICE # Socket Splicing for TCP
@@ -73,6 +74,8 @@ scsibus* at softraid?

vscsi0 at root # Userland backed Virtual SCSI
scsibus* at vscsi?
+
+pseudo-device fuse # filesystem in user land

pseudo-device pf # packet filter
pseudo-device pflog # pf log if
Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.540
diff -u -p -r1.540 files
--- sys/conf/files 21 Jan 2013 11:17:48 -0000 1.540
+++ sys/conf/files 6 Mar 2013 20:04:25 -0000
@@ -544,6 +544,15 @@ pseudo-device systrace
pseudo-device ksyms
file dev/ksyms.c ksyms needs-flag

+pseudo-device fuse
+file miscfs/fuse/fuse_device.c fuse needs-flag
+file miscfs/fuse/fuse_file.c fuse
+file miscfs/fuse/fuse_lookup.c fuse
+file miscfs/fuse/fuse_node.c fuse
+file miscfs/fuse/fuse_vfsops.c fuse
+file miscfs/fuse/fuse_vnops.c fuse
+file miscfs/fuse/fuse_subr.c fuse
+
pseudo-device pf: ifnet
file net/pf.c pf needs-flag
file net/pf_norm.c pf
Index: sys/kern/vfs_init.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_init.c,v
retrieving revision 1.30
diff -u -p -r1.30 vfs_init.c
--- sys/kern/vfs_init.c 23 Aug 2012 06:12:49 -0000 1.30
+++ sys/kern/vfs_init.c 6 Mar 2013 20:04:26 -0000
@@ -85,6 +85,10 @@ extern const struct vfsops ntfs_vfsops;
extern const struct vfsops udf_vfsops;
#endif

+#ifdef FUSE
+extern const struct vfsops fusefs_vfsops;
+#endif
+
/* Set up the filesystem operations for vnodes. */
static struct vfsconf vfsconflist[] = {
#ifdef FFS
@@ -121,6 +125,10 @@ static struct vfsconf vfsconflist[] = {

#ifdef UDF
{ &udf_vfsops, MOUNT_UDF, 13, 0, MNT_LOCAL, NULL },
+#endif
+
+#ifdef FUSE
+ { &fusefs_vfsops, MOUNT_FUSEFS, 42, 0, MNT_LOCAL, NULL }, /* put 42
as type, I don't know witch number I can use*/
#endif
};

Index: sys/miscfs/fuse/fuse_device.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_device.c
diff -N sys/miscfs/fuse/fuse_device.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_device.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEV_DEBUG
+#define DPRINTF(fmt, arg...) printf("fuse device: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+#else
+#define dump_buff(x, y)
+#endif
+
+void
+fuseattach(int num)
+{
+ DPRINTF("fuse attach\n");
+}
+
+int
+fuseopen(dev_t dev, int flags, int fmt, struct proc * p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV &&
+ fuse_devs[minor(dev)]->opened != FUSE_CLOSE)
+ return (ENXIO);
+
+ DPRINTF("open dev %i\n", minor(dev));
+
+ fuse_devs[minor(dev)] = malloc(sizeof(*fuse_devs[minor(dev)]),
+ M_FUSEFS, M_WAITOK | M_ZERO);
+ fuse_devs[minor(dev)]->opened = FUSE_OPEN;
+
+ return (0);
+}
+
+int
+fuseclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV)
+ return (ENXIO);
+
+ DPRINTF("close dev %i\n", minor(dev));
+
+ fuse_devs[minor(dev)]->opened = FUSE_CLOSE;
+ free(fuse_devs[minor(dev)], M_FUSEFS);
+ fuse_devs[minor(dev)] = NULL;
+ return (0);
+}
+
+int
+fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+{
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ DPRINTF("bad ioctl number %d\n", cmd);
+ return (ENODEV);
+ }
+
+ return (error);
+}
+
+int
+fuseread(dev_t dev, struct uio *uio, int ioflag)
+{
+ int error = 0;
+ struct fuse_msg *msg;
+
+ DPRINTF("read 0x%x\n", dev);
+
+
+ if (fuse_devs[minor(dev)]->opened != FUSE_OPEN) {
+ return (ENODEV);
+ }
+
+again:
+ if (TAILQ_EMPTY(&fmq_in)) {
+
+ if (ioflag & O_NONBLOCK) {
+ return (EAGAIN);
+ }
+
+ error = tsleep(&fmq_in, PWAIT, "fuse read", 0);
+
+ if (error)
+ return (error);
+ }
+ if (TAILQ_EMPTY(&fmq_in))
+ goto again;
+
+ if (!TAILQ_EMPTY(&fmq_in)) {
+ msg = TAILQ_FIRST(&fmq_in);
+
+ if (msg->hdr->opcode == FUSE_DESTROY) {
+ DPRINTF("catch done\n");
+ fuse_devs[minor(dev)]->opened = FUSE_DONE;
+ }
+
+ error = uiomove(msg->hdr, sizeof(struct fuse_in_header), uio);
+
+ DPRINTF("hdr r:\n");
+ dump_buff((char *)msg->hdr, sizeof(struct fuse_in_header));
+
+ if (msg->len > 0) {
+ error = uiomove(msg->data, msg->len, uio);
+ DPRINTF("data r:\n");
+ dump_buff(msg->data, msg->len);
+ }
+
+ DPRINTF("msg send : %i\n", msg->len);
+
+ if (error) {
+ DPRINTF("error: %i\n", error);
+ return (error);
+ }
+
+ /*
+ * msg moves from a tailq to another
+ */
+ TAILQ_REMOVE(&fmq_in, msg, node);
+ TAILQ_INSERT_TAIL(&fmq_wait, msg, node);
+ }
+
+ return (error);
+}
+
+int
+fusewrite(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct fuse_out_header hdr;
+ struct fuse_msg *msg;
+ int error = 0;
+ int caught = 0;
+ int len;
+ void *data;
+
+ DPRINTF("write %x bytes\n", uio->uio_resid);
+
+ if (uio->uio_resid < sizeof(struct fuse_out_header)) {
+ DPRINTF("uio goes wrong\n");
+ return (EINVAL);
+ }
+
+ /*
+ * get out header
+ */
+
+ if ((error = uiomove(&hdr, sizeof(struct fuse_out_header), uio)) !=
0) {
+ DPRINTF("uiomove failed\n");
+ return (error);
+ }
+ DPRINTF("hdr w:\n");
+ dump_buff((char *)&hdr, sizeof(struct fuse_out_header));
+
+ /*
+ * check header validity
+ */
+ if (uio->uio_resid + sizeof(struct fuse_out_header) != hdr.len ||
+ (uio->uio_resid && hdr.error) || TAILQ_EMPTY(&fmq_wait) ) {
+ DPRINTF("corrupted fuse header or queue empty\n");
+ return (EINVAL);
+ }
+
+ /* fuse errno are negative */
+ if (hdr.error)
+ hdr.error = -(hdr.error);
+
+ TAILQ_FOREACH(msg, &fmq_wait, node) {
+ if (msg->hdr->unique == hdr.unique) {
+ DPRINTF("catch unique %i\n", msg->hdr->unique);
+ caught = 1;
+ break;
+ }
+ }
+
+ if (caught) {
+ if (uio->uio_resid > 0) {
+ len = uio->uio_resid;
+ data = malloc(len, M_FUSEFS, M_WAITOK);
+ error = uiomove(data, len, uio);
+
+ DPRINTF("data w:\n");
+ dump_buff(data, len);
+ } else {
+ data = NULL;
+ }
+
+ DPRINTF("call callback\n");
+
+ if (!error)
+ msg->cb(msg, &hdr, data);
+
+ TAILQ_REMOVE(&fmq_wait, msg, node);
+
+ if (msg->type == msg_buff_async) {
+ free(msg->hdr, M_FUSEFS);
+ free(msg, M_FUSEFS);
+
+ if (data)
+ free(data, M_FUSEFS);
+ }
+
+ } else {
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+int
+fusepoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0;
+
+ DPRINTF("fuse poll\n");
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (!TAILQ_EMPTY(&fmq_in))
+ revents |= events & (POLLIN | POLLRDNORM);
+ }
+
+ if (events & (POLLOUT | POLLWRNORM))
+ revents |= events & (POLLOUT | POLLWRNORM);
+
+ return (revents);
+}
Index: sys/miscfs/fuse/fuse_file.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_file.c
diff -N sys/miscfs/fuse/fuse_file.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_file.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEV_DEBUG
+#define DPRINTF(fmt, arg...) printf("fuse vnop: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+
+int
+fuse_file_open(struct fuse_mnt *fmp, struct fuse_node *ip,
+ enum fufh_type fufh_type, int flags, int isdir, struct proc *p)
+{
+ struct fuse_open_out *open_out;
+ struct fuse_open_in open_in;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.data = &open_in;
+ msg.len = sizeof(open_in);
+ msg.cb = &fuse_sync_resp;
+ msg.fmp = fmp;
+ msg.type = msg_buff;
+
+ open_in.flags = flags;
+ open_in.mode = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*open_out);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len,
+ ((isdir) ? FUSE_OPENDIR : FUSE_OPEN), ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse open", 0);
+
+ if (error)
+ return (error);
+
+ open_out = (struct fuse_open_out *)msg.rep.buff.data_rcv;
+
+ ip->fufh[fufh_type].fh_id = open_out->fh;
+ ip->fufh[fufh_type].fh_type = fufh_type;
+
+ free(open_out, M_FUSEFS);
+
+ return (0);
+}
+
+int
+fuse_file_close(struct fuse_mnt *fmp, struct fuse_node * ip,
+ enum fufh_type fufh_type, int flags, int isdir, struct proc *p)
+{
+ struct fuse_release_in rel;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ bzero(&rel, sizeof(rel));
+ msg.hdr = &hdr;
+ msg.data = &rel;
+ msg.len = sizeof(rel);
+ msg.cb = &fuse_sync_it;
+ msg.fmp = fmp;
+ msg.type = msg_intr;
+
+ rel.fh = ip->fufh[fufh_type].fh_id;
+ rel.flags = flags;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len,
+ ((isdir) ? FUSE_RELEASEDIR : FUSE_RELEASE), ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse close", 0);
+
+ if (error)
+ return (error);
+
+ error = msg.rep.it_res;
+ if (error)
+ printf("fuse file error %d\n", error);
+
+ ip->fufh[fufh_type].fh_id = (uint64_t)-1;
+ ip->fufh[fufh_type].fh_type = FUFH_INVALID;
+
+ return (error);
+}
Index: sys/miscfs/fuse/fuse_kernel.h
===================================================================
RCS file: sys/miscfs/fuse/fuse_kernel.h
diff -N sys/miscfs/fuse/fuse_kernel.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_kernel.h 6 Mar 2013 20:04:26 -0000
Index: sys/miscfs/fuse/fuse_lookup.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_lookup.c
diff -N sys/miscfs/fuse/fuse_lookup.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_lookup.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEBUG_VNOP
+#define DPRINTF(fmt, arg...) printf("fuse vnop: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+extern int fusefs_lookup(void *);
+
+int
+fusefs_lookup(void *v)
+{
+ struct vop_lookup_args *ap = v;
+ struct vnode *vdp; /* vnode for directory being searched */
+ struct fuse_node *dp; /* inode for directory being searched */
+ struct fuse_mnt *fmp; /* file system that directory is in */
+ int lockparent; /* 1 => lockparent flag is set */
+ struct vnode *tdp; /* returned by VOP_VGET */
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+ struct ucred *cred = cnp->cn_cred;
+ struct fuse_entry_out *feo = NULL;
+ int flags;
+ int nameiop = cnp->cn_nameiop;
+ /*struct proc *p = cnp->cn_proc;*/
+ int error = 0;
+ uint64_t nid;
+
+ flags = cnp->cn_flags;
+ *vpp = NULL;
+ vdp = ap->a_dvp;
+ dp = VTOI(vdp);
+ fmp = dp->i_mnt;
+ lockparent = flags & LOCKPARENT;
+
+ DPRINTF("lookup path %s\n", cnp->cn_pnbuf);
+ DPRINTF("lookup file %s\n", cnp->cn_nameptr);
+
+ if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
+ return (error);
+
+ if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
+
+ if (flags & ISDOTDOT) {
+ /* got ".." */
+ nid = dp->parent;
+ if (nid == 0) {
+ return (ENOENT);
+ }
+ } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
+ /* got "." */
+ nid = dp->i_number;
+ } else {
+ /* got a real entry */
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LOOKUP,
+ dp->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse lookup", 0);
+
+ if (error)
+ return (error);
+
+ if (msg.error) {
+ if ((nameiop == CREATE || nameiop == RENAME) &&
+ (flags & ISLASTCN) ) {
+ if (vdp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
+ cnp->cn_flags |= SAVENAME;
+
+ if (!lockparent) {
+ VOP_UNLOCK(vdp, 0, p);
+ DPRINTF("lookup for ..\n");
+ VOP_UNLOCK(vdp, 0, p); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
+
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (error) {
+ if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
+
+ return (error);
+ }
+
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(vdp, LK_EXCLUSIVE, p))) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ *vpp = tdp;
+
+ } else if (nid == dp->i_number) {
+ vref(vdp);
+ *vpp = vdp;
+ error = 0;
+ } else {
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (!error) {
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+ }
+
+ fuse_internal_attr_fat2vat(fmp->mp, &feo->attr,
+ &(VTOI(tdp)->cached_attrs));
+ free(feo, M_FUSEFS);
+
+ if (error)
+ return (error);
+
+ if (vdp != NULL && vdp->v_type == VDIR) {
+ VTOI(tdp)->parent = dp->i_number;
+ }
+ if (!lockparent || !(flags & ISLASTCN)) {
+ VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+
+ *vpp = tdp;
+ }
+
+out:
+ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE &&
+ nameiop != DELETE )
+ cache_enter(vdp, *vpp, cnp);
+
+ return (error);
+}
Index: sys/miscfs/fuse/fuse_node.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_node.c
diff -N sys/miscfs/fuse/fuse_node.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_node.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+LIST_HEAD(ihashhead, fuse_node) *fhashtbl;
+u_long fhash; /* size of hash table - 1 */
+#define INOHASH(fd, inum) (&fhashtbl[((fd) + (inum)) & fhash])
+
+void
+fusefs_ihashinit(void)
+{
+ fhashtbl = hashinit(desiredvnodes, M_FUSEFS, M_WAITOK, &fhash);
+}
+
Index: sys/miscfs/fuse/fuse_node.h
===================================================================
RCS file: sys/miscfs/fuse/fuse_node.h
diff -N sys/miscfs/fuse/fuse_node.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_node.h 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSE_NODE_H__
+#define __FUSE_NODE_H__
+
+enum fufh_type {
+ FUFH_INVALID = -1,
+ FUFH_RDONLY = 0,
+ FUFH_WRONLY = 1,
+ FUFH_RDWR = 2,
+ FUFH_MAXTYPE = 3,
+};
+
+struct fuse_filehandle {
+ uint64_t fh_id;
+ enum fufh_type fh_type;
+};
+
+struct fuse_node {
+ LIST_ENTRY(fuse_node) i_hash; /* Hash chain */
+ struct vnode *i_vnode; /* vnode associated with this inode */
+ struct lockf *i_lockf; /* Head of byte-level lock list. */
+ struct lock i_lock; /* node lock */
+ ino_t i_number; /* the identity of the inode */
+ int i_fd; /* fd of fuse session */
+
+ struct fuse_mnt *i_mnt; /* fs associated with this inode */
+ uint64_t parent;
+
+ /** I/O **/
+ struct fuse_filehandle fufh[FUFH_MAXTYPE];
+
+ /** flags **/
+ uint32_t flag;
+
+ /** meta **/
+ struct vattr cached_attrs;
+ off_t filesize;
+ uint64_t nlookup;
+ enum vtype vtype;
+};
+
+extern struct fuse_node **fusehashtbl;
+extern u_long fusehash;
+
+void fusefs_ihashinit(void);
+struct vnode *fusefs_ihashget(int, ino_t);
+int fusefs_ihashins(struct fuse_node *);
+void fusefs_ihashrem(struct fuse_node *);
+#define ITOV(ip) ((ip)->i_vnode)
+#define VTOI(vp) ((struct fuse_node *)(vp)->v_data)
+
+#endif /* __FUSE_NODE_H__ */
Index: sys/miscfs/fuse/fuse_subr.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_subr.c
diff -N sys/miscfs/fuse/fuse_subr.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_subr.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEBUG_MSG
+#define DPRINTF(fmt, arg...) printf("fuse ipc: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+void
+fuse_make_in(struct mount *mp, struct fuse_in_header *hdr, int len,
+ enum fuse_opcode op, ino_t ino, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+
+ fmp = VFSTOFUSEFS(mp);
+ fmp->unique++;
+
+ hdr->len = sizeof(*hdr) + len;
+ hdr->opcode = op;
+ hdr->nodeid = ino;
+ hdr->unique = fmp->unique;
+
+ DPRINTF("create unique %i\n", hdr->unique);
+
+ if (!p) {
+ hdr->pid = curproc->p_pid;
+ hdr->uid = 0;
+ hdr->gid = 0;
+ } else {
+ hdr->pid = p->p_pid;
+ hdr->uid = p->p_cred->p_ruid;
+ hdr->gid = p->p_cred->p_rgid;
+ }
+}
+
+void
+fuse_init_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void
*data)
+{
+ struct fuse_init_out *out = data;
+
+ DPRINTF("async init unique %i\n", msg->hdr->unique);
+ DPRINTF("init_out flags %i\n", out->flags);
+ DPRINTF("init_out major %i\n", out->major);
+ DPRINTF("init_out minor %i\n", out->minor);
+ DPRINTF("init_out max_readahead %i\n", out->max_readahead);
+ DPRINTF("init_out max_write %i\n", out->max_write);
+ DPRINTF("init_out unused %i\n", out->unused);
+
+ msg->fmp->sess_init = 1;
+ msg->fmp->max_write = out->max_readahead;
+}
+
+void
+fuse_sync_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void
*data)
+{
+ size_t len;
+
+ DPRINTF("unique %i\n", msg->hdr->unique);
+
+ if (msg->type != msg_buff)
+ DPRINTF("bad msg type\n");
+
+ if (data != NULL && msg->rep.buff.len != 0) {
+ len = hdr->len - sizeof(*hdr);
+ if (msg->rep.buff.len != len) {
+ DPRINTF("fusefs: packet size error on opcode %i\n",
+ msg->hdr->opcode);
+ }
+
+ if (msg->rep.buff.len > len)
+ printf("unused byte : 0x%x\n", msg->rep.buff.len - len);
+
+ msg->rep.buff.data_rcv = malloc(msg->rep.buff.len, M_FUSEFS,
+ M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, msg->rep.buff.len);
+
+ wakeup(msg);
+
+ } else if (data != NULL) {
+ len = hdr->len - sizeof(*hdr);
+ msg->rep.buff.data_rcv = malloc(len, M_FUSEFS,
+ M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, len);
+ msg->rep.buff.len = len;
+
+ wakeup(msg);
+ } else if (hdr->error) {
+ msg->error = hdr->error;
+ DPRINTF("error %i\n", msg->error);
+ wakeup(msg);
+ } else {
+ msg->error = -1;
+ DPRINTF("ack for msg\n");
+ wakeup(msg);
+ }
+}
+
+void
+fuse_sync_it(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+ DPRINTF("unique %i\n", msg->hdr->unique);
+
+ if (msg->type != msg_intr)
+ printf("bad msg type\n");
+
+ if (data != NULL)
+ printf("normally data should be Null\n");
+
+ msg->rep.it_res = hdr->error;
+ DPRINTF("errno = %d\n", msg->rep.it_res);
+ wakeup(msg);
+}
Index: sys/miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_vfsops.c
diff -N sys/miscfs/fuse/fuse_vfsops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_vfsops.c 6 Mar 2013 20:04:26 -0000
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEBUG_VFS
+#define DPRINTF(fmt, arg...) printf("fuse vfsop: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+int fusefs_mount(struct mount *, const char *, void *, struct
nameidata *,
+ struct proc *);
+int fusefs_start(struct mount *, int, struct proc *);
+int fusefs_unmount(struct mount *, int, struct proc *);
+int fusefs_root(struct mount *, struct vnode **);
+int fusefs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
+int fusefs_statfs(struct mount *, struct statfs *, struct proc *);
+int fusefs_sync(struct mount *, int, struct ucred *, struct proc *);
+int fusefs_vget(struct mount *, ino_t, struct vnode **);
+int fusefs_fhtovp(struct mount *, struct fid *, struct vnode **);
+int fusefs_vptofh(struct vnode *, struct fid *);
+int fusefs_init(struct vfsconf *);
+int fusefs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
+ struct proc *);
+int fusefs_checkexp(struct mount *, struct mbuf *, int *,
+ struct ucred **);
+
+const struct vfsops fusefs_vfsops = {
+ fusefs_mount,
+ fusefs_start,
+ fusefs_unmount,
+ fusefs_root,
+ fusefs_quotactl,
+ fusefs_statfs,
+ fusefs_sync,
+ fusefs_vget,
+ fusefs_fhtovp,
+ fusefs_vptofh,
+ fusefs_init,
+ fusefs_sysctl,
+ fusefs_checkexp
+};
+
+int
+fusefs_mount(struct mount *mp, const char *path, void *data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_msg *msg;
+ struct fuse_init_in *init;
+ struct fusefs_args args;
+ int error;
+
+ DPRINTF("mount\n");
+
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
+
+ error = copyin(data, &args, sizeof(struct fusefs_args));
+ if (error)
+ return (error);
+
+ DPRINTF("fd = %d\n", args.fd);
+
+ fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
+ fmp->mp = mp;
+ fmp->sess_init = 0;
+ fmp->unique = 0;
+ fmp->fd = args.fd;
+ mp->mnt_data = (qaddr_t)fmp;
+
+ mp->mnt_flag |= MNT_LOCAL;
+ vfs_getnewfsid(mp);
+
+ bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
+ strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
+ bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
+ bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
+
+ msg = malloc(sizeof(struct fuse_msg), M_FUSEFS, M_WAITOK | M_ZERO);
+ msg->hdr = malloc(sizeof(struct fuse_in_header), M_FUSEFS,
+ M_WAITOK | M_ZERO);
+ init = malloc(sizeof(struct fuse_init_in), M_FUSEFS, M_WAITOK |
M_ZERO);
+
+ init->major = FUSE_KERNEL_VERSION;
+ init->minor = FUSE_KERNEL_MINOR_VERSION;
+ init->max_readahead = 4096 * 16;
+ init->flags = 0;
+ msg->data = init;
+ msg->len = sizeof(*init);
+ msg->cb = &fuse_init_resp;
+ msg->fmp = fmp;
+ msg->type = msg_buff_async;
+
+ fuse_make_in(mp, msg->hdr, msg->len, FUSE_INIT, 0, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, msg, node);
+ wakeup(&fmq_in);
+
+ return (0);
+}
+
+int
+fusefs_start(struct mount *mp, int flags, struct proc *p)
+{
+ DPRINTF("start\n");
+ return (0);
+}
+
+int
+fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ extern int doforce;
+ struct fuse_msg *m;
+ int flags = 0;
+ int error;
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (!fmp->sess_init)
+ return (0);
+
+ fmp->sess_init = 0;
+
+ DPRINTF("unmount\n");
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.type = msg_intr;
+ msg.data = NULL;
+ msg.cb = &fuse_sync_it;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_DESTROY, 0, p);
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse unmount", 0);
+
+ if (error)
+ return (error);
+
+ error = msg.rep.it_res;
+
+ if (error)
+ DPRINTF("error from fuse\n");
+
+ /* clear FIFO IN*/
+ while ((m = TAILQ_FIRST(&fmq_in))) {
+ DPRINTF("warning some msg where not processed....\n");
+ }
+
+ /* clear FIFO WAIT*/
+ while ((m = TAILQ_FIRST(&fmq_wait))) {
+ DPRINTF("warning some msg where not processed....\n");
+ }
+
+ if (mntflags & MNT_FORCE) {
+ /* fusefs can never be rootfs so don't check for it */
+ if (!doforce)
+ return (EINVAL);
+ flags |= FORCECLOSE;
+ }
+
+ if ((error = vflush(mp, 0, flags)))
+ return (error);
+
+ free(fmp, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_root(struct mount *mp, struct vnode **vpp)
+{
+ struct vnode *nvp;
+ struct fuse_node *ip;
+ int error;
+
+ DPRINTF("root\n");
+
+ if ((error = VFS_VGET(mp, (ino_t)FUSE_ROOTINO, &nvp)) != 0)
+ return (error);
+
+ ip = VTOI(nvp);
+ nvp->v_type = VDIR;
+ ip->vtype = VDIR;
+
+ *vpp = nvp;
+ return (0);
+}
+
+int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
+ struct proc *p)
+{
+ DPRINTF("quotactl\n");
+ return (0);
+}
+
+int fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
+{
+ struct fuse_statfs_out *stat;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+ DPRINTF("statfs\n");
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (fmp->sess_init) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*stat);
+ msg.cb = &fuse_sync_resp;
+ msg.type = msg_buff;
+
+ fuse_make_in(mp, msg.hdr, msg.len, FUSE_STATFS, FUSE_ROOT_ID,
+ NULL);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse stat", 0);
+ if (error) {
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ stat = (struct fuse_statfs_out *)msg.rep.buff.data_rcv;
+
+ DPRINTF("statfs a: %i\n", stat->st.bavail);
+ DPRINTF("statfs a: %i\n", stat->st.bfree);
+ DPRINTF("statfs a: %i\n", stat->st.blocks);
+ DPRINTF("statfs a: %i\n", stat->st.bsize);
+ DPRINTF("statfs a: %i\n", stat->st.ffree);
+ DPRINTF("statfs a: %i\n", stat->st.files);
+ DPRINTF("statfs a: %i\n", stat->st.frsize);
+ DPRINTF("statfs a: %i\n", stat->st.namelen);
+ DPRINTF("statfs a: %i\n", stat->st.padding);
+ DPRINTF("sync\n");
+ return (0);
+}
+
+int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct vnode *nvp;
+ int i;
+ int error;
+
+ DPRINTF("vget\n");
+
+retry:
+ fmp = VFSTOFUSEFS(mp);
+ /*
+ * check if vnode is in hash.
+ */
+ if ((*vpp = fusefs_ihashget(fmp->fd, ino)) != NULLVP)
+ return (0);
+
+ /*
+ * if not create it
+ */
+ if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
+ DPRINTF("getnewvnode error\n");
+ DPRINTF("fhtovp\n");
+ return (0);
+}
+
+int fusefs_vptofh(struct vnode *vp, struct fid *fhp)
+{
+ DPRINTF("vptofh\n");
+ return (0);
+}
+
+int fusefs_init(struct vfsconf *vfc)
+{
+ DPRINTF("init\n");
+
+ TAILQ_INIT(&fmq_in);
+ TAILQ_INIT(&fmq_wait);
+
+ fusefs_ihashinit();
+ return (0);
+}
+
+int fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplen,
+ void *newp, size_t newlen, struct proc *p)
+{
+ DPRINTF("sysctl\n");
+ return (0);
+}
+
+int fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
+ struct ucred **credanonp)
+{
+ DPRINTF("checkexp\n");
+ return (0);
+}
Index: sys/miscfs/fuse/fuse_vnops.c
===================================================================
RCS file: sys/miscfs/fuse/fuse_vnops.c
diff -N sys/miscfs/fuse/fuse_vnops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fuse_vnops.c 6 Mar 2013 20:04:27 -0000
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#include <sys/specdev.h>
+#include <sys/poll.h>
+#include <sys/lockf.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+#ifdef FUSE_DEBUG_VNOP
+#define DPRINTF(fmt, arg...) printf("fuse vnop: " fmt, ##arg)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+
+/*
+ DPRINTF("fusefs_open\n");
+
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+ DPRINTF("inode = %i mode=0x%x\n", ip->i_number, ap->a_mode);
+
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ isdir = 1;
+ } else {
+ if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) {
+ fufh_type = FUFH_RDWR;
+ flags = O_RDWR;
+ }
+ else if (ap->a_mode & (FWRITE)) {
+ fufh_type = FUFH_WRONLY;
+ flags = O_WRONLY;
+ }
+ else if (ap->a_mode & (FREAD)) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ }
+ }
+
+ /* already open i think all is ok */
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return (0);
+
+ error = fuse_file_open(fmp, ip, fufh_type, flags, isdir, ap->a_p);
+
+ if (error)
+ return (error);
+
+ DPRINTF("file open fd : %i\n", ip->fufh[fufh_type].fh_id);
+
+ return (error);
+}
+
+int
+fusefs_close(void *v)
+{
+ struct vop_close_args *ap;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ enum fufh_type fufh_type;
+ int isdir, flags, i;
+
+ DPRINTF("fusefs_close\n");
+
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ isdir = 1;
+
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return (fuse_file_close(fmp, ip, fufh_type, O_RDONLY,
+ isdir, ap->a_p));
+ struct proc *p;
+ uint32_t mask = 0;
+ int error = 0;
+
+ DPRINTF("fusefs_access\n");
+
+ ap = v;
+ p = ap->a_p;
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_ACCESS, ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse access", 0);
+
+ if (error)
+ return (error);
+
+ DPRINTF("it with value %x\n", msg.rep.it_res);
+ error = msg.rep.it_res;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_ACCESS;
+ goto system_check;
+ }
+
+ return (error);
+
+system_check:
+ DPRINTF("Use kernel access\n");
+
+ return (vaccess(ap->a_vp->v_type, ip->cached_attrs.va_mode & ALLPERMS,
+ ip->cached_attrs.va_uid, ip->cached_attrs.va_gid, ap->a_mode,
+ ap->a_cred));
+}
+
+int
+fusefs_getattr(void *v)
+{
+ struct vop_getattr_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_mnt *fmp;
+ struct vattr *vap = ap->a_vap;
+ struct proc *p = ap->a_p;
+ struct fuse_in_header hdr;
+ struct fuse_attr_out *fat;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+ DPRINTF("fusefs_getattr\n");
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ goto fake;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.len = sizeof(*fat);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_GETATTR, ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.data_rcv != NULL)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ fat = (struct fuse_attr_out *)msg.rep.buff.data_rcv;
+
+ DPRINTF("ino: %d\n", fat->attr.ino);
+ DPRINTF("size: %d\n", fat->attr.size);
+ DPRINTF("blocks: %d\n", fat->attr.blocks);
+ DPRINTF("atime: %d\n", fat->attr.atime);
+ DPRINTF("mtime: %d\n", fat->attr.mtime);
+ DPRINTF("ctime: %d\n", fat->attr.ctime);
+ DPRINTF("atimensec: %d\n", fat->attr.atimensec);
+ DPRINTF("mtimensec: %d\n", fat->attr.mtimensec);
+ DPRINTF("ctimensec: %d\n", fat->attr.ctimensec);
+ DPRINTF("mode: %d\n", fat->attr.mode);
+ DPRINTF("nlink: %d\n", fat->attr.nlink);
+ DPRINTF("uid: %d\n", fat->attr.uid);
+ DPRINTF("gid: %d\n", fat->attr.gid);
+ DPRINTF("rdev: %d\n", fat->attr.rdev);
+
+ fuse_internal_attr_fat2vat(fmp->mp, &fat->attr, vap);
+
+ memcpy(&ip->cached_attrs, vap, sizeof(*vap));
+ free(fat, M_FUSEFS);
+
+ return (error);
+fake:
+ bzero(vap, sizeof(*vap));
+ vap->va_type = vp->v_type;
+ return (0);
+}
+
+int
+fusefs_setattr(void *v)
+{
+ DPRINTF("fusefs_setattr\n");
+ return (0);
+}
+
+int
+fusefs_ioctl(void *v)
+{
+ DPRINTF("fusefs_ioctl\n");
+ return (ENOTTY);
+}
+
+int
+fusefs_link(void *v)
+{
+ struct vop_link_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_link_in fli;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+ DPRINTF("fusefs_link\n");
+
+ if (vp->v_type == VDIR) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EISDIR;
+ goto out2;
+ }
+ if (dvp->v_mount != vp->v_mount) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EXDEV;
+ goto out2;
+ }
+ if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
+ VOP_ABORTOP(dvp, cnp);
+ goto out2;
+ }
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_LINK))
+ goto out1;
+
+ fli.oldnodeid = ip->i_number;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fli);
+ msg.data = &fli;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LINK, ip->i_number, p);
+ VOP_UNLOCK(vp, 0, p);
+out2:
+ vput(dvp);
+ return (error);
+}
+
+int
+fusefs_symlink(void *v)
+{
+ DPRINTF("fusefs_symlink\n");
+ return (0);
+}
+
+#define GENERIC_DIRSIZ(dp) \
+ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3)
&~ 3))
+
+
+int
+readdir_process_data(void *buff, int len, struct uio *uio)
+{
+ struct fuse_dirent *fdir;
+ struct dirent dir;
+ int bytes;
+ int flen, error = 0;
+
+ if (len < FUSE_NAME_OFFSET) {
+ return (0);
+ }
+
+ while ( len > 0) {
+ if ( len < sizeof(*fdir)) {
+ error = 0;
+ break;
+ }
+
+ fdir = (struct fuse_dirent *)buff;
+ flen = FUSE_DIRENT_SIZE(fdir);
+
+ if (!fdir->namelen || fdir->namelen > MAXNAMLEN || len < flen) {
+ error = EINVAL;
+ break;
+ }
+
+ bytes = GENERIC_DIRSIZ((struct pseudo_dirent *) &fdir->namelen);
+ if (bytes > uio->uio_resid) {
+ error = 0;
+ break;
+ }
+
+ bzero(&dir, sizeof(dir));
+ dir.d_fileno = fdir->ino;
+ dir.d_reclen = bytes;
+ dir.d_type = fdir->type;
+ dir.d_namlen = fdir->namelen;
+ bcopy(fdir->name, dir.d_name, fdir->namelen);
+
+ uiomove(&dir, bytes , uio);
+ len -= flen;
+ /* ugly pointer arithmetic must find something else ...*/
+ buff = (void *)(((char *) buff) + flen);
+ uio->uio_offset = fdir->off;
+ }
+
+ return (error);
+}
+
+int
+fusefs_readdir(void *v)
+{
+ struct vop_readdir_args *ap = v;
+ struct fuse_read_in read;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct vnode *vp;
+ struct proc *p;
+ struct uio *uio;
+ int error = 0;
+
+ vp = ap->a_vp;
+ uio = ap->a_uio;
+ p = uio->uio_procp;
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+ DPRINTF("fusefs_readdir\n");
+ DPRINTF("uio resid 0x%x\n", uio->uio_resid);
+
+ if (uio->uio_resid == 0)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(read);
+ msg.type = msg_buff;
+
+ msg.rep.buff.len= 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.data = &read;
+ msg.cb = &fuse_sync_resp;
+
+ if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) {
+ DPRINTF("dir not open\n");
+ /* TODO open the file */
+ return (error);
+ }
+ read.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ read.offset = uio->uio_offset;
+ read.size = MIN(uio->uio_resid, PAGE_SIZE);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READDIR,
+ ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ if (msg.error == -1) {
+ //ack for end of readdir
+ break;
+ }
+
+ if ((error = readdir_process_data(msg.rep.buff.data_rcv,
+ msg.rep.buff.len, uio))) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ break;
+ }
+
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ }
+
+ return (error);
+}
+
+int
+fusefs_inactive(void *v)
+{
+ struct vop_inactive_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ register struct fuse_node *ip = VTOI(vp);
+ int error = 0;
+
+ DPRINTF("fusefs_inactive\n");
+
+ ip->flag = 0;
+ VOP_UNLOCK(vp, 0, p);
+
+ /* not sure if it is ok to do like that ...*/
+ if (ip->cached_attrs.va_mode == 0)
+ vrecycle(vp, p);
+
+ return (error);
+}
+
+int
+fusefs_readlink(void *v)
+{
+ struct vop_readlink_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct uio *uio;
+ struct proc *p;
+ int error = 0;
+
+ DPRINTF("fusefs_readlink\n");
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+ uio = ap->a_uio;
+ p = uio->uio_procp;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_READLINK)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READLINK, ip->i_number,
+ p);
+ DPRINTF("fusefs_reclaim\n");
+
+ /*
+ struct proc *p = cnp->cn_proc;
+ struct fuse_entry_out *feo;
+ struct fuse_in_header hdr;
+ struct vnode *tdp = NULL;
+ struct fuse_open_in foi;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+ mode_t mode;
+
+ DPRINTF("fusefs_create(cnp %08x, vap %08x\n", cnp, vap);
+
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_CREATE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(foi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out) +
+ sizeof(struct fuse_open_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ foi.mode = mode;
+ foi.flags = O_CREAT | O_RDWR;
+
+ memcpy(msg.data, &foi, sizeof(foi));
+ memcpy((char *)msg.data + sizeof(foi), cnp->cn_nameptr,
+ cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(foi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_CREATE, ip->i_number, p);
+ struct proc *p = uio->uio_procp;
+ struct fuse_in_header hdr;
+ struct fuse_read_in fri;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error=0;
+
+ DPRINTF("fusefs_read\n");
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ DPRINTF("read inode=%i, offset=%%llu, resid=%x\n", ip->i_number,
+ uio->uio_offset, uio->uio_resid);
+
+ if (uio->uio_resid == 0)
+ return (error);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fri);
+ msg.data = &fri;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fri.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ fri.offset = uio->uio_offset;
+ fri.size = MIN(uio->uio_resid, fmp->max_write);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READ,
+ ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse read", 0)))
+ break;
+
+ if (msg.error) {
+ DPRINTF("read error %i\n", msg.error);
+ }
+
+ if ((error = uiomove(msg.rep.buff.data_rcv,
+ MIN(fri.size, msg.rep.buff.len), uio))) {
+ break;
+ }
+
+ if (msg.rep.buff.len < fri.size)
+ break;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_write(void *v)
+{
+ struct vop_write_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
+ struct fuse_in_header hdr;
+ struct fuse_write_in *fwi;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ size_t len, diff;
+ int error=0;
+
+ DPRINTF("fusefs_write\n");
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ DPRINTF("write inode=%i, offset=%llu, resid=%x\n", ip->i_number,
+ uio->uio_offset, uio->uio_resid);
+
+ if (uio->uio_resid == 0)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ len = MIN(uio->uio_resid, fmp->max_write);
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(*fwi) + len;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_write_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fwi = (struct fuse_write_in *)msg.data;
+ fwi->fh = ip->fufh[FUFH_WRONLY].fh_id;
+ fwi->offset = uio->uio_offset;
+ fwi->size = len;
+
+ if ((error = uiomove((char *)msg.data + sizeof(*fwi), len,
+ uio))) {
+ DPRINTF("uio error %i", error);
+ break;
+ }
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_WRITE,
+ ip->i_number, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse write", 0)))
+ break;
+
+ if (msg.error) {
+ DPRINTF("write error %i\n", msg.error);
+ }
+
+ diff = len -
+ ((struct fuse_write_out *)msg.rep.buff.data_rcv)->size;
+ if (diff < 0) {
+ error = EINVAL;
+ break;
+ }
+
+ uio->uio_resid += diff;
+ uio->uio_offset -= diff;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_poll(void *v)
+{
+ struct vop_poll_args *ap = v;
+
+ DPRINTF("fusefs_poll\n");
+
+ /*
+ * We should really check to see if I/O is possible.
+ */
+ return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
+}
+
+int
+fusefs_fsync(void *v)
+{
+ DPRINTF("fusefs_fsync\n");
+ return (0);
+}
+
+int
+fusefs_rename(void *v)
+{
+ DPRINTF("fusefs_rename\n");
+ return (0);
+}
+
+int
+fusefs_mkdir(void *v)
+{
+ struct vop_mkdir_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct vattr *vap = ap->a_vap;
+ struct proc *p = cnp->cn_proc;
+ struct fuse_mkdir_in fmdi;
+ struct vnode *tdp = NULL;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+ DPRINTF("fusefs_mkdir %s\n", cnp->cn_nameptr);
+
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKDIR)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fmdi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ memcpy(msg.data, &fmdi, sizeof(fmdi));
+ memcpy((char *)msg.data + sizeof(fmdi), cnp->cn_nameptr,
+ cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(fmdi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_MKDIR, ip->i_number, p);
+ struct proc *p = cnp->cn_proc;
+ struct fuse_node *ip, *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+ DPRINTF("fusefs_rmdir\n");
+ DPRINTF("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0],
+ cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+
+ ip = VTOI(vp);
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_RMDIR, dp->i_number, p);
+ struct proc *p = cnp->cn_proc;
+ struct fuse_node *ip;
+ struct fuse_node *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+ DPRINTF("fusefs_remove\n");
+ DPRINTF("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0],
+ cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+
+ ip = VTOI(vp);
+ dp = VTOI(dvp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_REMOVE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_intr;
+ msg.cb = &fuse_sync_it;
+
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_UNLINK, dp->i_number, p);
+ DPRINTF("fusefs_strategy\n");
+ return (0);
+}
+
+int
+fusefs_lock(void *v)
+{
+ struct vop_lock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+ DPRINTF("fuse_lock\n");
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, NULL));
+}
+
+int
+fusefs_unlock(void *v)
+{
+ struct vop_unlock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+ DPRINTF("fuse_unlock\n");
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, NULL));
+}
+
+int
+fusefs_islocked(void *v)
+{
+ struct vop_islocked_args *ap = v;
+
+ DPRINTF("fuse_islock\n");
+ return (lockstatus(&VTOI(ap->a_vp)->i_lock));
+}
+
+int
+fusefs_advlock(void *v)
+{
+ struct vop_advlock_args *ap = v;
+ struct fuse_node *ip = VTOI(ap->a_vp);
+
+ DPRINTF("fuse_advlock\n");
+ return (lf_advlock(&ip->i_lockf, ip->filesize, ap->a_id, ap->a_op,
+ ap->a_fl, ap->a_flags));
+}
Index: sys/miscfs/fuse/fusefs.h
===================================================================
RCS file: sys/miscfs/fuse/fusefs.h
diff -N sys/miscfs/fuse/fusefs.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/miscfs/fuse/fusefs.h 6 Mar 2013 20:04:27 -0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSEFS_H__
+#define __FUSEFS_H__
+
+struct fuse_msg;
+
+struct fuse_mnt {
+ struct mount *mp;
+ uint32_t undef_op;
+ uint32_t max_write;
+ int sess_init;
+ int unique;
+ int fd;
+};
+
+#define UNDEF_ACCESS 1<<0
+#define UNDEF_MKDIR 1<<1
+#define UNDEF_CREATE 1<<2
+#define UNDEF_LINK 1<<3
+#define UNDEF_READLINK 1<<4
+#define UNDEF_RMDIR 1<<5
+#define UNDEF_REMOVE 1<<6
+
+typedef void (*fuse_cb)(struct fuse_msg *,struct fuse_out_header *,
void *);
+void fuse_sync_it(struct fuse_msg *, struct fuse_out_header *, void *);
+
+/*
+ * files helpers.
+ */
+
+int fuse_file_open(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int,
+ int, struct proc *);
+int fuse_file_close(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int,
+ int, struct proc *);
+void fuse_internal_attr_fat2vat(struct mount *, struct fuse_attr *,
+ struct vattr *);
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be
used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ */
+#define FUSE_ROOTINO ((ino_t)1)
+#define VFSTOFUSEFS(mp) ((struct fuse_mnt *)((mp)->mnt_data))
+
+#define MAX_FUSE_DEV 4
+/*
+#define FUSE_DEBUG_VNOP
+#define FUSE_DEBUG_VFS
+#define FUSE_DEV_DEBUG
+#define FUSE_DEBUG_MSG
+*/
+
+#endif /* __FUSEFS_H__ */
Index: sys/sys/conf.h
===================================================================
RCS file: /cvs/src/sys/sys/conf.h,v
retrieving revision 1.119
diff -u -p -r1.119 conf.h
--- sys/sys/conf.h 23 Aug 2012 06:12:49 -0000 1.119
+++ sys/sys/conf.h 6 Mar 2013 20:04:27 -0000
@@ -509,6 +509,13 @@ extern struct cdevsw cdevsw[];
(dev_type_stop((*))) enodev, 0, selfalse, \
(dev_type_mmap((*))) enodev }

+/* open, close, read, write, poll, ioctl */
+#define cdev_fuse_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \
+ (dev_type_mmap((*))) enodev }
+
#endif

/*
@@ -657,6 +664,7 @@ cdev_decl(urio);
cdev_decl(hotplug);
cdev_decl(gpio);
cdev_decl(amdmsr);
+cdev_decl(fuse);

#endif

Index: sys/sys/malloc.h
===================================================================
RCS file: /cvs/src/sys/sys/malloc.h,v
retrieving revision 1.101
diff -u -p -r1.101 malloc.h
--- sys/sys/malloc.h 7 Feb 2013 11:06:42 -0000 1.101
+++ sys/sys/malloc.h 6 Mar 2013 20:04:28 -0000
@@ -118,7 +118,8 @@
#define M_TTYS 62 /* allocated tty structures */
#define M_EXEC 63 /* argument lists & other mem used by
exec */
#define M_MISCFSMNT 64 /* miscfs mount structures */
-/* 65-73 - free */
+#define M_FUSEFS 65 /* fusefs mount structures */
+/* 66-73 - free */
#define M_PFKEY 74 /* pfkey data */
#define M_TDB 75 /* Transforms database */
#define M_XDATA 76 /* IPsec data */
@@ -247,7 +248,7 @@
"ttys", /* 62 M_TTYS */ \
"exec", /* 63 M_EXEC */ \
"miscfs mount", /* 64 M_MISCFSMNT */ \
- NULL, \
+ "fusefs mount", /* 65 M_FUSEFS */ \
NULL, \
NULL, \
NULL, \
Index: sys/sys/mount.h
===================================================================
RCS file: /cvs/src/sys/sys/mount.h,v
retrieving revision 1.108
diff -u -p -r1.108 mount.h
--- sys/sys/mount.h 5 Sep 2012 17:01:06 -0000 1.108
+++ sys/sys/mount.h 6 Mar 2013 20:04:28 -0000
@@ -258,6 +258,15 @@ struct procfs_args {
#define PROCFS_ARGSVERSION 1
#define PROCFSMNT_LINUXCOMPAT 0x01

+/*
+ * Arguments to mount fusefs filesystems
+ */
+struct fusefs_args {
+ char *name;
+ char *url;
+ int fd;
+ int flags;
+};

/*
* file system statistics
@@ -325,6 +334,7 @@ struct statfs {
#define MOUNT_NCPFS "ncpfs" /* NetWare Network File System */
#define MOUNT_NTFS "ntfs" /* NTFS */
#define MOUNT_UDF "udf" /* UDF */
+#define MOUNT_FUSEFS "fuse" /* FUSE */

/*
* Structure per mounted file system. Each mounted file system has an
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvs/src/sys/sys/vnode.h,v
retrieving revision 1.113
diff -u -p -r1.113 vnode.h
--- sys/sys/vnode.h 8 Oct 2012 15:43:08 -0000 1.113
+++ sys/sys/vnode.h 6 Mar 2013 20:04:28 -0000

Ted Unangst

unread,
Mar 6, 2013, 4:19:25 PM3/6/13
to
On Wed, Mar 06, 2013 at 22:27, Sylvestre Gallon wrote:
> Do you know if miscfs is the best place to put my code ?

I think so.

> Do I keep the device code (fuse_device.c) in the same directory than the
> filesystem code?

I'd prefer that. sys/dev is kind of cluttered as it is, and since the
dev code and fs code are tightly coupled, it makes sense to keep it
all in one place.

> Do you know which fs type I can use in kern/vfs_init.c for fuse ? I've
> taken 42 but I have no idea what I was doing when I choose this number :)

Whatever. I don't think those numbers are used.

> +/*
> + * The root inode is the root of the file system. Inode 0 can't be
> used for
> + * normal purposes and bad blocks are normally linked to inode 1, thus
> + * the root inode is 2.
> + */
> +#define FUSE_ROOTINO ((ino_t)1)

Internal disagreement here. :)

Jonathan Armani

unread,
Mar 7, 2013, 7:10:48 AM3/7/13
to
On Tue, Mar 05, 2013 at 03:24:06PM +0100, Sylvestre Gallon wrote:

> I am not quite sure but I think that only libfuse and sshfs are GPL
> licenced. The patches for those two items are only present in ports.
>
> All the code present in src is ISC licenced. The kernel communicate with
> libfuse througth a device (ie /dev/fuse) and only share a header with the
> libfuse (fuse_kernel.h) which is BSD licenced. FreeBSD used the same way to
> implement it. (I do not know if it is a good example)
>

Hi Sylvestre,

Nice to see that someone is working on this.

I think the problem here is that the kernel will provide a service that only
ports can use. If we want to use it in the basesystem, we will have to
rewrite a BSD licenced libfuse.

Other possibility is to make it a loadable kernel module, but I don't know
the current state of our support.


Gilles Chehade

unread,
Mar 7, 2013, 8:16:42 AM3/7/13
to
On Thu, Mar 07, 2013 at 01:10:48PM +0100, Jonathan Armani wrote:
> On Tue, Mar 05, 2013 at 03:24:06PM +0100, Sylvestre Gallon wrote:
>
> > I am not quite sure but I think that only libfuse and sshfs are GPL
> > licenced. The patches for those two items are only present in ports.
> >
> > All the code present in src is ISC licenced. The kernel communicate with
> > libfuse througth a device (ie /dev/fuse) and only share a header with the
> > libfuse (fuse_kernel.h) which is BSD licenced. FreeBSD used the same way to
> > implement it. (I do not know if it is a good example)
> >
>
> Hi Sylvestre,
>
> Nice to see that someone is working on this.
>
> I think the problem here is that the kernel will provide a service that only
> ports can use. If we want to use it in the basesystem, we will have to
> rewrite a BSD licenced libfuse.
>

Quite frankly, if there's work in that area and hope that it does not go
to waste, I will happily volunteer to work on that.

Bob Beck

unread,
Mar 7, 2013, 9:03:03 AM3/7/13
to
....

Which is why I keep pointing people at puffs and librefuse in netbsd....

Sylvestre Gallon

unread,
Mar 7, 2013, 12:11:07 PM3/7/13
to
On Thu, Mar 7, 2013 at 3:03 PM, Bob Beck <be...@obtuse.com> wrote:
>
> ....
>
> Which is why I keep pointing people at puffs and librefuse in netbsd....
>
>

Hi,

Using puffs will induce a rewrite of all the kernel code, because the
internals are completely different (and I think a little bit more
complex, but this is a personal opinion...).

For a libfuse support in basesystem we will need to do a librefuse
like library. In this case we could perhaps keep the librefuse
frontend and only rewrite the backend.

Which solution do you think is best ? In any case and if you need me,
I will be provide all the help I can :)

Cheers,

--
Sylvestre Gallon

Bob Beck

unread,
Mar 7, 2013, 12:15:59 PM3/7/13
to
> Using puffs will induce a rewrite of all the kernel code, because the
> internals are completely different (and I think a little bit more
> complex, but this is a personal opinion...).
>
>
I might share that opinon :)



> For a libfuse support in basesystem we will need to do a librefuse
> like library. In this case we could perhaps keep the librefuse
> frontend and only rewrite the backend.

|

>

Which solution do you think is best ? In any case and if you need me,
> I will be provide all the help I can :)
>

Essentially we just need the best solution to have a base acceptable fuse
library. I don't know
what the right answer to that is, but perhaps starting with librefuse and
makeing it less refusey (and more towards
compatible with a working ISC licensed fuse implementation in the kernel
would be the way to go.

0 new messages