Add support for mknod in fuse.
authorsyl <syl@openbsd.org>
Thu, 16 Jan 2014 09:31:44 +0000 (09:31 +0000)
committersyl <syl@openbsd.org>
Thu, 16 Jan 2014 09:31:44 +0000 (09:31 +0000)
OK tedu@
"it looks good to me" from guenther@

lib/libfuse/fuse_ops.c
sys/miscfs/fuse/fuse_vnops.c
sys/miscfs/fuse/fusefs.h
sys/sys/fusebuf.h

index 88c6bb2..23e6e92 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_ops.c,v 1.19 2014/01/02 15:39:12 syl Exp $ */
+/* $OpenBSD: fuse_ops.c,v 1.20 2014/01/16 09:31:44 syl Exp $ */
 /*
  * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -809,6 +809,34 @@ ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
        return (0);
 }
 
+static int
+ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
+{
+       struct fuse_vnode *vn;
+       char *realname;
+       uint32_t mode;
+       dev_t dev;
+
+       CHECK_OPT(mknod);
+
+       mode = fbuf->fb_io_mode;
+       dev = fbuf->fb_io_rdev;
+       vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
+
+       free(fbuf->fb_dat);
+       realname = build_realname(f, vn->ino);
+       fbuf->fb_err = f->op.mknod(realname, mode, dev);
+
+       if (!fbuf->fb_err) {
+               fbuf->fb_err = update_vattr(f, &fbuf->fb_vattr, realname, vn);
+               fbuf->fb_io_mode = fbuf->fb_vattr.va_mode;
+               fbuf->fb_ino = fbuf->fb_vattr.va_fileid;
+       }
+       free(realname);
+
+       return (0);
+}
+
 int
 ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
 {
@@ -887,6 +915,9 @@ ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
        case FBT_RECLAIM:
                ret = ifuse_ops_reclaim(f, fbuf);
                break;
+       case FBT_MKNOD:
+               ret = ifuse_ops_mknod(f, fbuf);
+               break;
        default:
                DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
                DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
index 420b927..6d514bb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fuse_vnops.c,v 1.12 2013/12/20 22:03:26 syl Exp $ */
+/* $OpenBSD: fuse_vnops.c,v 1.13 2014/01/16 09:31:44 syl Exp $ */
 /*
  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -885,10 +885,72 @@ int
 fusefs_mknod(void *v)
 {
        struct vop_mknod_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 proc *p = cnp->cn_proc;
+       struct vnode *tdp = NULL;
+       struct fusefs_mnt *fmp;
+       struct fusefs_node *ip;
+       struct fusebuf *fbuf;
+       int error = 0;
+
+       ip = VTOI(dvp);
+       fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
 
+       if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKNOD)) {
+               error = ENOSYS;
+               goto out;
+       }
+
+       fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
+           FBT_MKNOD, p);
+
+       fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
+       if (vap->va_rdev != VNOVAL)
+               fbuf->fb_io_rdev = vap->va_rdev;
+
+       memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
+       fbuf->fb_dat[cnp->cn_namelen] = '\0';
+
+       error = fb_queue(fmp->dev, fbuf);
+       if (error) {
+               if (error == ENOSYS)
+                       fmp->undef_op |= UNDEF_MKNOD;
+
+               fb_delete(fbuf);
+               goto out;
+       }
+
+       if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
+               fb_delete(fbuf);
+               goto out;
+       }
+
+       tdp->v_type = IFTOVT(fbuf->fb_io_mode);
+       VTOI(tdp)->vtype = tdp->v_type;
+
+       if (dvp != NULL && dvp->v_type == VDIR)
+               VTOI(tdp)->parent = ip->ufs_ino.i_number;
+
+       *vpp = tdp;
        VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+       fb_delete(fbuf);
        vput(ap->a_dvp);
-       return (EINVAL);
+
+       /* Remove inode so that it will be reloaded by VFS_VGET and
+        * checked to see if it is an alias of an existing entry in
+        * the inode cache.
+        */
+       vput(*vpp);
+       (*vpp)->v_type = VNON;
+       vgone(*vpp);
+       *vpp = NULL;
+       return (0);
+out:
+       vput(ap->a_dvp);
+       return (error);
 }
 
 int
index 60b6fa1..1d9c7fb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fusefs.h,v 1.5 2013/12/10 13:43:05 pelikan Exp $ */
+/* $OpenBSD: fusefs.h,v 1.6 2014/01/16 09:31:44 syl Exp $ */
 /*
  * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
  *
@@ -65,6 +65,7 @@ struct fusefs_mnt {
 #define UNDEF_SETATTR  1<<7
 #define UNDEF_RENAME   1<<8
 #define UNDEF_SYMLINK  1<<9
+#define UNDEF_MKNOD    1<<10
 
 extern struct vops fusefs_vops;
 extern struct pool fusefs_fbuf_pool;
index bec298d..f2e1aa0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: fusebuf.h,v 1.8 2013/12/03 09:59:40 syl Exp $ */
+/* $OpenBSD: fusebuf.h,v 1.9 2014/01/16 09:31:44 syl Exp $ */
 /*
  * Copyright (c) 2013 Sylvestre Gallon
  * Copyright (c) 2013 Martin Pieuchot
@@ -43,6 +43,7 @@ struct fb_io {
        size_t          fi_len;         /* Length of data */
        mode_t          fi_mode;        /* mode for fd */
        uint32_t        fi_flags;       /* flags on transfer */
+       dev_t           fi_rdev;        /* dev for mknod */
 };
 
 /*
@@ -82,6 +83,7 @@ struct fusebuf {
 #define fb_io_len      FD.FD_io.fi_len
 #define fb_io_mode     FD.FD_io.fi_mode
 #define fb_io_flags    FD.FD_io.fi_flags
+#define fb_io_rdev     FD.FD_io.fi_rdev
 #define        fb_dat          F_databuf
 
 /*