summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorJean-Pierre André <jpandre@users.sourceforge.net>2012-08-22 10:00:21 +0200
committerJean-Pierre André <jpandre@users.sourceforge.net>2012-08-22 10:00:21 +0200
commit50ef4d88a5478f208af3fee991bb94e5ddbd9a83 (patch)
tree3d889efd49134e0d4e343d27773450da5ae872f8 /kernel
parentcc7bc99d0c3a383ac94f705b09e3280725a7b906 (diff)
downloadillumos-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.h1
-rw-r--r--kernel/fuse_vfsops.c1
-rw-r--r--kernel/fuse_vnops.c53
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.
*