diff options
author | das <das@FreeBSD.org> | 2003-06-13 08:59:37 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2003-06-13 08:59:37 +0000 |
commit | 7b9c7016940003859fcca549bd5468de9a774ac8 (patch) | |
tree | 42da53bdeef0e9c8ba2b1203a0e04b69bbd38270 /sys/fs | |
parent | 6e6f4e827010564489106d68fd31745b8712f0d0 (diff) | |
download | FreeBSD-src-7b9c7016940003859fcca549bd5468de9a774ac8.zip FreeBSD-src-7b9c7016940003859fcca549bd5468de9a774ac8.tar.gz |
Plug a serious memory leak. The -STABLE equivalent of this patch has
been tested extensively, but -CURRENT testing has been hampered by a
number of panics that also occur without the patch. Since the
destabilizing changes between 4.X and 5.X are external to unionfs,
I believe this patch applies equally well to both.
Thanks to scrappy for assistance testing these and other changes.
MFC after: 4 days
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/unionfs/union_subr.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index 643e150..0777268 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -1246,12 +1246,14 @@ union_dircache(vp, td) int cnt; struct vnode *nvp; struct vnode **vpp; - struct vnode **dircache; + struct vnode **dircache, **newdircache; struct union_node *un; int error; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - dircache = VTOUNION(vp)->un_dircache; + un = VTOUNION(vp); + dircache = un->un_dircache; + newdircache = NULL; nvp = NULLVP; @@ -1259,8 +1261,8 @@ union_dircache(vp, td) cnt = 0; union_dircache_r(vp, 0, &cnt); cnt++; - dircache = malloc(cnt * sizeof(struct vnode *), - M_TEMP, M_WAITOK); + newdircache = dircache = malloc(cnt * sizeof(struct vnode *), + M_TEMP, M_WAITOK); vpp = dircache; union_dircache_r(vp, &vpp, &cnt); *vpp = NULLVP; @@ -1268,7 +1270,7 @@ union_dircache(vp, td) } else { vpp = dircache; do { - if (*vpp++ == VTOUNION(vp)->un_uppervp) + if (*vpp++ == un->un_uppervp) break; } while (*vpp != NULLVP); } @@ -1284,11 +1286,21 @@ union_dircache(vp, td) if (error) goto out; - VTOUNION(vp)->un_dircache = 0; - un = VTOUNION(nvp); - un->un_dircache = dircache; + un->un_dircache = NULL; + VTOUNION(nvp)->un_dircache = dircache; + newdircache = NULL; out: + /* + * If we allocated a new dircache and couldn't attach + * it to a new vp, free the resources we allocated. + */ + if (newdircache) { + for (vpp = newdircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(newdircache, M_TEMP); + } + VOP_UNLOCK(vp, 0, td); return (nvp); } |