diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2017-01-19 19:15:21 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2017-01-19 19:15:21 +0000 |
commit | 64c250439fc403c7f0073a0bfbdcabedc7e11f99 (patch) | |
tree | 1b9ab5ff992809c2a471de4036a265f658609a47 /sys/fs/tmpfs/tmpfs_vnops.c | |
parent | 295df609dfd32cfbeda6ee13db7ae1a355fb6871 (diff) | |
download | src-64c250439fc403c7f0073a0bfbdcabedc7e11f99.tar.gz src-64c250439fc403c7f0073a0bfbdcabedc7e11f99.zip |
Refcount tmpfs nodes and mount structures.
On dotdot lookup and fhtovp operations, it is possible for the file
represented by tmpfs node to be removed after the thread calculated
the pointer. In this case, tmpfs_alloc_vp() accesses freed memory.
Introduce the reference count on the nodes. The allnodes list from
tmpfs mount owns 1 reference, and threads performing unlocked
operations on the node, add one transient reference. Similarly, since
struct tmpfs_mount maintains the list where nodes are enlisted,
refcount it by one reference from struct mount and one reference from
each node on the list. Both nodes and tmpfs_mounts are removed when
refcount goes to zero.
Note that this means that nodes and tmpfs_mounts might survive some
time after the node is deleted or tmpfs_unmount() finished. The
tmpfs_alloc_vp() in these cases returns error either due to node
removal (tn_nlinks == 0) or because of insmntque1(9) error.
Tested by: pho (as part of larger patch)
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Notes
Notes:
svn path=/head/; revision=312428
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_vnops.c')
-rw-r--r-- | sys/fs/tmpfs/tmpfs_vnops.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 1b498de4539a..becc72b1f0fa 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -82,7 +82,8 @@ tmpfs_lookup(struct vop_cachedlookup_args *v) struct vnode **vpp = v->a_vpp; struct componentname *cnp = v->a_cnp; struct tmpfs_dirent *de; - struct tmpfs_node *dnode; + struct tmpfs_node *dnode, *pnode; + struct tmpfs_mount *tm; int error; dnode = VP_TO_TMPFS_DIR(dvp); @@ -104,8 +105,12 @@ tmpfs_lookup(struct vop_cachedlookup_args *v) goto out; } if (cnp->cn_flags & ISDOTDOT) { + tm = VFS_TO_TMPFS(dvp->v_mount); + pnode = dnode->tn_dir.tn_parent; + tmpfs_ref_node(pnode); error = vn_vget_ino_gen(dvp, tmpfs_vn_get_ino_alloc, - dnode->tn_dir.tn_parent, cnp->cn_lkflags, vpp); + pnode, cnp->cn_lkflags, vpp); + tmpfs_free_node(tm, pnode); if (error != 0) goto out; } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { |