Date: Mon, 13 Jun 2011 15:40:19 GMT From: Ilya Putsikau <ilya@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 194687 for review Message-ID: <201106131540.p5DFeJBr074784@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@194687?ac=10 Change 194687 by ilya@ilya_triton2011 on 2011/06/13 15:39:55 Vnode operations merge. Affected files ... .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#12 edit Differences ... ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#12 (text+ko) ==== @@ -74,7 +74,7 @@ static vop_print_t fuse_vnop_print; static vop_unlock_t fuse_vnop_unlock; -static struct vop_vector fuse_vnops = { +struct vop_vector fuse_vnops = { .vop_default = &default_vnodeops, .vop_access = fuse_vnop_access, .vop_close = fuse_vnop_close, @@ -289,12 +289,11 @@ goto undo; } - err = FSNodeGetOrCreateFileVNodeByID(mp, - feo->nodeid, - dvp, - VREG, /*size*/0, - vpp, - (gone_good_old) ? 0 : FN_CREATING); + err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, VREG, + /*size*/0); + if (!err && !gone_good_old) { + VTOFUD(*vpp)->flag |= FN_CREATING; + } if (err) { if (gone_good_old) { fuse_internal_forget_send(mp, td, cred, feo->nodeid, 1, fdip); @@ -416,7 +415,11 @@ return 0; } -#ifdef XXXVP +#define fusetimespeccmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) + /* struct vnop_getattr_args { struct vnode *a_vp; @@ -428,68 +431,72 @@ static int fuse_vnop_getattr(struct vop_getattr_args *ap) { - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct thread *td = curthread; - struct fuse_dispatcher fdi; - struct timespec uptsp; - int err = 0; + int err = 0; + int dataflag; + struct vnode *vp = ap->a_vp; + struct vattr *vap = ap->a_vap; + struct ucred *cred = ap->a_cred; + struct thread *td = curthread; + struct fuse_dispatcher fdi; + struct timespec uptsp; - /* look for cached attributes */ - nanouptime(&uptsp); - if (timespeccmp(&uptsp, &VTOFUD(vp)->cached_attrs_valid, <=)) { - DEBUG("found valid cached attrs for vp #%llu\n", VTOILLU(vp)); + fuse_trace_printf_vnop(); - if (vap != VTOVA(vp)) - memcpy(vap, VTOVA(vp), sizeof(*vap)); + dataflag = fusefs_get_data(vnode_mount(vp))->dataflag; - return (0); - } + /* Note that we are not bailing out on a dead file system just yet. */ - if (! (fusefs_get_data(vp->v_mount)->dataflag & FSESS_INITED)) { - if (! (vp->v_vflag & VV_ROOT)) { - fdata_kick_set(fusefs_get_data(vp->v_mount)); - err = ENOTCONN; + /* look for cached attributes */ + nanouptime(&uptsp); + if (fusetimespeccmp(&uptsp, &VTOFUD(vp)->cached_attrs_valid, <=)) { + if (vap != VTOVA(vp)) { + memcpy(vap, VTOVA(vp), sizeof(*vap)); + } + debug_printf("fuse_getattr a: returning 0\n"); + return (0); + } - return (err); - } else - goto fake; - } + if (!(dataflag & FSESS_INITED)) { + if (!vnode_isvroot(vp)) { + fdata_kick_set(fusefs_get_data(vnode_mount(vp))); + err = ENOTCONN; + debug_printf("fuse_getattr b: returning ENOTCONN\n"); + return (err); + } else { + goto fake; + } + } - if ((err = fdisp_simple_putget(&fdi, FUSE_GETATTR, vp, td, cred))) { - if (err == ENOTCONN && vp->v_vflag & VV_ROOT) - /* see comment at similar place in fuse_statfs() */ - goto fake; + if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) { + if (err == ENOTCONN && vnode_isvroot(vp)) { + /* see comment at similar place in fuse_statfs() */ + goto fake; + } + debug_printf("fuse_getattr c: returning ENOTCONN\n"); + return (err); + } - return (err); - } + cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); + if (vap != VTOVA(vp)) { + memcpy(vap, VTOVA(vp), sizeof(*vap)); + } - cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); - if (vap != VTOVA(vp)) - memcpy(vap, VTOVA(vp), sizeof(*vap)); + fuse_ticket_drop(fdi.tick); - fuse_ticket_drop(fdi.tick); + if (vnode_vtype(vp) != vap->va_type) { + if (vnode_vtype(vp) == VNON && vap->va_type != VNON) { + // vp->v_type = vap->va_type; + } else { + /* stale vnode */ + // XXX: vnode should be ditched. + debug_printf("fuse_getattr d: returning ENOTCONN\n"); + return (ENOTCONN); + } + } - if (vp->v_type != vap->va_type) { - if (vp->v_type == VNON && vap->va_type != VNON) { - DEBUG2G("vnode #%llu with no type\n", VTOILLU(vp)); - vp->v_type = vap->va_type; - } else { - /* stale vnode */ - DEBUG2G("node #%lu got stale (old type %#x, new type %#x), kicking...\n", - vap->va_fileid, vp->v_type, vap->va_type); - fuse_vnode_ditch(vp, td); - return (ENOTCONN); - } - } + debug_printf("fuse_getattr e: returning 0\n"); - DEBUG("node #%llu, type %d\n", VTOILLU(vp), vap->va_type); -#if _DEBUG - DEBUG2G("\n"); - vn_printf(vp, " * "); -#endif - return (0); + return (0); fake: bzero(vap, sizeof(*vap)); @@ -497,7 +504,6 @@ return (0); } -#endif /* struct vnop_inactive_args { @@ -584,47 +590,44 @@ struct componentname *a_cnp; }; */ -#ifdef XXXIP int fuse_vnop_lookup(struct vop_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; int nameiop = cnp->cn_nameiop; int flags = cnp->cn_flags; - int wantparent = flags & WANTPARENT; + int wantparent = flags & (LOCKPARENT|WANTPARENT); int islastcn = flags & ISLASTCN; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct thread *td = cnp->cn_thread; struct ucred *cred = cnp->cn_cred; + struct mount *mp = vnode_mount(dvp); fuse_trace_printf_vnop(); int err = 0; int lookup_err = 0; struct vnode *vp = NULL; + struct vnode *pdp = NULL; struct fuse_attr *fattr = NULL; struct fuse_dispatcher fdi; enum fuse_opcode op; - uint64_t nid, parentid; + uint64_t nid, parent_nid; struct fuse_access_param facp; -#ifdef INVARIANTS - int cache_attrs_hit = 0; -#endif + uint64_t size = 0; - /* general stuff, based on vfs_cache_lookup */ + if (fuse_isdeadfs(dvp)) { + *vpp = NULL; + return ENXIO; + } -#if _DEBUG - DEBUG2G("root node:\n"); - vn_printf(fusefs_get_data(dvp->v_mount)->rvp, " * "); -#endif - - if (dvp->v_type != VDIR) { + if (vnode_vtype(dvp) != VDIR) { return ENOTDIR; } - if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (nameiop == DELETE || nameiop == RENAME)) { + if (islastcn && vfs_isrdonly(mp) && + ((nameiop == DELETE) || (nameiop == RENAME) || (nameiop == CREATE))) { return (EROFS); } @@ -636,122 +639,121 @@ */ bzero(&facp, sizeof(facp)); - if ( -#ifdef NO_EARLY_PERM_CHECK_HACK - 1 -#else - dvp->v_vflag & VV_ROOT -#endif - ) { - if ((err = fuse_internal_access(dvp, VEXEC, cred, td, &facp))) - return err; + if (vnode_isvroot(dvp)) { /* early permission check hack */ + if ((err = fuse_internal_access(dvp, VEXEC, cred, td, &facp))) { + return err; + } } - DEBUG2G("lookup in #%llu, nameiop %lu, with flags %#x\n", - VTOILLU(dvp), cnp->cn_nameiop, flags); - - /* fetching data from "storage" */ - if (flags & ISDOTDOT) { - DEBUG2G("dotdot lookup!\n"); - nid = VTOFUD(dvp)->parent_nid; - parentid = FUSE_NULL_ID; + pdp = VTOFUD(dvp)->parent; + nid = VTOI(pdp); + parent_nid = VTOFUD(dvp)->parent_nid; fdisp_init(&fdi, 0); op = FUSE_GETATTR; + goto calldaemon; } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { - DEBUG2G("dot lookup!\n"); nid = VTOI(dvp); - parentid = VTOFUD(dvp)->parent_nid; /* irrelevant */ + parent_nid = VTOFUD(dvp)->parent_nid; fdisp_init(&fdi, 0); op = FUSE_GETATTR; + goto calldaemon; } else { - nid = VTOI(dvp); - parentid = VTOI(dvp); - fdisp_init(&fdi, cnp->cn_namelen + 1); - op = FUSE_LOOKUP; + err = cache_lookup(dvp, vpp, cnp); + switch (err) { + + case -1: /* positive match */ +#ifdef XXXIP + fuse_lookup_cache_hits++; +#endif + return 0; + + case 0: /* no match in cache */ +#ifdef XXXIP + fuse_lookup_cache_misses++; +#endif + break; + + case ENOENT: /* negative match */ + /* fall through */ + default: + return err; + } } - fdisp_make(&fdi, dvp->v_mount, op, nid, td, cred); + nid = VTOI(dvp); + parent_nid = VTOI(dvp); + fdisp_init(&fdi, cnp->cn_namelen + 1); + op = FUSE_LOOKUP; + +calldaemon: + fdisp_make(&fdi, vnode_mount(dvp), op, nid, td, cred); if (op == FUSE_LOOKUP) { memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; - DEBUG2G("standard lookup, looking up %s\n", (char *)fdi.indata); } lookup_err = fdisp_wait_answ(&fdi); if (op == FUSE_LOOKUP && !lookup_err) { nid = ((struct fuse_entry_out *)fdi.answ)->nodeid; + size = ((struct fuse_entry_out *)fdi.answ)->attr.size; if (!nid) { /* * zero nodeid is the same as "not found", * but it's also cacheable (which we keep * keep on doing not as of writing this) */ - DEBUG2G("zero nid, ie ENOENT\n"); lookup_err = ENOENT; } else if (nid == FUSE_ROOT_ID) { - DEBUG2G("root inode found on lookup?!!\n"); lookup_err = EINVAL; } } - if (lookup_err && ( - (!fdi.answ_stat) || /* this means messaging error */ - lookup_err != ENOENT || /* daemon reported other error than "legal" ENOENT */ - op != FUSE_LOOKUP /* we tolerate ENOENT only when we sent a LOOKUP */ - )) { + if (lookup_err && + ((!fdi.answ_stat) || lookup_err != ENOENT || op != FUSE_LOOKUP)) { /* * There is error but not lookup related actually * (messaging error) */ - DEBUG("lookup failed b/c messaging crap\n"); return (lookup_err); } - /* analyzing answer */ - /* * Now we got the answer and filtered out the crap, too, so we know that * "found" iff lookup_err == 0 */ if (lookup_err) { - DEBUG("looked up thingy not found\n"); - if ((nameiop == CREATE || nameiop == RENAME) - && islastcn - /* && directory dvp has not been removed */) { + if ((nameiop == CREATE || nameiop == RENAME) && + islastcn /* && directory dvp has not been removed */) { - if (dvp->v_mount->mnt_flag & MNT_RDONLY) { - err = EROFS; - goto out; - } + if (vfs_isrdonly(mp)) { + err = EROFS; + goto out; + } - DEBUG("create/rename -- we have to make it\n"); - /* - * Check for write access on directory. - */ - - if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) - goto out; +#if 0 // THINK_ABOUT_THIS + if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) { + goto out; + } +#endif - /* - * Possibly record the position of a slot in the - * directory large enough for the new component name. - * This can be recorded in the vnode private data for - * dvp. Set the SAVENAME flag to hold onto the - * pathname for use later in VOP_CREATE or VOP_RENAME. - */ - cnp->cn_flags |= SAVENAME; - - err = EJUSTRETURN; - goto out; + /* + * Possibly record the position of a slot in the + * directory large enough for the new component name. + * This can be recorded in the vnode private data for + * dvp. Set the SAVENAME flag to hold onto the + * pathname for use later in VOP_CREATE or VOP_RENAME. + */ + cnp->cn_flags |= SAVENAME; + + err = EJUSTRETURN; + goto out; } - /* - * Consider inserting name into cache. - */ + /* Consider inserting name into cache. */ /* * No we can't use negative caching, as the fs @@ -772,13 +774,13 @@ goto out; } else { + if (op == FUSE_GETATTR) { fattr = &((struct fuse_attr_out *)fdi.answ)->attr; } else { fattr = &((struct fuse_entry_out *)fdi.answ)->attr; } - DEBUG("we found something...\n"); /* * If deleting, and at end of pathname, return parameters * which can be used to remove file. If the wantparent flag @@ -786,11 +788,9 @@ * and lock the inode, being careful with ".". */ if (nameiop == DELETE && islastcn) { - DEBUG("something to delete\n"); /* * Check for write access on directory. */ - facp.xuid = fattr->uid; facp.facc_flags |= FACCESS_STICKY; err = fuse_internal_access(dvp, VWRITE, cred, td, &facp); @@ -801,95 +801,112 @@ } if (nid == VTOI(dvp)) { - VREF(dvp); + vref(dvp); *vpp = dvp; goto out; } - if ((err = fuse_vget_i(dvp->v_mount, td, - nid, - IFTOVT(fattr->mode), - &vp, - VG_NORMAL, - parentid))) { - goto out; + /* + * XXX We discard generation, also brought to us by + * LOOKUP. It's purpose is unclear... it seems to be + * simply just yet another 32/64 bit extension for the + * inode number, but I'm not sure (hmm, it seems to + * have something to do with NFS exportability, too). + * + * (Linux has such a 32 bit value in its inode struct, + * and it really might just be a backward compatible + * extension for the inode space [but might as well + * be more into it, dunno]. The FUSE protocol uses + * a 64 bit generation value; FUSE/Linux uses it for + * filling the inode's i_generation field.) + */ + err = fuse_vnode_get(dvp->v_mount, + nid, + dvp, + &vp, + cnp, + IFTOVT(fattr->mode), + size); + if (err) { + goto out; } *vpp = vp; goto out; + } + + /* + * If rewriting (RENAME), return the inode and the + * information required to rewrite the present directory + * Must get inode of directory entry to verify it's a + * regular file, or empty directory. + */ + if (nameiop == RENAME && wantparent && islastcn) { + +#if 0 // THINK_ABOUT_THIS + if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) { + goto out; } +#endif /* - * If rewriting (RENAME), return the inode and the - * information required to rewrite the present directory - * Must get inode of directory entry to verify it's a - * regular file, or empty directory. + * Check for "." */ - if (nameiop == RENAME && wantparent && islastcn) { - DEBUG("something to rename...\n"); + if (nid == VTOI(dvp)) { + err = EISDIR; + goto out; + } - facp.xuid = fattr->uid; - facp.facc_flags |= FACCESS_STICKY; - err = fuse_internal_access(dvp, VWRITE, cred, td, &facp); - facp.facc_flags &= ~FACCESS_XQUERIES; + err = fuse_vnode_get(vnode_mount(dvp), + nid, + dvp, + &vp, + cnp, + IFTOVT(fattr->mode), + size); + if (err) { + goto out; + } - if (err) - goto out; + *vpp = vp; + /* + * Save the name for use in VOP_RENAME later. + */ + cnp->cn_flags |= SAVENAME; - /* - * Check for "." - */ - if (nid == VTOI(dvp)) { - err = EISDIR; - goto out; - } + goto out; + } - err = fuse_vget_i(dvp->v_mount, td, nid, - IFTOVT(fattr->mode), &vp, VG_NORMAL, - parentid); - if (err) - goto out; - *vpp = vp; - /* - * Save the name for use in VOP_RENAME later. - */ - cnp->cn_flags |= SAVENAME; - - goto out; + if (flags & ISDOTDOT) { + vref(pdp); + *vpp = pdp; + } else if (nid == VTOI(dvp)) { + vref(dvp); + *vpp = dvp; + } else { + err = fuse_vnode_get(vnode_mount(dvp), + nid, + dvp, + &vp, + cnp, + IFTOVT(fattr->mode), + size); + if (err) { + goto out; } - - DEBUG("we peacefully found that file\n"); - - if (nid == VTOI(dvp)) { - VREF(dvp); /* We want ourself, ie "." */ - *vpp = dvp; - } else { - if (flags & ISDOTDOT) - /* - * If doing dotdot, we unlock dvp for vget time - * to conform lock order regulations. - */ - VOP_UNLOCK(dvp, 0); - err = fuse_vget_i(dvp->v_mount, td, nid, - IFTOVT(fattr->mode), &vp, VG_NORMAL, - parentid); - if (flags & ISDOTDOT) - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - if (err) - goto out; - *vpp = vp; + if (vnode_vtype(vp) == VDIR) { + VTOFUD(vp)->parent = dvp; + //SETPARENT(vp, dvp); } + *vpp = vp; + } if (op == FUSE_GETATTR) cache_attrs(*vpp, (struct fuse_attr_out *)fdi.answ); else cache_attrs(*vpp, (struct fuse_entry_out *)fdi.answ); -#ifdef INVARIANTS - cache_attrs_hit = 1; -#endif - /* Insert name into cache if appropriate. */ /* @@ -915,27 +932,19 @@ */ #if 0 if (cnp->cn_flags & MAKEENTRY) { - DEBUG("...caching\n"); cache_enter(dvp, *vpp, cnp); } #endif } out: if (!lookup_err) { - DEBUG("as the looked up thing was simply found, the cleanup is left for us\n"); - + // as the looked up thing was simply found, the cleanup is left for us if (err) { - DEBUG("though inode found, err exit with no vnode\n"); + // though inode found, err exit with no vnode if (op == FUSE_LOOKUP) - fuse_internal_forget_send(dvp->v_mount, td, cred, nid, 1, &fdi); + fuse_internal_forget_send(vnode_mount(dvp), td, cred, nid, 1, &fdi); return (err); } else { - if (op == FUSE_LOOKUP) - VTOFUD(*vpp)->nlookup++; - - if (islastcn && flags & ISOPEN) - VTOFUD(*vpp)->flags |= FVP_ACCESS_NOOP; - #ifndef NO_EARLY_PERM_CHECK_HACK if (!islastcn) { /* We have the attributes of the next item @@ -966,18 +975,21 @@ * dir in question. But that can be known only * by having the vnode... */ + int tmpvtype = vnode_vtype(*vpp); + bzero(&facp, sizeof(facp)); - DEBUG("the early perm check hack\n"); + // the early perm check hack facp.facc_flags |= FACCESS_VA_VALID; - KASSERT(cache_attrs_hit, - (("invalid reference to cached attrs"))); - if ((*vpp)->v_type != VDIR && (*vpp)->v_type != VLNK) + if (tmpvtype != VDIR && tmpvtype != VLNK) err = ENOTDIR; - if (!err && !(*vpp)->v_mountedhere) + + if (!err && !vnode_mountedhere(*vpp)) { err = fuse_internal_access(*vpp, VEXEC, cred, td, &facp); + } + if (err) { - if ((*vpp)->v_type == VLNK) + if (tmpvtype == VLNK) DEBUG("weird, permission error with a symlink?\n"); vput(*vpp); *vpp = NULL; @@ -991,9 +1003,7 @@ return (err); } -#endif - /* struct vnop_mkdir_args { struct vnode *a_dvp; @@ -1199,17 +1209,68 @@ static int fuse_vnop_read(struct vop_read_args *ap) { + int err; struct vnode *vp = ap->a_vp; - struct ucred *cred = ap->a_cred; struct uio *uio = ap->a_uio; +#ifdef XXXIP int ioflag = ap->a_ioflag; + struct ucred *cred = ap->a_cred; +#endif + off_t orig_resid; + off_t orig_offset; - DEBUG2G("vnode #%llu\n", VTOILLU(vp)); - return fuse_io_vnode(vp, cred, uio, ioflag); + struct fuse_vnode_data *fvdat; + + fuse_trace_printf_vnop(); + + if (fuse_isdeadfs_nop(vp)) { + if (vnode_vtype(vp) != VCHR) { + return EIO; + } else { + return 0; + } + } + + if (uio_offset(uio) < 0) { + return EINVAL; + } + + /* + * if (uio_offset(uio) > SOME_MAXIMUM_SIZE) { + * return 0; + * } + */ + + orig_resid = uio_resid(uio); + if (orig_resid == 0) { + return 0; + } + + orig_offset = uio_offset(uio); + if (orig_offset < 0) { + return EINVAL; + } + + fvdat = VTOFUD(vp); + if (!fvdat) { + return EINVAL; + } + + /* Protect against size change here. */ + + if (vnode_isreg(vp)) { +#ifdef XXXIP + err = cluster_read(vp, uio, fvdat->filesize, 0); +#endif + } else if (vnode_isdir(vp)) { + err = EISDIR; + } else { + err = EPERM; + } + + return err; } -#define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1) - /* struct vnop_readdir_args { struct vnode *a_vp; @@ -1226,48 +1287,47 @@ struct vnode *vp = ap->a_vp; struct ucred *cred = ap->a_cred; struct uio *uio = ap->a_uio; - - struct thread *td = curthread; + int freefufh = 0; int err = 0; struct fuse_iov cookediov; struct fuse_filehandle *fufh; - struct fuse_io_data fioda; - struct get_filehandle_param gefhp; + struct fuse_vnode_data *fvdat; + + fuse_trace_printf_vnop(); + + if (fuse_isdeadfs_nop(vp)) { + return EBADF; + } + +#ifdef XXXIP + /* Sanity check the uio data. */ + if ((uio_iovcnt(uio) > 1) || + (uio_resid(uio) < (int)sizeof(struct dirent))) { + return (EINVAL); + } +#endif + + fvdat = VTOFUD(vp); - bzero(&gefhp, sizeof(gefhp)); - gefhp.opcode = FUSE_OPENDIR; - if ((err = fuse_get_filehandle(vp, td, cred, FREAD, &fufh, &gefhp))) { - DEBUG2G("fetching filehandle failed\n"); - return (err); + fufh = &(fvdat->fufh[FUFH_RDONLY]); + if (!(fufh->fufh_flags & FUFH_VALID)) { + err = fuse_filehandle_get(vp, NULL, cred, FUFH_RDONLY); + if (err) { + return err; + } + freefufh = 1; } - /* - * In "most cases" this will do and won't have to resize the buffer - * (that is, if the daemon has a "tight" view of the dir entries, - * which is the case if userspace uses the old API or the new one - * in the analogous way; by our terminology, this means - * freclen == bytesavail) - * (See fuse_internal_readdir_processdata). - */ +#define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1) fiov_init(&cookediov, DIRCOOKEDSIZE); - bzero(&fioda, sizeof(fioda)); - fioda.vp = vp; - fioda.fufh = fufh; - fioda.uio = uio; - fioda.cred = cred; - fioda.opcode = FUSE_READDIR; - fioda.buffeater = fuse_internal_readdir_processdata; - fioda.param = &cookediov; - /* - * We tried hard to use bio, but offsety readdir can't be handled - * properly that way -- the offset field of fuse_dirents can't be - * mapped to an offset of a bio buffer - */ - err = fuse_read_directbackend(&fioda); + err = fuse_internal_readdir(vp, uio, fufh, &cookediov); fiov_teardown(&cookediov); - fufh->useco--; + if (freefufh) { + fufh->open_count--; + (void)fuse_filehandle_put(vp, NULL, NULL, FUFH_RDONLY, 0); + } fuse_invalidate_attr(vp); return err; @@ -1286,19 +1346,27 @@ int err; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; + struct ucred *cred = ap->a_cred; struct fuse_dispatcher fdi; fuse_trace_printf_vnop(); - if ((err = fdisp_simple_putget(&fdi, FUSE_READLINK, vp, curthread, - ap->a_cred))) - return (err); + if (fuse_isdeadfs_nop(vp)) { + return EBADF; + } + + if (vnode_vtype(vp) != VLNK) { + return EINVAL; + } + + if ((err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred))) { + return err; + } if (((char *)fdi.answ)[0] == '/' && - fusefs_get_data(vp->v_mount)->dataflag & FSESS_PUSH_SYMLINKS_IN) { - char *mpth = vp->v_mount->mnt_stat.f_mntonname; - - err = uiomove(mpth, strlen(mpth), uio); + fusefs_get_data(vnode_mount(vp))->dataflag & FSESS_PUSH_SYMLINKS_IN) { + char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname; + err = uiomove(mpth, strlen(mpth), uio); } if (!err) { @@ -1320,18 +1388,46 @@ static int fuse_vnop_reclaim(struct vop_reclaim_args *ap) { + int type; struct vnode *vp = ap->a_vp; struct thread *td = ap->a_td; + struct fuse_vnode_data *fvdat = VTOFUD(vp); + struct fuse_filehandle *fufh = NULL; + + fuse_trace_printf_vnop(); + + if (!fvdat) { + panic("FUSE: no vnode data during recycling"); + } + + for (type = 0; type < FUFH_MAXTYPE; type++) { + fufh = &(fvdat->fufh[type]); + if (fufh->fufh_flags & FUFH_VALID) { + if (fufh->fufh_flags & FUFH_STRATEGY) { + fufh->fufh_flags &= ~FUFH_MAPPED; + fufh->open_count = 0; + (void)fuse_filehandle_put(vp, td, NULL, type, 0); + } else { + panic("vnode being reclaimed but fufh (type=%d) is valid", + type); + } + } + } - DEBUG("pfft...\n"); -#if _DEBUG - DEBUG2G("=============>\n"); - kdb_backtrace(); - vn_printf(vp, " "); - DEBUG2G("<=============\n"); -#endif + if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) { + struct fuse_dispatcher fdi; + fdi.tick = NULL; + fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp), + fvdat->nlookup, &fdi); + } + + cache_purge(vp); + /* XXXIP TODO */ + vfs_hash_remove(vp); vnode_destroy_vobject(vp); - return (fuse_recyc_backend(vp, td)); + fuse_vnode_destroy(vp); + + return 0; } /* @@ -1348,6 +1444,18 @@ struct vnode *vp = ap->a_vp; struct componentname *cnp = ap->a_cnp; + fuse_trace_printf_vnop(); + + if (fuse_isdeadfs_nop(vp)) { + panic("fuse_vnop_remove(): called on a dead file system"); + } + + if (vnode_isdir(vp)) { + return EPERM; + } + + cache_purge(vp); + return (fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK)); } @@ -1364,252 +1472,34 @@ static int fuse_vnop_rename(struct vop_rename_args *ap) { - struct vnode *tvp = ap->a_tvp; - struct vnode *tdvp = ap->a_tdvp; - struct vnode *fvp = ap->a_fvp; - struct vnode *fdvp = ap->a_fdvp; - struct componentname *tcnp = ap->a_tcnp; - struct componentname *fcnp = ap->a_fcnp; + int err = 0; + struct vnode *fdvp = ap->a_fdvp; + struct vnode *fvp = ap->a_fvp; + struct componentname *tcnp = ap->a_tcnp; + struct vnode *tdvp = ap->a_tdvp; + struct vnode *tvp = ap->a_tvp; + struct componentname *fcnp = ap->a_fcnp; - int doingdirectory = 0; - int err = 0; - struct thread *td; - struct fuse_access_param facp; - uint64_t fnid, tdnid; - struct fuse_data *data = NULL; - struct parentmanager_param pmp; - struct vnode *xvp; + fuse_trace_printf_vnop(); - td = curthread; - bzero(&facp, sizeof(facp)); + if (fuse_isdeadfs_nop(fdvp)) { + panic("fuse_vnop_rename(): called on a dead file system"); + } >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106131540.p5DFeJBr074784>