diff options
author | Jean-Pierre André <jpandre@users.sourceforge.net> | 2012-08-22 10:00:21 +0200 |
---|---|---|
committer | Jean-Pierre André <jpandre@users.sourceforge.net> | 2012-08-22 10:00:21 +0200 |
commit | 50ef4d88a5478f208af3fee991bb94e5ddbd9a83 (patch) | |
tree | 3d889efd49134e0d4e343d27773450da5ae872f8 /kernel | |
parent | cc7bc99d0c3a383ac94f705b09e3280725a7b906 (diff) | |
download | illumos-fusefs-50ef4d88a5478f208af3fee991bb94e5ddbd9a83.tar.gz |
Freed the file system data when unmounting (and avoid big memory leak)
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fuse_queue.h | 1 | ||||
-rw-r--r-- | kernel/fuse_vfsops.c | 1 | ||||
-rw-r--r-- | kernel/fuse_vnops.c | 53 |
3 files changed, 54 insertions, 1 deletions
diff --git a/kernel/fuse_queue.h b/kernel/fuse_queue.h index 251dbb0..82e107f 100644 --- a/kernel/fuse_queue.h +++ b/kernel/fuse_queue.h @@ -133,6 +133,7 @@ fuse_avl_cache_node_t *fuse_avl_cache_node_create(vnode_t *np, uint64_t inode, uint64_t par_nodeid, unsigned short namelen, char *name); fuse_msg_node_t *fuse_setup_message(size_t argsize, enum fuse_opcode op, uint64_t nodeid, cred_t *credp, uint64_t unique); +void fuse_destroy_cache(fuse_session_t *sep); #ifdef __cplusplus } diff --git a/kernel/fuse_vfsops.c b/kernel/fuse_vfsops.c index 9539274..c32542b 100644 --- a/kernel/fuse_vfsops.c +++ b/kernel/fuse_vfsops.c @@ -436,6 +436,7 @@ fuse_unmount(struct vfs *vfsp, int flag, struct cred *crp) fsep = fuse_minor_get_session(getminor(vfsp->vfs_dev)); if (fsep != NULL) { + fuse_destroy_cache(fsep); /* Mark the filesystem as unmounted */ fsep->mounted = 0; diff --git a/kernel/fuse_vnops.c b/kernel/fuse_vnops.c index 83dad20..682d073 100644 --- a/kernel/fuse_vnops.c +++ b/kernel/fuse_vnops.c @@ -115,7 +115,9 @@ static int fuse_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw, struct cred *credp, caller_context_t *ct); static int fuse_putpage(struct vnode *vp, offset_t off, size_t len, int flags, - struct cred *credp, caller_context_t *ct); + struct cred *credp, caller_context_t *ct); +static int fuse_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, + size_t *lenp, int flags, cred_t *credp); static int fuse_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *); static int fuse_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t, @@ -2976,6 +2978,55 @@ fuse_vnode_free(struct vnode *vp, fuse_session_t *sep) vn_free(vp); } + +/* + * Destroy all cached data when unmounting + */ + +void fuse_destroy_cache(fuse_session_t *sep) +{ + fuse_avl_cache_node_t *item; + int failed; + + item = (fuse_avl_cache_node_t*)avl_first(&(sep->avl_cache)); + failed = 0; + if (item) + do { + struct vnode *vp = item->facn_vnode_p; + struct fuse_fh_param fh_param; + + if (vp && VTOFD(vp)) { + /* + * Invalidate pages associated to vnode : + * http://wesunsolve.net/bugid/id/6732672 + * http://wesunsolve.net/bugid/id/6730916 + */ + if (vn_has_cached_data(vp)) { + /* + * This calls VOP_DISPOSE() for each page + * with flag == 0x10000 and dn == 0 + */ + pvn_vplist_dirty(vp, 0, fuse_putapage, + B_INVAL, sep->usercred); + } + /* Release any file handles */ + fh_param.vp = vp; + fh_param.flag = FUSE_FORCE_FH_RELEASE; + iterate_filehandle(vp, fuse_release_fh, + &fh_param, NULL); + /* Finally remove from our cache */ + fuse_vnode_cache_remove(vp, sep); + fuse_free_vdata(vp); + vp->v_data = NULL; + if (!vn_has_cached_data(vp)) + vn_free(vp); + item = (fuse_avl_cache_node_t*) + avl_first(&(sep->avl_cache)); + } else + failed = 1; + } while (!failed && item); +} + /* * Insert the indicated symbolic reference entry into the directory. * |