diff --git a/sys/vfs/dirfs/dirfs_subr.c b/sys/vfs/dirfs/dirfs_subr.c index 0fda4856..4f85fea5 100644 --- a/sys/vfs/dirfs/dirfs_subr.c +++ b/sys/vfs/dirfs/dirfs_subr.c @@ -463,6 +463,14 @@ dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur, if (cur == NULL) return NULL; + /* + * Serialize the fd walk + node ref against + * dirfs_node_setpassive()'s check-then-close of dn_fd. The token + * is released by dirfs_dropfd() once the caller is done using the + * descriptor. + */ + lwkt_gettoken(&dmp->dm_token); + buf = kmalloc(MAXPATHLEN + 1, M_DIRFS_MISC, M_WAITOK | M_ZERO); count = 0; @@ -489,6 +497,7 @@ dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur, } else { dbg(9, "failed too long\n"); kfree(buf, M_DIRFS_MISC); + lwkt_reltoken(&dmp->dm_token); *pathfreep = NULL; *pathto = NULL; dnp1 = NULL; @@ -501,8 +510,11 @@ dirfs_dropfd(dirfs_mount_t dmp, dirfs_node_t dnp1, char *pathfree) { if (pathfree) kfree(pathfree, M_DIRFS_MISC); - if (dnp1) + if (dnp1) { dirfs_node_drop(dmp, dnp1); + /* pairs with lwkt_gettoken() in dirfs_findfd() */ + lwkt_reltoken(&dmp->dm_token); + } } int @@ -844,7 +856,13 @@ dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state) * * The descriptor for the root node is NEVER closed by * this function. + * + * The token pairs with the one held across + * dirfs_findfd()..dirfs_dropfd() so an in-flight consumer + * can never lose its dn_fd (or have the fd number recycled + * underneath it) while it is being used. */ + lwkt_gettoken(&dmp->dm_token); vp = dnp->dn_vnode; if (dirfs_node_refcnt(dnp) == 2 && vp && dnp->dn_fd != DIRFS_NOFD && @@ -864,6 +882,7 @@ dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state) dnp->dn_fd = DIRFS_NOFD; } } + lwkt_reltoken(&dmp->dm_token); dirfs_node_drop(dmp, dnp); } }