* Clear out a doomed vnode (if any) and replace it with a new one as long * as the fs is not being unmounted. Return the root vnode to the caller. */
| 6436 | * as the fs is not being unmounted. Return the root vnode to the caller. |
| 6437 | */ |
| 6438 | static int __noinline |
| 6439 | vfs_cache_root_fallback(struct mount *mp, int flags, struct vnode **vpp) |
| 6440 | { |
| 6441 | struct vnode *vp; |
| 6442 | int error; |
| 6443 | |
| 6444 | restart: |
| 6445 | if (mp->mnt_rootvnode != NULL) { |
| 6446 | MNT_ILOCK(mp); |
| 6447 | vp = mp->mnt_rootvnode; |
| 6448 | if (vp != NULL) { |
| 6449 | if (!VN_IS_DOOMED(vp)) { |
| 6450 | vrefact(vp); |
| 6451 | MNT_IUNLOCK(mp); |
| 6452 | error = vn_lock(vp, flags); |
| 6453 | if (error == 0) { |
| 6454 | *vpp = vp; |
| 6455 | return (0); |
| 6456 | } |
| 6457 | vrele(vp); |
| 6458 | goto restart; |
| 6459 | } |
| 6460 | /* |
| 6461 | * Clear the old one. |
| 6462 | */ |
| 6463 | mp->mnt_rootvnode = NULL; |
| 6464 | } |
| 6465 | MNT_IUNLOCK(mp); |
| 6466 | if (vp != NULL) { |
| 6467 | vfs_op_barrier_wait(mp); |
| 6468 | vrele(vp); |
| 6469 | } |
| 6470 | } |
| 6471 | error = VFS_CACHEDROOT(mp, flags, vpp); |
| 6472 | if (error != 0) |
| 6473 | return (error); |
| 6474 | if (mp->mnt_vfs_ops == 0) { |
| 6475 | MNT_ILOCK(mp); |
| 6476 | if (mp->mnt_vfs_ops != 0) { |
| 6477 | MNT_IUNLOCK(mp); |
| 6478 | return (0); |
| 6479 | } |
| 6480 | if (mp->mnt_rootvnode == NULL) { |
| 6481 | vrefact(*vpp); |
| 6482 | mp->mnt_rootvnode = *vpp; |
| 6483 | } else { |
| 6484 | if (mp->mnt_rootvnode != *vpp) { |
| 6485 | if (!VN_IS_DOOMED(mp->mnt_rootvnode)) { |
| 6486 | panic("%s: mismatch between vnode returned " |
| 6487 | " by VFS_CACHEDROOT and the one cached " |
| 6488 | " (%p != %p)", |
| 6489 | __func__, *vpp, mp->mnt_rootvnode); |
| 6490 | } |
| 6491 | } |
| 6492 | } |
| 6493 | MNT_IUNLOCK(mp); |
| 6494 | } |
| 6495 | return (0); |
no test coverage detected