summaryrefslogtreecommitdiffstats
path: root/sys/fs/tmpfs/tmpfs_subr.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-08-05 18:53:59 +0000
committerkib <kib@FreeBSD.org>2013-08-05 18:53:59 +0000
commitb8fe5eca7f69369d0faabdfa7ab217dab06183d5 (patch)
tree52e9296eaae28bf8ae2fb9cf87ba3ece87fd7e33 /sys/fs/tmpfs/tmpfs_subr.c
parentfcc01a7fa0405e9a2a84a9c83efd8184ec7ea386 (diff)
downloadFreeBSD-src-b8fe5eca7f69369d0faabdfa7ab217dab06183d5.zip
FreeBSD-src-b8fe5eca7f69369d0faabdfa7ab217dab06183d5.tar.gz
The tmpfs_alloc_vp() is used to instantiate vnode for the tmpfs node,
in particular, from the tmpfs_lookup VOP method. If LK_NOWAIT is not specified in the lkflags, the lookup is supposed to return an alive vnode whenever the underlying node is valid. Currently, the tmpfs_alloc_vp() returns ENOENT if the vnode attached to node exists and is being reclaimed. This causes spurious ENOENT errors from lookup on tmpfs and corresponding random 'No such file' failures from syscalls working with tmpfs files. Fix this by waiting for the doomed vnode to be detached from the tmpfs node if sleepable allocation is requested. Note that filesystems which use vfs_hash.c, correctly handle the case due to vfs_hash_get() looping when vget() returns ENOENT for sleepable requests. Reported and tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_subr.c')
-rw-r--r--sys/fs/tmpfs/tmpfs_subr.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
index ed6bff0..4e94476 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -479,11 +479,32 @@ tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
error = 0;
loop:
TMPFS_NODE_LOCK(node);
+loop1:
if ((vp = node->tn_vnode) != NULL) {
MPASS((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0);
VI_LOCK(vp);
+ if ((node->tn_type == VDIR && node->tn_dir.tn_parent == NULL) ||
+ ((vp->v_iflag & VI_DOOMED) != 0 &&
+ (lkflag & LK_NOWAIT) != 0)) {
+ VI_UNLOCK(vp);
+ TMPFS_NODE_UNLOCK(node);
+ error = ENOENT;
+ vp = NULL;
+ goto out;
+ }
+ if ((vp->v_iflag & VI_DOOMED) != 0) {
+ VI_UNLOCK(vp);
+ node->tn_vpstate |= TMPFS_VNODE_WRECLAIM;
+ while ((node->tn_vpstate & TMPFS_VNODE_WRECLAIM) != 0) {
+ msleep(&node->tn_vnode, TMPFS_NODE_MTX(node),
+ 0, "tmpfsE", 0);
+ }
+ goto loop1;
+ }
TMPFS_NODE_UNLOCK(node);
error = vget(vp, lkflag | LK_INTERLOCK, curthread);
+ if (error == ENOENT)
+ goto loop;
if (error != 0) {
vp = NULL;
goto out;
@@ -620,6 +641,9 @@ tmpfs_free_vp(struct vnode *vp)
mtx_assert(TMPFS_NODE_MTX(node), MA_OWNED);
node->tn_vnode = NULL;
+ if ((node->tn_vpstate & TMPFS_VNODE_WRECLAIM) != 0)
+ wakeup(&node->tn_vnode);
+ node->tn_vpstate &= ~TMPFS_VNODE_WRECLAIM;
vp->v_data = NULL;
}
OpenPOWER on IntegriCloud