aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/tmpfs/tmpfs_vnops.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2017-01-19 19:15:21 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2017-01-19 19:15:21 +0000
commit64c250439fc403c7f0073a0bfbdcabedc7e11f99 (patch)
tree1b9ab5ff992809c2a471de4036a265f658609a47 /sys/fs/tmpfs/tmpfs_vnops.c
parent295df609dfd32cfbeda6ee13db7ae1a355fb6871 (diff)
downloadsrc-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.c9
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] == '.') {