| 1722 | } |
| 1723 | |
| 1724 | static int __noinline |
| 1725 | cache_lookup_dotdot(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, |
| 1726 | struct timespec *tsp, int *ticksp) |
| 1727 | { |
| 1728 | struct namecache_ts *ncp_ts; |
| 1729 | struct namecache *ncp; |
| 1730 | struct mtx *dvlp; |
| 1731 | enum vgetstate vs; |
| 1732 | int error, ltype; |
| 1733 | bool whiteout; |
| 1734 | |
| 1735 | MPASS((cnp->cn_flags & ISDOTDOT) != 0); |
| 1736 | |
| 1737 | if ((cnp->cn_flags & MAKEENTRY) == 0) { |
| 1738 | cache_remove_cnp(dvp, cnp); |
| 1739 | return (0); |
| 1740 | } |
| 1741 | |
| 1742 | counter_u64_add(dotdothits, 1); |
| 1743 | retry: |
| 1744 | dvlp = VP2VNODELOCK(dvp); |
| 1745 | mtx_lock(dvlp); |
| 1746 | ncp = dvp->v_cache_dd; |
| 1747 | if (ncp == NULL) { |
| 1748 | SDT_PROBE3(vfs, namecache, lookup, miss, dvp, "..", NULL); |
| 1749 | mtx_unlock(dvlp); |
| 1750 | return (0); |
| 1751 | } |
| 1752 | if ((ncp->nc_flag & NCF_ISDOTDOT) != 0) { |
| 1753 | if (ncp->nc_flag & NCF_NEGATIVE) |
| 1754 | *vpp = NULL; |
| 1755 | else |
| 1756 | *vpp = ncp->nc_vp; |
| 1757 | } else |
| 1758 | *vpp = ncp->nc_dvp; |
| 1759 | if (*vpp == NULL) |
| 1760 | goto negative_success; |
| 1761 | SDT_PROBE3(vfs, namecache, lookup, hit, dvp, "..", *vpp); |
| 1762 | cache_out_ts(ncp, tsp, ticksp); |
| 1763 | if ((ncp->nc_flag & (NCF_ISDOTDOT | NCF_DTS)) == |
| 1764 | NCF_DTS && tsp != NULL) { |
| 1765 | ncp_ts = __containerof(ncp, struct namecache_ts, nc_nc); |
| 1766 | *tsp = ncp_ts->nc_dotdottime; |
| 1767 | } |
| 1768 | |
| 1769 | MPASS(dvp != *vpp); |
| 1770 | ltype = VOP_ISLOCKED(dvp); |
| 1771 | VOP_UNLOCK(dvp); |
| 1772 | vs = vget_prep(*vpp); |
| 1773 | mtx_unlock(dvlp); |
| 1774 | error = vget_finish(*vpp, cnp->cn_lkflags, vs); |
| 1775 | vn_lock(dvp, ltype | LK_RETRY); |
| 1776 | if (VN_IS_DOOMED(dvp)) { |
| 1777 | if (error == 0) |
| 1778 | vput(*vpp); |
| 1779 | *vpp = NULL; |
| 1780 | return (ENOENT); |
| 1781 | } |
no test coverage detected