From owner-p4-projects@FreeBSD.ORG Tue Jun 7 10:56:16 2011 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id C21A71065673; Tue, 7 Jun 2011 10:56:16 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 750BC106566C for ; Tue, 7 Jun 2011 10:56:16 +0000 (UTC) (envelope-from ilya@FreeBSD.org) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:4f8:fff6::2d]) by mx1.freebsd.org (Postfix) with ESMTP id 630248FC1D for ; Tue, 7 Jun 2011 10:56:16 +0000 (UTC) Received: from skunkworks.freebsd.org (localhost [127.0.0.1]) by skunkworks.freebsd.org (8.14.4/8.14.4) with ESMTP id p57AuGno053169 for ; Tue, 7 Jun 2011 10:56:16 GMT (envelope-from ilya@FreeBSD.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id p57AuGS4053166 for perforce@freebsd.org; Tue, 7 Jun 2011 10:56:16 GMT (envelope-from ilya@FreeBSD.org) Date: Tue, 7 Jun 2011 10:56:16 GMT Message-Id: <201106071056.p57AuGS4053166@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to ilya@FreeBSD.org using -f From: Ilya Putsikau To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 194383 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 07 Jun 2011 10:56:17 -0000 http://p4web.freebsd.org/@@194383?ac=10 Change 194383 by ilya@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 #include #include +#include #include -#include #include +#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #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 #include +#include #include #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) <<<