PERFORCE change 194383 for review

Ilya Putsikau ilya at FreeBSD.org
Tue Jun 7 10:56:17 UTC 2011


http://p4web.freebsd.org/@@194383?ac=10

Change 194383 by ilya at ilya_triton2011 on 2011/06/07 10:55:10

	fuse_vnops.c change function order, move internal functions to fuse_internal.c

Affected files ...

.. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse.h#5 edit
.. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.c#4 edit
.. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.h#5 edit
.. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#8 edit

Differences ...

==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse.h#5 (text+ko) ====

@@ -195,6 +195,22 @@
 #endif
 #endif
 
+#ifdef FUSE_TRACE
+#define fuse_trace_printf(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#define fuse_trace_printf_func()    printf("%s\n", __FUNCTION__)
+#else
+#define fuse_trace_printf(fmt, ...) {}
+#define fuse_trace_printf_func()    {}
+#endif
+
+#ifdef FUSE_TRACE_OP
+#define fuse_trace_printf_vfsop() printf("%s\n", __FUNCTION__)
+#define fuse_trace_printf_vnop()  printf("%s\n", __FUNCTION__)
+#else
+#define fuse_trace_printf_vfsop() {}
+#define fuse_trace_printf_vnop()  {}
+#endif
+
 #define debug_printf(fmt, ...) DEBUG(fmt, ## __VA_ARGS__)
 #define kdebug_printf(fmt, ...) DEBUG(fmt, ## __VA_ARGS__)
 

==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.c#4 (text+ko) ====

@@ -11,20 +11,644 @@
 #include <sys/malloc.h>
 #include <sys/queue.h>
 #include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/sx.h>
-#include <sys/mutex.h>
 #include <sys/proc.h>
+#include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/namei.h>
-#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+#include <sys/filedesc.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
 #include <sys/sysctl.h>
-#include <sys/fcntl.h>
+#include <sys/priv.h>
 
 #include "fuse.h"
 #include "fuse_node.h"
 #include "fuse_ipc.h"
 #include "fuse_internal.h"
 
+/* access */
+
+static __inline int     fuse_check_spyable(struct fuse_dispatcher *fdip,
+                                           struct mount *mp, struct thread *td,
+                                           struct ucred *cred);
+static __inline int     fuse_match_cred(struct ucred *daemoncred,
+                                        struct ucred *usercred);
+
+int
+fuse_internal_access(struct vnode *vp,
+                     mode_t mode,
+                     struct ucred *cred,
+                     struct thread *td,
+                     struct fuse_access_param *facp)
+{
+    int err = 0;
+    struct fuse_dispatcher fdi;
+
+    /*
+     * Disallow write attempts on read-only file systems; unless the file
+     * is a socket, fifo, or a block or character device resident on the
+     * file system.
+     */
+
+    DEBUG("ro? %#x vp #%llu mode %#x\n",
+          vp->v_mount->mnt_flag & MNT_RDONLY, VTOILLU(vp), mode);
+
+    RECTIFY_TDCR(td, cred);
+
+    if (mode & VWRITE) {
+            switch (vp->v_type) {
+            case VDIR:
+            case VLNK:
+            case VREG:
+                    if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+                            DEBUG("no write access (read-only fs)\n");
+                            return (EROFS);
+                    }
+                    break;
+            default:
+                    break;
+            }
+    }
+
+    bzero(&fdi, sizeof(fdi));
+    if (vp->v_vflag & VV_ROOT && ! (facp->facc_flags & FACCESS_NOCHECKSPY)) {
+            if ((err = fuse_check_spyable(&fdi, vp->v_mount, td, cred)))
+                    return (err);
+            facp->facc_flags |= FACCESS_NOCHECKSPY;
+    }
+
+    if (fusefs_get_data(vp->v_mount)->dataflag & FSESS_DEFAULT_PERMISSIONS ||
+        /*
+         * According to Linux code, we fall back to in-kernel check
+         * when it comes to executing a file
+         */
+        (vp->v_type == VREG && mode == VEXEC)) {
+            /* We are to do the check in-kernel */
+
+            if (! (facp->facc_flags & FACCESS_VA_VALID)) {
+                    err = VOP_GETATTR(vp, VTOVA(vp), cred);
+                    if (err)
+                            return (err);
+                    facp->facc_flags |= FACCESS_VA_VALID;
+            }
+
+            err = vaccess(VTOVA(vp)->va_type,
+                          VTOVA(vp)->va_mode,
+                          VTOVA(vp)->va_uid,
+                          VTOVA(vp)->va_gid,
+                          mode, cred, NULL);
+
+            if (err)
+                    return (err);
+
+            if (facp->facc_flags & FACCESS_STICKY) {
+                    if (vp->v_type == VDIR && VTOVA(vp)->va_mode & S_ISTXT &&
+                        mode == VWRITE) {
+                            if (cred->cr_uid != facp->xuid &&
+                                cred->cr_uid != VTOVA(vp)->va_uid)
+                                    err = priv_check_cred(cred,
+                                                          PRIV_VFS_ADMIN,
+                                                          0);
+                    }
+                    /*
+                     * We return here because this flags is exlusive
+                     * with the others
+                     */
+                    KASSERT(facp->facc_flags == FACCESS_STICKY,
+                            ("sticky access check comes in mixed"));
+                    return (err);
+            }
+
+            if (mode != VADMIN)
+                    return (err);
+
+            if (facp->facc_flags & FACCESS_CHOWN) {
+                    if ((cred->cr_uid != facp->xuid &&
+                             facp->xuid != (uid_t)VNOVAL) ||
+                        (cred->cr_gid != facp->xgid &&
+                             facp->xgid != (gid_t)VNOVAL &&
+                             ! groupmember(facp->xgid, cred)))
+                            err = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
+                    if (err)
+                            return (err);
+            }
+
+            if (facp->facc_flags & FACCESS_SETGID) {
+                    gid_t sgid = facp->xgid;
+
+                    if (sgid == (gid_t)VNOVAL)
+                            sgid = VTOVA(vp)->va_gid;
+
+                    if (! groupmember(sgid, cred))
+                            err = priv_check_cred(cred, PRIV_VFS_SETGID, 0);
+                    return (err);
+            }
+
+    } else {
+#if FUSE_HAS_ACCESS
+            struct fuse_access_in *fai;
+
+            if (! (facp->facc_flags & FACCESS_DO_ACCESS))
+                    return (0);
+
+            if (fusefs_get_data(vp->v_mount)->dataflag & FSESS_NOACCESS)
+                    return (0);
+
+            fdisp_init(&fdi, sizeof(*fai));
+            fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
+
+            fai = fdi.indata;
+
+            fai->mask = F_OK;
+            if (mode & VREAD)
+                    fai->mask |= R_OK;
+            if (mode & VWRITE)
+                    fai->mask |= W_OK;
+            if (mode & VEXEC)
+                    fai->mask |= X_OK;
+
+            if (! (err = fdisp_wait_answ(&fdi)))
+                    fuse_ticket_drop(fdi.tick);
+
+            if (err == ENOSYS) {
+                    fusefs_get_data(vp->v_mount)->dataflag |= FSESS_NOACCESS;
+                    err = 0;
+            }
+#endif
+    }
+    return err;
+}
+
+/*
+ * An access check routine based on fuse_allow_task() of the Linux module.
+ * Now we use this one rather than the more permissive function we used to
+ * (and which seemed more logical to me), to ensure uniform behaviour on Linux
+ * and FreeBSD.
+ *
+ * Non-null return value indicates error (ie., "not allowed").
+ */
+static __inline int
+fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
+{
+	if (basecred->cr_uid == usercred->cr_uid             &&
+	    basecred->cr_uid == usercred->cr_ruid            &&
+	    basecred->cr_uid == usercred->cr_svuid           &&
+	    basecred->cr_groups[0] == usercred->cr_groups[0] &&
+	    basecred->cr_groups[0] == usercred->cr_rgid      &&
+	    basecred->cr_groups[0] == usercred->cr_svgid)
+		return (0);
+
+	return (EPERM);
+}
+
+
+static __inline int
+fuse_check_spyable(struct fuse_dispatcher *fdip, struct mount *mp,
+                   struct thread *td, struct ucred *cred)
+{
+	struct fuse_data *data = fusefs_get_data(mp);
+	struct fuse_secondary_data *x_fsdat;
+	int denied;
+
+	if (data->dataflag & FSESS_DAEMON_CAN_SPY)
+		return (0);
+
+	/*
+	 * The policy is to forbid a user from using the filesystem,
+	 * unless she has it mounted.
+	 *
+	 * This is primarily to
+	 * protect her from the daemon spying on her I/O
+	 * operations. Although this is not a concern if the user
+	 * is more privileged than the daemon, we consistently
+	 * demand the per-user mount, in order to be compatible
+	 * with the Linux implementation.
+	 *
+	 * Secondary mounts let arbitrary number of users mount and
+	 * use the filesystem. However, the primary mounter must explicitly
+	 * allow secondary mounts. This is again for providing Linux like
+	 * defaults.
+	 */
+
+	denied = fuse_match_cred(mp->mnt_cred, cred);
+	if (! denied)
+		goto allow;
+
+	LIST_FOREACH(x_fsdat, &data->slaves_head, slaves_link) {
+		denied = fuse_match_cred(x_fsdat->mp->mnt_cred, cred);
+		if (! denied)
+			goto allow;
+	}
+
+	return (EACCES);
+
+allow:
+	return (0);
+}
+
+/* fsync */
+
+int
+fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
+{
+    if (tick->tk_aw_ohead.error == ENOSYS)
+        tick->tk_data->dataflag |=
+         fticket_opcode(tick) == FUSE_FSYNC ?
+         FSESS_NOFSYNC : FSESS_NOFSYNCDIR;
+
+    fuse_ticket_drop(tick);
+    return (0);
+}
+
+/* readdir */
+
+int
+fuse_internal_readdir_processdata(struct uio *uio,
+                                  size_t reqsize,
+                                  void *buf,
+                                  size_t bufsize,
+                                  void *param)
+{
+    /*
+     * The daemon presents us with a virtual geometry when reading dirents.
+     * This info is stored in the "off" field of fuse_dirent (which is the
+     * struct we can read from her). "off" shows the absolut position of
+     * the next entry (by definition). So I might pull 40 actual bytes from
+     * the daemon, that might count as 60 by her virtual geometry, and when
+     * I translate fuse_dirents to POSIX dirents, I have 20 bytes to pass
+     * to the userspace reader.
+     *	
+     * How to keep these in sync? We don't want to make the general read
+     * routine complex (to which here we serve a background, and which
+     * naively treats reading by a liner logic). So we artifically inflate
+     * dirents: we pad them with as much zeros as we need them to get to
+     * next offset (as the deamon declared), and we pass it to the reader
+     * thusly (this will work as fuse dirents are bigger than std ones). So
+     * we do more IO with the reader than absolutely necessary, but it's
+     * hardly a problem as the expensive thing is reading from the daemon,
+     * not sending data to the reader.
+     *
+     * There is no use to change this simple geometry translation scheme
+     * 'till we do page caching. [We do now, but it's still fine as is.]
+     */
+    int err = 0;
+    int cou = 0;
+    int bytesavail;
+    size_t freclen;
+
+    struct dirent      *de;
+    struct fuse_dirent *fudge;
+    struct fuse_iov    *cookediov = param;
+    
+    KASSERT(bufsize <= reqsize, ("read more than asked for?"));
+
+    DEBUG2G("starting\n");
+
+    /*
+     * Sanity check: if this fails, we would overrun the allocated space
+     * upon entering the loop below, so we'd better leave right now.
+     * If so, we return -1 to terminate reading.
+     */
+    if (bufsize < FUSE_NAME_OFFSET) {
+        return (-1);
+    }
+
+    DEBUG2G("entering loop with bufsize %d\n", (int)bufsize);
+
+    /*
+     * Can we avoid infite loops? An infinite loop could occur only if we
+     * leave this function with 0 return value, because otherwise we wont't
+     * be called again. But both 0 exit points imply that some data has
+     * been consumed... because
+     *   1) if a turn is not aborted, it consumes positive amount of data
+     *   2) the 0 jump-out from within the loop can't occur in the first
+     *      turn
+     *   3) if we exit 0 after the loop is over, then at least one turn
+     *      was completed, otherwise we hed exited above with -1.
+     */  
+
+    for (;;) {
+
+        if (bufsize < FUSE_NAME_OFFSET) {
+            err = -1;
+            break;
+        }
+
+        cou++;
+
+        fudge = (struct fuse_dirent *)buf;
+        freclen = FUSE_DIRENT_SIZE(fudge);
+
+        DEBUG("bufsize %d, freclen %d\n", (int)bufsize, (int)freclen);
+
+        /*
+         * Here is an exit condition: we terminate the whole reading
+         * process if a fresh chunk of buffer is already too short to
+         * cut out an entry.
+         * (It it was not the first turn in the loop, nevermind,
+         * return with asking for more)
+         */
+        if (bufsize < freclen) {
+            err = ((cou == 1) ? -1 : 0);
+            break;
+        }
+
+#if FUSELIB_CONFORM_BIOREAD
+        if (isbzero(buf, FUSE_NAME_OFFSET)) {
+            err = -1;
+            break;
+        }
+#endif
+
+        /* Sanity checks */
+
+        if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
+            DEBUG2G("bogus namelen %d at turn %d\n",
+                    fudge->namelen, cou);
+            err = EINVAL;
+            break;
+        }
+
+        bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen); 
+
+        /*
+         * Exit condition 2: if the pretended amount of input is more
+         * than that the userspace wants, then it's time to stop
+         * reading.
+         */  
+        if (bytesavail > uio->uio_resid) {
+            DEBUG2G("leaving at %d-th item as we have %d bytes but only %d is asked for\n",
+                    cou, bytesavail, uio->uio_resid);
+            err = -1;
+            break;
+        }
+
+        fiov_refresh(cookediov);
+        fiov_adjust(cookediov, bytesavail);
+
+        de = (struct dirent *)cookediov->base;
+        de->d_fileno = fudge->ino; /* XXX cast from 64 to 32 bits */
+        de->d_reclen = bytesavail;
+        de->d_type = fudge->type; 
+        de->d_namlen = fudge->namelen;
+        memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1,
+               (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
+        ((char *)cookediov->base)[bytesavail] = '\0';
+
+        DEBUG("bytesavail %d, fudge->off %llu, fudge->namelen %d, uio->uio_offset %d, name %s\n",
+              bytesavail, (unsigned long long)fudge->off, fudge->namelen, (int)uio->uio_offset,
+              (char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1);
+
+        err = uiomove(cookediov->base, cookediov->len, uio);
+        if (err) {
+            break;
+        }
+
+        buf = (char *)buf + freclen;
+        bufsize -= freclen;
+        uio->uio_offset = fudge->off;
+    }
+
+    return (err);
+}
+
+/* remove */
+
+int
+fuse_internal_remove(struct vnode *dvp,
+                     struct vnode *vp,
+                     struct componentname *cnp,
+                     enum fuse_opcode op)
+{
+    struct fuse_dispatcher fdi;
+    int err = 0;
+
+    debug_printf("dvp=%p, cnp=%p, op=%d, context=%p\n", vp, cnp, op, context);
+
+    fdisp_init(&fdi, cnp->cn_namelen + 1);
+    fdisp_make_vp(&fdi, op, dvp, curthread, NULL);
+
+    memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
+    ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
+
+    if (!(err = fdisp_wait_answ(&fdi))) {
+        fuse_ticket_drop(fdi.tick);
+    }
+
+    fuse_invalidate_attr(dvp);
+    fuse_invalidate_attr(vp);
+
+    return (err);
+}
+
+/* rename */
+
+int
+fuse_internal_rename(struct vnode *fdvp,
+                     struct componentname *fcnp,
+                     struct vnode *tdvp,
+                     struct componentname *tcnp)
+{
+    struct fuse_dispatcher fdi;
+    struct fuse_rename_in *fri;
+    int err = 0;
+
+    fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
+    fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, curthread, NULL);
+
+    fri = fdi.indata;
+    fri->newdir = VTOI(tdvp);
+    memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
+           fcnp->cn_namelen);
+    ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
+    memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
+           tcnp->cn_nameptr, tcnp->cn_namelen);
+    ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
+                         tcnp->cn_namelen + 1] = '\0';
+        
+    if (!(err = fdisp_wait_answ(&fdi))) {
+        fuse_ticket_drop(fdi.tick);
+    }
+
+    fuse_invalidate_attr(fdvp);
+    if (tdvp != fdvp) {
+        fuse_invalidate_attr(tdvp);
+    }
+
+    return (err);
+}
+
+/* strategy */
+
+
+
+
+
+/* entity creation */
+
+void
+fuse_internal_newentry_makerequest(struct mount *mp,
+                                   uint64_t dnid,
+                                   struct componentname *cnp,
+                                   enum fuse_opcode op,
+                                   void *buf,
+                                   size_t bufsize,
+                                   struct fuse_dispatcher *fdip)
+{
+    debug_printf("fdip=%p, context=%p\n", fdip, context);
+
+    fdip->iosize = bufsize + cnp->cn_namelen + 1;
+
+    fdisp_make(fdip, mp, op, dnid, curthread, NULL);
+    memcpy(fdip->indata, buf, bufsize);
+
+    memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
+    ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
+}
+
+int
+fuse_internal_newentry_core(struct vnode *dvp,
+                            struct vnode **vpp,
+                            enum vtype vtyp,
+                            struct fuse_dispatcher *fdip)
+{
+    int err = 0;
+    struct fuse_entry_out *feo;
+    struct mount *mp = dvp->v_mount;
+
+    debug_printf("fdip=%p\n", fdip);
+
+    KASSERT(! (mp->mnt_flag & MNT_RDONLY),
+            ("request for new entry in a read-only mount"));
+
+    if ((err = fdisp_wait_answ(fdip))) {
+        return (err);
+    }
+        
+    feo = fdip->answ;
+
+    if ((err = fuse_internal_checkentry(feo, vtyp))) {
+        goto out;
+    }
+
+    /*
+     * The Linux code doesn't seem to make a fuss about
+     * getting a nodeid for a new entry which is  already
+     * in use. Therefore we used to do the same.
+     * This is not possible with our implementation of
+     * atomic create+open; so, even if we could ignore this
+     * fuzz here, we don't do, for the sake of consistency.
+     */
+    err = fuse_vget_i(mp, curthread, feo->nodeid, vtyp, vpp,
+                      VG_FORCENEW, VTOI(dvp));
+
+    if (err) {
+        DEBUG2G("failed to fetch vnode for nodeid\n");
+        fuse_internal_forget_send(mp, curthread, NULL, feo->nodeid, 1, fdip);
+        return err;
+    }
+
+    VTOFUD(*vpp)->nlookup++;
+    cache_attrs(*vpp, feo);
+
+out:
+    fuse_ticket_drop(fdip->tick);
+
+    return err;
+}
+
+int
+fuse_internal_newentry(struct vnode *dvp,
+                       struct vnode **vpp,
+                       struct componentname *cnp,
+                       enum fuse_opcode op,
+                       void *buf,
+		       size_t bufsize,
+                       enum vtype vtyp)
+{
+    int err;
+    struct fuse_dispatcher fdi;
+
+    fdisp_init(&fdi, 0);
+    fuse_internal_newentry_makerequest(dvp->v_mount, VTOI(dvp), cnp,
+	                               op, buf, bufsize, &fdi);
+    err = fuse_internal_newentry_core(dvp, vpp, vtyp, &fdi);
+    fuse_invalidate_attr(dvp);
+
+    return (err);
+}
+
+/* entity destruction */
+
+static void
+fuse_internal_forget_send_pid(struct mount *mp,
+                          pid_t pid,
+                          struct ucred *cred,
+                          uint64_t nodeid,
+                          uint64_t nlookup,
+                          struct fuse_dispatcher *fdip)
+{
+    struct fuse_forget_in *ffi;
+
+    KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
+            (long long unsigned) nodeid));
+
+    DEBUG("sending FORGET with %llu lookups\n", (unsigned long long)nlookup);
+
+    fdisp_init(fdip, sizeof(*ffi));
+    fdisp_make_pid(fdip, mp, FUSE_FORGET, nodeid, pid, cred);
+
+    ffi = fdip->indata;
+    ffi->nlookup = nlookup;
+
+    fticket_disown(fdip->tick);
+    fuse_insert_message(fdip->tick);
+}
+
+int
+fuse_internal_forget_callback(struct fuse_ticket *tick,
+                              struct uio *uio)
+{
+    struct fuse_dispatcher fdi;
+    struct fuse_pidcred *pidcred;
+
+    /*
+     * XXX I think I'm right to send a forget regardless of possible
+     * errors, but...
+     */
+
+    fdi.tick = tick;
+    pidcred = tick->tk_aw_handler_parm.base;
+
+    fuse_internal_forget_send_pid(tick->tk_data->mp, pidcred->pid, &pidcred->cred,
+               ((struct fuse_in_header *)tick->tk_ms_fiov.base)->nodeid,
+               1, &fdi);
+
+    return (0);
+}
+
+void
+fuse_internal_forget_send(struct mount *mp,
+                          struct thread *td,
+                          struct ucred *cred,
+                          uint64_t nodeid,
+                          uint64_t nlookup,
+                          struct fuse_dispatcher *fdip)
+{
+    RECTIFY_TDCR(td, cred);
+    return (fuse_internal_forget_send_pid(mp, td->td_proc->p_pid, cred, nodeid,
+                                   nlookup, fdip));
+}
+
+/* fuse start/stop */
+
 int
 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
 {

==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.h#5 (text+ko) ====

@@ -8,12 +8,19 @@
 
 #include <sys/types.h>
 #include <sys/uio.h>
+#include <sys/stat.h>
 #include <sys/vnode.h>
 
 #include "fuse_ipc.h"
 #include "fuse_node.h"
 
-/* access related data */
+/* XXX */
+struct fuse_pidcred {
+	pid_t pid;
+	struct ucred cred;
+};
+
+/* access */
 
 #define FACCESS_VA_VALID   0x01 /* flag to sign to reuse cached attributes
                                    regardless of cache timeout */
@@ -29,12 +36,180 @@
 #define FVP_ACCESS_NOOP   0x01 /* vnode based control flag for doing access check */
 
 struct fuse_access_param {
-	uid_t xuid;
-	gid_t xgid;
+    uid_t xuid;
+    gid_t xgid;
+    unsigned facc_flags;
+};
+
+int
+fuse_internal_access(struct vnode *vp,
+                     mode_t mode,
+                     struct ucred *cred,
+                     struct thread *td,
+                     struct fuse_access_param *facp);
+
+/* attributes */
+
+static __inline
+void
+fuse_internal_attr_fat2vat(struct mount *mp,
+                           struct fuse_attr *fat,
+                           struct vattr *vap)
+{
+    DEBUG("node #%llu, mode 0%o\n", (unsigned long long)fat->ino, fat->mode);
+
+    vattr_null(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; /* XXX on some platforms cast from 64 bits to 32 */
+    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
+
+    vap->va_flags = 0;
+}
+
+#define timespecadd(vvp, uvp)                  \
+    do {                                       \
+           (vvp)->tv_sec += (uvp)->tv_sec;     \
+           (vvp)->tv_nsec += (uvp)->tv_nsec;   \
+           if ((vvp)->tv_nsec >= 1000000000) { \
+               (vvp)->tv_sec++;                \
+               (vvp)->tv_nsec -= 1000000000;   \
+           }                                   \
+    } while (0)
+
+#define cache_attrs(vp, fuse_out) do {                                         \
+    struct timespec uptsp_ ## __func__;                                        \
+                                                                               \
+    VTOFUD(vp)->cached_attrs_valid.tv_sec = (fuse_out)->attr_valid;            \
+    VTOFUD(vp)->cached_attrs_valid.tv_nsec = (fuse_out)->attr_valid_nsec;      \
+    nanouptime(&uptsp_ ## __func__);                                           \
+                                                                               \
+    timespecadd(&VTOFUD(vp)->cached_attrs_valid, &uptsp_ ## __func__);         \
+                                                                               \
+    fuse_internal_attr_fat2vat((vp)->v_mount, &(fuse_out)->attr, VTOVA(vp));   \
+} while (0)
+
+/* fsync */
+
+int
+fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio);
+
+/* readdir */
 
-	unsigned facc_flags;
+struct pseudo_dirent {
+    uint32_t d_namlen;
 };
 
+int
+fuse_internal_readdir_processdata(struct uio *uio,
+                                  size_t reqsize,
+                                  void *buf,
+                                  size_t bufsize,
+                                  void *param);
+
+/* remove */
+
+int
+fuse_internal_remove(struct vnode *dvp,
+                     struct vnode *vp,
+                     struct componentname *cnp,
+                     enum fuse_opcode op);
+
+/* rename */
+
+int
+fuse_internal_rename(struct vnode *fdvp,
+                     struct componentname *fcnp,
+                     struct vnode *tdvp,
+                     struct componentname *tcnp);
+
+/* strategy */
+
+
+
+
+/* entity creation */
+
+static __inline
+int
+fuse_internal_checkentry(struct fuse_entry_out *feo, enum vtype vtyp)
+{
+    debug_printf("feo=%p, vtype=%d\n", feo, vtyp);
+
+    if (vtyp != IFTOVT(feo->attr.mode)) {
+        debug_printf("EINVAL -- %x != %x\n", vtype, IFTOVT(feo->attr.mode));
+        return (EINVAL);
+    }
+
+    if (feo->nodeid == FUSE_NULL_ID) {
+        debug_printf("EINVAL -- feo->nodeid is NULL\n");
+        return (EINVAL);
+    }
+
+    if (feo->nodeid == FUSE_ROOT_ID) {
+        debug_printf("EINVAL -- feo->nodeid is FUSE_ROOT_ID\n");
+        return (EINVAL);
+    }
+
+    return (0);
+}
+
+int
+fuse_internal_newentry(struct vnode *dvp,
+                       struct vnode **vpp,
+                       struct componentname *cnp,
+                       enum fuse_opcode op,
+                       void *buf,
+                       size_t bufsize,
+                       enum vtype vtyp);
+
+void
+fuse_internal_newentry_makerequest(struct mount *mp,
+                                   uint64_t dnid,
+                                   struct componentname *cnp,
+                                   enum fuse_opcode op,
+                                   void *buf,
+                                   size_t bufsize,
+                                   struct fuse_dispatcher *fdip);
+
+int
+fuse_internal_newentry_core(struct vnode *dvp,
+                            struct vnode **vpp,
+                            enum vtype vtyp,
+                            struct fuse_dispatcher *fdip);
+
+/* entity destruction */
+
+int
+fuse_internal_forget_callback(struct fuse_ticket *tick, struct uio *uio);
+
+void
+fuse_internal_forget_send(struct mount *mp,
+                          struct thread *td,
+                          struct ucred *cred,
+                          uint64_t nodeid,
+                          uint64_t nlookup,
+                          struct fuse_dispatcher *fdip);
 
 /* fuse start/stop */
 

==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#8 (text+ko) ====

@@ -64,39 +64,14 @@
 	uint8_t flush:1;
 };
 
-#if FUSE_HAS_CREATE
-struct fuse_pidcred {
-	pid_t pid;
-	struct ucred cred;
-};
-#endif
-
-static void             fuse_send_forget_pid(struct mount *mp, pid_t pid,
-                                             struct ucred *cred, uint64_t nodeid,
-                                             uint64_t nlookup,
-                                             struct fuse_dispatcher *fdip);
-static void             fuse_send_forget(struct mount *mp, struct thread *td,
-                                         struct ucred *cred, uint64_t nodeid,
-                                         uint64_t nlookup,
-                                         struct fuse_dispatcher *fdip);
 static __inline void    fuse_vnode_init_data(struct vnode *vp, struct fuse_vnode_data *fvdat,
                                              uint64_t nodeid);
 static __inline void    fuse_vnode_init_misc(struct vnode *vp, enum vtype vtyp,
                                              uint64_t parentid);
-static __inline void    fat2vat(struct mount *mp, struct fuse_attr *fat,
-                                struct vattr *vap);
-static __inline int     fuse_match_cred(struct ucred *daemoncred,
-                                        struct ucred *usercred);
-static __inline int     fuse_check_spyable(struct fuse_dispatcher *fdip,
-                                           struct mount *mp, struct thread *td,
-                                           struct ucred *cred);
 static int              fuse_recyc_backend(struct vnode *vp, struct thread *td);
 static void             fuse_filehandle_gc(struct vnode *vp, struct thread *td,
                                            struct ucred *cred,
                                            struct fuse_release_param *frp);
-static int              fuse_access_i(struct vnode *vp, mode_t mode,
-                                      struct ucred *cred, struct thread *td,
-                                      struct fuse_access_param *facp);
 static int              iterate_filehandles(struct vnode *vp, struct thread *td,
                                             struct ucred *cred,
                                             fuse_metrics_t fmetr, void *param);
@@ -109,38 +84,8 @@
                                           struct thread *td, struct ucred *cred,
                                           int flags,
                                           struct fuse_release_param *frp);
-static int              fuse_newentry_backend(struct vnode *dvp,
-                                              struct vnode **vpp,
-                                              struct componentname *cnp,
-                                              enum fuse_opcode op, void *buf,
-                                              size_t bufsize, enum vtype vtyp);
-static __inline void    fuse_make_entry_req(struct mount *mp, uint64_t dnid,
-                                            struct componentname *cnp,
-                                            enum fuse_opcode op, void *buf,
-                                            size_t bufsize,
-                                            struct fuse_dispatcher *fdip);
-static __inline int     checkentry(struct fuse_entry_out *feo, enum vtype vtyp);
-static __inline int     fuse_newentry_core(struct vnode *dvp, struct vnode **vpp,
-                                           enum vtype vtyp,
-                                           struct fuse_dispatcher *fdip);
-static __inline int     fuse_remove_backend(struct vnode *dvp,
-                                            struct vnode *vp,
-                                            struct componentname *cnp,
-                                            enum fuse_opcode op);
-static __inline int     fuse_rename_core(struct vnode *fdvp,
-                                         struct componentname *fcnp,
-                                         struct vnode *tdvp,
-                                         struct componentname *tcnp);
-
 extern int              fuse_read_directbackend(struct fuse_io_data *fioda);
 
-static fuse_buffeater_t fuse_dir_buffeater;
-
-static fuse_handler_t		 fuse_fsync_handler;
-#if FUSE_HAS_CREATE
-static fuse_handler_t		 fuse_forgetful_handler;
-#endif
-
 static fuse_metrics_t fuse_file_ditch;
 static fuse_metrics_t fuse_standard_metrics;
 static fuse_metrics_t fuse_fsync_filehandle;
@@ -155,36 +100,63 @@
 static fo_close_t fuse_close_f;
 
 /* vnode ops */
-static vop_getattr_t  fuse_getattr;
-static vop_reclaim_t  fuse_reclaim;
-static vop_inactive_t fuse_inactive;
-static vop_access_t   fuse_access;
-static vop_lookup_t   fuse_lookup;
-static vop_open_t     fuse_open;
-static vop_close_t    fuse_close;
-static vop_read_t     fuse_read;
-static vop_readdir_t  fuse_readdir;
-static vop_readlink_t fuse_readlink;
-static vop_mknod_t    fuse_mknod;
-static vop_create_t   fuse_create;
-static vop_mkdir_t    fuse_mkdir;
-static vop_link_t     fuse_link;
-static vop_symlink_t  fuse_symlink;
-static vop_remove_t   fuse_remove;
-static vop_rmdir_t    fuse_rmdir;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list