From owner-p4-projects@FreeBSD.ORG Mon Jun 13 15:35:55 2011 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 481D01065689; Mon, 13 Jun 2011 15:35:55 +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 09CBA1065680 for ; Mon, 13 Jun 2011 15:35:55 +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 EB0DE8FC1C for ; Mon, 13 Jun 2011 15:35:54 +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 p5DFZs3L074595 for ; Mon, 13 Jun 2011 15:35:54 GMT (envelope-from ilya@FreeBSD.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.4/8.14.4/Submit) id p5DFZsQb074591 for perforce@freebsd.org; Mon, 13 Jun 2011 15:35:54 GMT (envelope-from ilya@FreeBSD.org) Date: Mon, 13 Jun 2011 15:35:54 GMT Message-Id: <201106131535.p5DFZsQb074591@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 194684 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: Mon, 13 Jun 2011 15:35:55 -0000 http://p4web.freebsd.org/@@194684?ac=10 Change 194684 by ilya@ilya_triton2011 on 2011/06/13 15:35:37 Fix internal functions definfions, rename fdisp_simple_vfs_getattr -> fdisp_simple_vfs_statfs Affected files ... .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_file.c#2 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.c#6 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.h#8 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_ipc.h#6 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#11 edit Differences ... ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_file.c#2 (text+ko) ==== @@ -3,14 +3,34 @@ * Amit Singh */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "fuse.h" #include "fuse_file.h" +#include "fuse_internal.h" #include "fuse_ipc.h" #include "fuse_node.h" -#include "fuse_sysctl.h" int -fuse_filehandle_get(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type) +fuse_filehandle_get(struct vnode *vp, struct thread *td, struct ucred *cred, fufh_type_t fufh_type) { struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_dispatcher fdi; @@ -42,7 +62,7 @@ } fdisp_init(&fdi, sizeof(*foi)); - fdisp_make_vp(&fdi, op, vp, context); + fdisp_make_vp(&fdi, op, vp, td, cred); foi = fdi.indata; foi->flags = oflags; @@ -68,7 +88,7 @@ } int -fuse_filehandle_put(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, +fuse_filehandle_put(struct vnode *vp, struct thread *td, struct ucred *cred, fufh_type_t fufh_type, int foregrounded) { struct fuse_dispatcher fdi; @@ -103,7 +123,7 @@ } fdisp_init(&fdi, sizeof(*fri)); - fdisp_make_vp(&fdi, op, vp, context); + fdisp_make_vp(&fdi, op, vp, td, cred); fri = fdi.indata; fri->fh = fufh->fh_id; fri->flags = fufh->open_flags; ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.c#6 (text+ko) ==== @@ -280,8 +280,6 @@ int fuse_internal_readdir(struct vnode *vp, struct uio *uio, - struct thread *td, - struct ucred *cred, struct fuse_filehandle *fufh, struct fuse_iov *cookediov) { @@ -300,7 +298,7 @@ while (uio_resid(uio) > 0) { fdi.iosize = sizeof(*fri); - fdisp_make_vp(&fdi, FUSE_READDIR, vp, td, cred); + fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL); fri = fdi.indata; fri->fh = fufh->fh_id; @@ -544,6 +542,7 @@ int fuse_internal_newentry_core(struct vnode *dvp, struct vnode **vpp, + struct componentname *cnp, enum vtype vtyp, struct fuse_dispatcher *fdip) { @@ -563,8 +562,8 @@ goto out; } - err = fuse_vget_i(mp, curthread, feo->nodeid, vtyp, vpp, - VG_FORCENEW, VTOI(dvp)); + err = fuse_vnode_get(mp, feo->nodeid, dvp, vpp, cnp, + vtyp, 0); if (err) { fuse_internal_forget_send(mp, curthread, NULL, feo->nodeid, 1, fdip); return err; @@ -593,7 +592,7 @@ fdisp_init(&fdi, 0); fuse_internal_newentry_makerequest(vnode_mount(dvp), VTOI(dvp), cnp, op, buf, bufsize, &fdi); - err = fuse_internal_newentry_core(dvp, vpp, vtyp, &fdi); + err = fuse_internal_newentry_core(dvp, vpp, cnp, vtyp, &fdi); fuse_invalidate_attr(dvp); return (err); ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_internal.h#8 (text+ko) ==== @@ -14,12 +14,24 @@ #include "fuse_ipc.h" #include "fuse_node.h" +static __inline int +vfs_isrdonly(struct mount *mp) +{ + return ((mp->mnt_flag & MNT_RDONLY) != 0 ? 1 : 0); +} + static __inline struct mount * vnode_mount(struct vnode *vp) { return (vp->v_mount); } +static __inline int +vnode_mountedhere(struct vnode *vp) +{ + return (vp->v_mountedhere != NULL ? 1 : 0); +} + static __inline enum vtype vnode_vtype(struct vnode *vp) { @@ -32,6 +44,18 @@ return ((vp->v_vflag & VV_ROOT) != 0 ? 1 : 0); } +static __inline int +vnode_isreg(struct vnode *vp) +{ + return (vp->v_type == VREG ? 1 : 0); +} + +static __inline int +vnode_isdir(struct vnode *vp) +{ + return (vp->v_type == VDIR ? 1 : 0); +} + static __inline ssize_t uio_resid(struct uio *uio) { @@ -50,6 +74,12 @@ uio->uio_offset = offset; } +static __inline void +uio_setresid(struct uio *uio, ssize_t resid) +{ + uio->uio_resid = resid; +} + /* XXX */ void cluster_push(struct vnode *vp, int a); @@ -166,8 +196,6 @@ int fuse_internal_readdir(struct vnode *vp, struct uio *uio, - struct thread *td, - struct ucred *cred, struct fuse_filehandle *fufh, struct fuse_iov *cookediov); @@ -246,6 +274,7 @@ int fuse_internal_newentry_core(struct vnode *dvp, struct vnode **vpp, + struct componentname *cnp, enum vtype vtyp, struct fuse_dispatcher *fdip); ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_ipc.h#6 (text+ko) ==== @@ -302,14 +302,12 @@ return (fdisp_wait_answ(fdip)); } -static __inline__ int -fdisp_simple_vfs_getattr(struct fuse_dispatcher *fdip, - struct mount *mp, - struct thread *td, - struct ucred *cred) +static __inline int +fdisp_simple_vfs_statfs(struct fuse_dispatcher *fdip, + struct mount *mp) { fdisp_init(fdip, 0); - fdisp_make(fdip, mp, FUSE_STATFS, FUSE_ROOT_ID, td, cred); + fdisp_make(fdip, mp, FUSE_STATFS, FUSE_ROOT_ID, NULL, NULL); return (fdisp_wait_answ(fdip)); } ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#11 (text+ko) ==== @@ -46,60 +46,6 @@ #include -#if 0 -/* function prototype for iterators over filehandles (of a vp) */ -typedef int fuse_metrics_t(struct fuse_filehandle *fufh, struct thread *td, - struct ucred *cred, void *param); - - -/* parameter struct for fuse_standard_metrics() */ -struct standard_metrics_param { - int mode; - enum fuse_opcode op; - struct fuse_filehandle *fufh; -}; - -struct fuse_release_param { - int err; - uint8_t fg:1; - uint8_t flush:1; -}; - -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 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 iterate_filehandles(struct vnode *vp, struct thread *td, - struct ucred *cred, - fuse_metrics_t fmetr, void *param); -#if FUSE_HAS_CREATE -static __inline int create_filehandle(struct vnode *vp, struct thread *td, - struct ucred *cred, int mode, - struct fuse_dispatcher *fdip); -#endif -static void fuse_send_release(struct fuse_filehandle *fufh, - struct thread *td, struct ucred *cred, - int flags, - struct fuse_release_param *frp); -extern int fuse_read_directbackend(struct fuse_io_data *fioda); - -static fuse_metrics_t fuse_file_ditch; -static fuse_metrics_t fuse_standard_metrics; -static fuse_metrics_t fuse_fsync_filehandle; -static fuse_metrics_t release_filehandle; - -#if FUSE_HAS_CREATE -static vfs_hash_cmp_t fuse_vnode_fgdrop_cmp; -#endif -static vfs_hash_cmp_t fuse_vnode_findparent_cmp; - -/* file ops */ -static fo_close_t fuse_close_f; - /* vnode ops */ static vop_access_t fuse_vnop_access; static vop_close_t fuse_vnop_close; @@ -159,162 +105,11 @@ .vop_unlock = fuse_vnop_unlock, }; -struct fileops fuse_fileops = { - .fo_read = fuse_io_file, - .fo_write = fuse_io_file, - /* - * following fields are filled from vnops, but "vnops.foo" is not - * legitimate in a definition, so we set them at module load time - */ - .fo_ioctl = NULL, - .fo_poll = NULL, - .fo_kqfilter = NULL, - .fo_stat = NULL, - .fo_close = fuse_close_f, - .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE -}; - -#if FUSE_HAS_CREATE -struct vop_vector fuse_germ_vnops; -#endif - MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data"); MALLOC_DEFINE(M_FUSEFH, "fuse_filehandles", "buffer for fuse filehandles"); int fuse_pbuf_freecnt = -1; -/****************** - * - * >>> VFS hash comparators - * - ******************/ - -#if FUSE_HAS_CREATE -/* - * Vnode comparison function with which the given vnode always - * gets inserted, but got marked invalid upon a clash. Caller - * is free (and expected to) deal with clashes. - */ - -int -fuse_vnode_fgdrop_cmp(struct vnode *vp, void *param) -{ - struct fuse_vnode_data *fvdat = param; - - if (VTOI(vp) == fvdat->nid) - fvdat->nid = FUSE_NULL_ID; - - return (1); -} -#endif - -/* - * A skewed use of the vfs hash subsystem for finding out parent - * nodeid. This comparator never matches, just collects data during - * scanning through the nodes (without vnode locking). - */ - -static int -fuse_vnode_findparent_cmp(struct vnode *vp, void *param) -{ - struct parentmanager_param *pmp = param; - - /* - * In general, we'd need a (nodeid, vtyp) pair to match - * but we may assume that the type is directory, because - * that's what users of this function will want. - */ - - if (VTOI(vp) == pmp->nodeid && vp->v_type == VDIR) { - KASSERT(! pmp->valid, - ("more than one vnode seems to match #%llu", - (unsigned long long)pmp->nodeid)); - pmp->parent_nid = VTOFUD(vp)->parent_nid; - pmp->valid = 1; - } - - return (1); -} - -/****************** - * - * >>> Vnode related aux routines - * - ******************/ - -static __inline void -fuse_vnode_init_data(struct vnode *vp, struct fuse_vnode_data *fvdat, - uint64_t nodeid) -{ - fvdat->nid = nodeid; - vp->v_data = fvdat; -} - -static __inline void -fuse_vnode_init_misc(struct vnode *vp, enum vtype vtyp, uint64_t parentid) -{ - struct fuse_vnode_data *fvdat = VTOFUD(vp); - - VNASSERT(fvdat, vp, (("init_misc on virgin vnode"))); - - fvdat->parent_nid = parentid; - vp->v_type = vtyp; - - LIST_INIT(&fvdat->fh_head); - - vp->v_bufobj.bo_private = vp; -} - -void -fuse_vnode_init(struct vnode *vp, struct fuse_vnode_data *fvdat, - uint64_t nodeid, enum vtype vtyp, uint64_t parentid) -{ - fuse_vnode_init_data(vp, fvdat, nodeid); - fuse_vnode_init_misc(vp, vtyp, parentid); -} - -void -fuse_vnode_ditch(struct vnode *vp, struct thread *td) -{ - if (! td) - td = curthread; - - if (vp->v_vflag & VV_ROOT) { - fdata_kick_set(fusefs_get_data(vp->v_mount)); - return; - } - DEBUG2G("vp %p, #%llu\n", vp, VTOILLU(vp)); - vnode_destroy_vobject(vp); - /* - * this implies we won't get feedback on recycling - * (other than panicking, or the lack of that) - * but creating a customized set of bad vnode ops - * would be too much hassle... - */ - vp->v_op = &dead_vnodeops; - fuse_recyc_backend(vp, td); -} - -void -fuse_vnode_teardown(struct vnode *vp, struct thread *td, struct ucred *cred, - enum vtype vtyp) -{ - struct fuse_dispatcher fdi; - struct fuse_vnode_data *fvdat = VTOFUD(vp); - - if (vp->v_type == vtyp) { - bzero(&fdi, sizeof(fdi)); - vfs_hash_remove(vp); - fuse_internal_forget_send(vp->v_mount, td, cred, fvdat->nid, - fvdat->nlookup, &fdi); - fvdat->nid = FUSE_NULL_ID; - } else - fuse_vnode_ditch(vp, td); - - vput(vp); -} -#endif - /* struct vnop_access_args { struct vnode *a_vp; @@ -2135,7 +1930,7 @@ ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len); - err = fuse_internal_newentry_core(dvp, vpp, VLNK, &fdi); + err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi); fuse_invalidate_attr(dvp); return (err); } @@ -2476,503 +2271,3 @@ return vop_stdunlock(ap); } - -static int -release_filehandle(struct fuse_filehandle *fufh, struct thread *td, - struct ucred *cred, void *param) -{ - KASSERT(fufh->useco >= 0, - ("negative use count for fuse filehandle #%llu@#%llu", - (long long unsigned)fufh->fh_id, VTOILLU(fufh->fh_vp))); - KASSERT(! fufh->fp || fufh->useco > 0, - ("filehandle bound with 0 use counter")); - DEBUG2G("vnode #%llu, fufh %p #%llu, owner file %p, useco %d\n", - VTOILLU(fufh->fh_vp), fufh, (long long unsigned) fufh->fh_id, - fufh->fp, fufh->useco); - if (! fufh->fp && fufh->useco == 0) { - LIST_REMOVE(fufh, fh_link); - fuse_send_release(fufh, td, cred, fufh->mode, param); - } - - return (0); -} - -static void -fuse_filehandle_gc(struct vnode *vp, struct thread *td, struct ucred *cred, - struct fuse_release_param *frp) -{ - ASSERT_VOP_ELOCKED__FH(vp); - iterate_filehandles(vp, td, cred, release_filehandle, frp); -} - -static int -iterate_filehandles(struct vnode *vp, struct thread *td, struct ucred *cred, - fuse_metrics_t fmetr, void *param) -{ - struct fuse_filehandle *fufh, *fufhxxx; - struct fuse_vnode_data *fvdat = VTOFUD(vp); - int rv = 0; - - RECTIFY_TDCR(td, cred); - - LIST_FOREACH_SAFE(fufh, &fvdat->fh_head, fh_link, fufhxxx) { - KASSERT(fufh->fh_vp == vp, - ("vnode mismatch for fuse_filehandle %p\n", fufh)); - if ((rv = fmetr(fufh, td, cred, param))) - return (rv); - } - - return (0); -} - -static int -fuse_standard_metrics(struct fuse_filehandle *fufh, struct thread *td, - struct ucred *cred, void *param) -{ - struct standard_metrics_param *stmp = param; - - DEBUG2G("fufh->mode %#x, mode %#x\n", fufh->mode, stmp->mode); - if (fufh->cred->cr_uid == cred->cr_uid && - fufh->cred->cr_rgid == cred->cr_rgid && - fufh->pid == td->td_proc->p_pid && - ((fufh->mode ^ stmp->mode) & ~(O_CREAT | O_EXCL | O_TRUNC)) == 0 && - fufh->op == stmp->op) { - stmp->fufh = fufh; - fufh->useco++; - return (-1); - } - - return (0); -} - -#if FUSE_HAS_CREATE -static __inline int -create_filehandle(struct vnode *vp, struct thread *td, struct ucred *cred, - int mode, struct fuse_dispatcher *fdip) -{ - struct fuse_vnode_data *fvdat = VTOFUD(vp); - uint64_t parentid = fvdat->parent_nid; - struct componentname *cnp = fvdat->germcnp; - struct fuse_open_in *foi; - struct fuse_entry_out *feo; - struct fuse_mknod_in fmni; - int err; - int gone_good_old = 0; - struct vnode *clashvp; - - vp->v_data = NULL; - mode &= ~O_NOCTTY; - - fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1); - - if (fusefs_get_data(vp->v_mount)->dataflag & FSESS_NOCREATE) - goto good_old; - fdisp_make(fdip, vp->v_mount, FUSE_CREATE, parentid, td, cred); - - /* - * Looks stupid, but this is how we could smuggle in these - * values from fuse_create... - */ - foi = fdip->indata; - foi->flags = OFLAGS(mode); - foi->mode = fvdat->flags; - - memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr, - cnp->cn_namelen); - ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0'; - - err = fdisp_wait_answ(fdip); - - if (err == ENOSYS) { - fusefs_get_data(vp->v_mount)->dataflag |= FSESS_NOCREATE; - fdip->tick = NULL; - goto good_old; - } else if (err) - goto undo; - - goto bringup; - -good_old: - gone_good_old = 1; - fmni.mode = fvdat->flags; - fmni.rdev = 0; - fuse_internal_newentry_makerequest(vp->v_mount, parentid, cnp, FUSE_MKNOD, - &fmni, sizeof(fmni), fdip); - err = fdisp_wait_answ(fdip); - if (err) - goto undo; - -bringup: - feo = fdip->answ; - - if ((err = fuse_internal_checkentry(feo, VREG))) { - fuse_ticket_drop(fdip->tick); - goto undo; - } - - bzero(fvdat, sizeof(*fvdat)); - fuse_vnode_init(vp, fvdat, feo->nodeid, VREG, parentid); - fvdat->nlookup++; - vp->v_op = &fuse_vnops; - cache_attrs(vp, feo); - -try_insert: - VOP_UNLOCK(vp, 0); - /* - * We can't let the vnode being vput() here, the caller wants - * that do by herself. - * That means hash collisions must be relaxed. With a funky - * comparison function insertion will succeed, but we get a clear - * sign of the collision and we can handle it by ourselves. - */ - err = vfs_hash_get(vp->v_mount, feo->nodeid, LK_EXCLUSIVE, td, - &clashvp, fuse_vnode_cmp, &feo->nodeid); - if (! err && clashvp) - fuse_vnode_teardown(clashvp, td, cred, VREG); - - if (! err) { - err = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - if (err) - printf("fuse4bsd: leaking vnode %p\n", vp); - else { - struct mount *mp = vp->v_mount; - - vp->v_mount = NULL; - err = insmntque(vp, mp); - } - } - - if (! err) - err = vfs_hash_insert(vp, feo->nodeid, LK_EXCLUSIVE, td, - &clashvp, fuse_vnode_fgdrop_cmp, fvdat); - if (! err && fvdat->nid == FUSE_NULL_ID) { - vfs_hash_remove(vp); - fvdat->nid = feo->nodeid; - goto try_insert; - } - - if (err) { - if (gone_good_old) - fuse_internal_forget_send(vp->v_mount, td, cred, feo->nodeid, 1, - fdip); - else { - struct fuse_release_in *fri; - uint64_t nodeid = feo->nodeid; - uint64_t fh_id = ((struct fuse_open_out *)(feo + 1))->fh; - struct fuse_pidcred *pidcred; - - fdisp_init(fdip, sizeof(*fri)); - fdisp_make(fdip, vp->v_mount, FUSE_RELEASE, nodeid, td, - cred); - fri = fdip->indata; - fri->fh = fh_id; - fri->flags = OFLAGS(mode); - /* - * The node must be forgotten after the release. - * Release is sent in the background as usual (that's not - * necessary, but anyway...), so we do the forgetting - * by a dedicated callback handler. - * - * Current pid/cred is attached to the ticket as a parameter - * as the FORGET must be sent with current pid/cred but - * it will be sent from another context. - */ - fiov_adjust(&fdip->tick->tk_aw_handler_parm, - sizeof(*pidcred)); - pidcred = fdip->tick->tk_aw_handler_parm.base; - pidcred->pid = td->td_proc->p_pid; - memcpy(&pidcred->cred, cred, sizeof(*cred)); - fuse_insert_callback(fdip->tick, fuse_internal_forget_callback); - fuse_insert_message(fdip->tick); - } - - return (err); - } - - fdip->answ = gone_good_old ? NULL : feo + 1; - - return (0); - -undo: - free(fvdat, M_FUSEVN); - vp->v_data = NULL; - return (err); -} -#endif - -int -fuse_get_filehandle(struct vnode *vp, struct thread *td, struct ucred *cred, - int mode, struct fuse_filehandle **fufhp, - struct get_filehandle_param *gefhp) -{ - struct fuse_vnode_data *fvdat = VTOFUD(vp); - struct fuse_dispatcher fdi; - struct fuse_open_in *foi; - struct fuse_open_out *foo; - int err = 0; - struct fuse_filehandle *fufh = NULL; - enum fuse_opcode op; - int gone_create = 0; - - RECTIFY_TDCR(td, cred); - - /* - * "create" messaging is almost transparent for get_filehandle. There are - * some gotos and status variables though. - * And it's totally transparent for fuse_open. - * (By transparent I mean that they don't see the special "germic" state of - * the vnode... if the vnode is a germ, it will be tried to be initialized - * via a dedicated method, but from that on we go on as usual.) - */ -#if FUSE_HAS_CREATE - if (vp->v_op == &fuse_germ_vnops) { - KASSERT(gefhp, ("create_filehandle called without get_filehandle_param")); - gone_create = 1; - if (gefhp) - gefhp->do_gc = 0; - op = FUSE_OPEN; - fdi.answ = NULL; - if ((err = create_filehandle(vp, td, cred, mode, &fdi))) - goto out; - else if (fdi.answ) - goto setup_filehandle; - } -#endif - - if (gefhp && gefhp->opcode) - op = gefhp->opcode; - else - op = FUSE_OPEN; - - if (op == FUSE_OPENDIR) - mode = FREAD; - else - mode &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - - if (! (gefhp && gefhp->do_new)) { - struct standard_metrics_param stmp; - stmp.mode = mode; - stmp.op = op; - - ASSERT_VOP_LOCKED__FH(vp); - err = iterate_filehandles(vp, td, cred, fuse_standard_metrics, - &stmp); - - if (err) { - if (err == -1) { - DEBUG2G("suitable fh of vnode #%llu found\n", - VTOILLU(vp)); - fufh = stmp.fufh; - err = 0; - } - goto out; - } - } - - DEBUG2G("we need to fetch a new filehandle for vnode #%llu\n", VTOILLU(vp)); - - fdisp_init(&fdi, sizeof(*foi)); - fdisp_make_vp(&fdi, op, vp, td, cred); - - foi = fdi.indata; - foi->flags = OFLAGS(mode); - - if ((err = fdisp_wait_answ(&fdi))) - goto out; - -#if FUSE_HAS_CREATE -setup_filehandle: -#endif - foo = fdi.answ; - - fufh = malloc(sizeof(*fufh), M_FUSEFH, M_WAITOK | M_ZERO); - - /* - * We need to reference the vnode from fuse private file data - * as files' f_vnode field might point to another vnode (eg., - * if we are accessed through a nullfs overlay). - */ - fufh->fh_vp = vp; - fufh->fh_id = foo->fh; - fufh->flags = foo->open_flags; - - fuse_ticket_drop(fdi.tick); - - fufh->mode = mode; - fufh->cred = crhold(cred); - fufh->pid = td->td_proc->p_pid; - fufh->useco = 1; - fufh->op = op; - - ASSERT_VOP_ELOCKED__FH(vp); - LIST_INSERT_HEAD(&fvdat->fh_head, fufh, fh_link); - if (gefhp && gefhp->do_gc) { - /* - * The neat idea is that a cache cleanup is the best time for - * a gc -- gc'ing unbound filehandles at inactive/reclaim time - * is not enough, they can just accumulate while something - * happens with the file, given the cache is flushed frequently - * (otherwise there is no reason for the system to spawn them, - * as the data can be read from core). - * So then, let's just tie their gc to cache flush... - * Luckily, this won't break the POSIX semantics that an - * unlinked file is get kept until there is reference to it, - * because that's done via the lookup/forget mechanism, and not - * via filehandles. - */ - /* - * Now we use unbound filehandles pretty rarely (as read/write - * of regular files doesn't rely on them anymore), only during - * exec and reading directories. It's pretty much unlikely that - * one can be reused in any way, so we drop them - * unconditionally. - */ - struct fuse_release_param frp; - - DEBUG2G("gc'ing...\n"); - frp.fg = 0; - frp.flush = 0; - iterate_filehandles(vp, td, cred, release_filehandle, &frp); - } - fvdat->fh_counter++; - -#if _DEBUG2G - if (gefhp && gefhp->do_gc) { - DEBUG2G("after gc...\n"); - vn_printf(vp, " "); - } -#endif - -out: - if (gone_create && ! err) - fufh->flags |= FOPEN_KEEP_CACHE; - - *fufhp = fufh; - - return (err); -} - -static void -fuse_send_release(struct fuse_filehandle *fufh, struct thread *td, - struct ucred *cred, int flags, struct fuse_release_param *frp) -{ - struct vnode *vp = fufh->fh_vp; - struct fuse_dispatcher fdi; - struct fuse_release_in *fri; - int err = 0; - - KASSERT(! fufh->fp && fufh->useco == 0, ("active-looking fuse filehandle was attempted to release")); - - VTOFUD(vp)->fh_counter--; - DEBUG2G("filehandle of vnode #%llu being released, fh counter now is %d\n", - VTOILLU(vp), VTOFUD(vp)->fh_counter); - - if (vp->v_type == VBAD) - goto out; - - fdisp_init(&fdi, sizeof(*fri)); - fdisp_make_vp(&fdi, - fufh->op == FUSE_OPENDIR ? FUSE_RELEASEDIR : FUSE_RELEASE, - vp, td, cred); - fri = fdi.indata; - fri->fh = fufh->fh_id; - fri->flags = OFLAGS(flags); -#if FUSE_HAS_FLUSH_RELEASE - if (frp->flush) - fri->release_flags = FUSE_RELEASE_FLUSH; -#endif - - if (frp->fg) { - err = fdisp_wait_answ(&fdi); - if (err) - goto out; - else - fuse_ticket_drop(fdi.tick); - } else { - fuse_insert_callback(fdi.tick, NULL); - fuse_insert_message(fdi.tick); - } - -out: - crfree(fufh->cred); - free(fufh, M_FUSEFH); - if (err && frp->err == 0) - frp->err = err; -} - -static int -fuse_close_f(struct file *fp, struct thread *td) -{ - struct fuse_filehandle *fufh; - struct vnode *vp = NULL, *ovl_vp = fp->f_vnode; - struct fuse_release_param frp; - - if (! _file_is_fat(fp)) - panic("non-fat file passed to close routine"); - - vn_lock(ovl_vp, LK_EXCLUSIVE | LK_RETRY); - - if (_file_is_bad(fp)) { - DEBUG2G("fp %p, (overlay) vnode %p: went bad, giving up\n", - fp, ovl_vp); - goto out; - } - fufh = FTOFH(fp); - vp = fufh->fh_vp; - KASSERT(fufh->fp == fp, ("file's filehandle is stolen")); - DEBUG2G("vnode #%llu, fufh owner %p, useco %d\n", - VTOILLU(vp), fp, fufh->useco); - - fufh->useco--; - ASSERT_VOP_ELOCKED__FH(vp); - fufh->fp = NULL; - if (fufh->useco == 0) - LIST_REMOVE(fufh, fh_link); - fp->f_data = NULL; - - if (fufh->useco == 0) { - frp.err = 0; -#if FUSE_HAS_FLUSH_RELEASE - frp.fg = 1; - frp.flush = 1; -#else - frp.fg = 0; - frp.flush = 0; -#endif - fuse_send_release(fufh, td, NULL, fp->f_flag & ~O_EXCL, &frp); - } - -out: - if (fp->f_flag & FWRITE && vp) - vp->v_writecount--; - vput(ovl_vp); - return (frp.err); -} - -static int -fuse_fsync_filehandle(struct fuse_filehandle *fufh, struct thread *td, - struct ucred *cred, void *param) -{ - struct fuse_fsync_in *ffsi; - struct fuse_dispatcher *fdip = param; - - fdip->iosize = sizeof(*ffsi); - fdip->tick = NULL; - fdisp_make_vp(fdip, - (fufh->op == FUSE_OPENDIR) ? FUSE_FSYNCDIR : FUSE_FSYNC, - fufh->fh_vp, td, cred); - - ffsi = fdip->indata; - ffsi->fh = fufh->fh_id; - /* - * this sets that we wanna sync file data, - * not just metadata; a 0 value would have no - * counterpart in BSD semantics - */ - ffsi->fsync_flags = 1; - - fuse_insert_callback(fdip->tick, fuse_internal_fsync_callback); - fuse_insert_message(fdip->tick); - - return (0); -}