Date: Sat, 9 Jul 2011 09:02:46 GMT From: Ilya Putsikau <ilya@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 195926 for review Message-ID: <201107090902.p6992kqQ044935@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@195926?ac=10 Change 195926 by ilya@ilya_triton2011 on 2011/07/09 09:02:07 Truncate vnode buffers in fuse_vnode_setsize Set new size before extending file Flush vnode buffers before close Affected files ... .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_io.c#17 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_io.h#10 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_node.c#16 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_node.h#16 edit .. //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#38 edit Differences ... ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_io.c#17 (text+ko) ==== @@ -298,7 +298,7 @@ uio->uio_resid += diff; uio->uio_offset -= diff; if (uio->uio_offset > fvdat->filesize) - fuse_vnode_setsize(vp, uio->uio_offset); + fuse_vnode_setsize(vp, cred, uio->uio_offset); } fuse_ticket_drop(fdi.tick); @@ -363,7 +363,7 @@ if (bp != NULL) { long save; - fuse_vnode_setsize(vp, uio->uio_offset + n); + fuse_vnode_extend(vp, cred, uio->uio_offset + n); save = bp->b_flags & B_CACHE; bcount += n; @@ -385,7 +385,7 @@ DEBUG("getting block from OS, bcount %d\n", bcount); bp = getblk(vp, lbn, bcount, PCATCH, 0, 0); if (uio->uio_offset + n > fvdat->filesize) { - fuse_vnode_setsize(vp, uio->uio_offset + n); + fuse_vnode_extend(vp, cred, uio->uio_offset + n); } } @@ -649,3 +649,63 @@ bufdone(bp); return (error); } + +/* + * Flush and invalidate all dirty buffers. If another process is already + * doing the flush, just wait for completion. + */ +int +fuse_io_invalbuf(struct vnode *vp, struct thread *td) +{ + struct fuse_vnode_data *fvdat = VTOFUD(vp); + int error = 0; + + if (vp->v_iflag & VI_DOOMED) + return 0; + + ASSERT_VOP_ELOCKED(vp, "fuse_io_invalbuf"); + + while (fvdat->flag & FN_FLUSHINPROG) { + struct proc *p = td->td_proc; + if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) + return EIO; + fvdat->flag |= FN_FLUSHWANT; + tsleep(&fvdat->flag, PRIBIO + 2, "fusevinv", 2 * hz); + error = 0; + if (p != NULL) { + PROC_LOCK(p); + if (SIGNOTEMPTY(p->p_siglist) || + SIGNOTEMPTY(td->td_siglist)) + error = EINTR; + PROC_UNLOCK(p); + } + if (error == EINTR) + return EINTR; + } + fvdat->flag |= FN_FLUSHINPROG; + + if (vp->v_bufobj.bo_object != NULL) { + VM_OBJECT_LOCK(vp->v_bufobj.bo_object); + vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC); + VM_OBJECT_UNLOCK(vp->v_bufobj.bo_object); + } + + error = vinvalbuf(vp, V_SAVE, PCATCH, 0); + while (error) { + if (error == ERESTART || error == EINTR) { + fvdat->flag &= ~FN_FLUSHINPROG; + if (fvdat->flag & FN_FLUSHWANT) { + fvdat->flag &= ~FN_FLUSHWANT; + wakeup(&fvdat->flag); + } + return EINTR; + } + error = vinvalbuf(vp, V_SAVE, PCATCH, 0); + } + fvdat->flag &= ~FN_FLUSHINPROG; + if (fvdat->flag & FN_FLUSHWANT) { + fvdat->flag &= ~FN_FLUSHWANT; + wakeup(&fvdat->flag); + } + return (error); +} ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_io.h#10 (text+ko) ==== @@ -4,5 +4,6 @@ int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred); int fuse_io_strategy(struct vnode *vp, struct buf *bp); +int fuse_io_invalbuf(struct vnode *vp, struct thread *td); #endif /* _FUSE_IO_H_ */ ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_node.c#16 (text+ko) ==== @@ -228,6 +228,68 @@ return fuse_timespec_cmp(&uptsp, &fvdat->cached_attrs_valid, <=); } +int +fuse_vnode_extend(struct vnode *vp, struct ucred *cred, off_t newsize) +{ + struct thread *td = curthread; + struct fuse_filehandle *fufh = NULL; + struct fuse_dispatcher fdi; + struct fuse_setattr_in *fsai; + struct fuse_access_param facp; + int err = 0; + + DEBUG("inode=%jd oldsize=%jd newsize=%jd\n", + VTOI(vp), VTOFUD(vp)->filesize, newsize); + ASSERT_VOP_ELOCKED(vp, "fuse_io_extend"); + MPASS(newsize > VTOFUD(vp)->filesize); + + if (fuse_isdeadfs(vp)) { + return EBADF; + } + + if (vnode_vtype(vp) == VDIR) { + return EISDIR; + } + + if (vfs_isrdonly(vnode_mount(vp))) { + return EROFS; + } + + if (cred == NULL) { + cred = td->td_ucred; + } + + fdisp_init(&fdi, sizeof(*fsai)); + fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); + fsai = fdi.indata; + fsai->valid = 0; + + bzero(&facp, sizeof(facp)); + facp.xuid = cred->cr_uid; + facp.xgid = cred->cr_gid; + + // Truncate to a new value. + fsai->size = newsize; + fsai->valid |= FATTR_SIZE; + + fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh); + if (fufh) { + fsai->fh = fufh->fh_id; + fsai->valid |= FATTR_FH; + } + + err = fdisp_wait_answ(&fdi); + + fuse_ticket_drop(fdi.tick); + + fuse_invalidate_attr(vp); + if (!err) { + fuse_vnode_setsize(vp, cred, newsize); + } + + return err; +} + void fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred) { @@ -241,10 +303,22 @@ } void -fuse_vnode_setsize(struct vnode *vp, off_t newsize) +fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize) { struct fuse_vnode_data *fvdat = VTOFUD(vp); + off_t oldsize; + + DEBUG("inode=%jd oldsize=%jd newsize=%jd\n", + VTOI(vp), fvdat->filesize, newsize); + ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize"); + oldsize = fvdat->filesize; + fvdat->filesize = newsize; + + if (newsize < oldsize) { + vtruncbuf(vp, cred, curthread, newsize, fuse_iosize(vp)); + } + vnode_pager_setsize(vp, newsize); - fvdat->filesize = newsize; + fuse_invalidate_attr(vp); } ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_node.h#16 (text+ko) ==== @@ -13,6 +13,8 @@ #define FN_CREATING 0x00000002 #define FN_REVOKED 0x00000020 +#define FN_FLUSHINPROG 0x00000040 +#define FN_FLUSHWANT 0x00000080 struct fuse_vnode_data { /** self **/ @@ -103,8 +105,10 @@ int32_t fuse_open_flags, struct thread *td); +int fuse_vnode_extend(struct vnode *vp, struct ucred *cred, off_t newsize); + void fuse_vnode_refreshsize(struct vnode *vp, struct ucred *cred); -void fuse_vnode_setsize(struct vnode *vp, off_t newsize); +void fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize); #endif /* _FUSE_NODE_H_ */ ==== //depot/projects/soc2011/ilya_fuse/fuse_module/fuse_vnops.c#38 (text+ko) ==== @@ -522,7 +522,7 @@ off_t new_filesize = ((struct fuse_attr_out *)fdi.answ)->attr.size; if (fvdat->filesize != new_filesize) { - fuse_vnode_setsize(vp, new_filesize); + fuse_vnode_setsize(vp, cred, new_filesize); } } @@ -574,13 +574,17 @@ struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_filehandle *fufh = NULL; - int type; + int type, need_invalbuf = 1; DEBUG("inode=%jd\n", (uintmax_t)VTOI(vp)); for (type = 0; type < FUFH_MAXTYPE; type++) { fufh = &(fvdat->fufh[type]); if (FUFH_IS_VALID(fufh)) { + if (need_invalbuf) { + fuse_io_invalbuf(vp, td); + need_invalbuf = 0; + } fuse_filehandle_close(vp, type, td, NULL, FUSE_OP_BACKGROUNDED); } } @@ -1710,7 +1714,7 @@ fuse_ticket_drop(fdi.tick); if (!err && sizechanged) { fuse_invalidate_attr(vp); - fuse_vnode_setsize(vp, newsize); + fuse_vnode_setsize(vp, cred, newsize); } return err;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107090902.p6992kqQ044935>