+
+ /*
+ * We need our own usecount on the root vnode and the starting dir across
+ * the lookup. There's two things that be done here. We can hold the locks
+ * (which protect the existing usecounts on the directories) across the
+ * lookup or take our own usecount. Holding the locks across the lookup can
+ * cause deadlock issues if we re-enter namei on the same thread so the
+ * correct thing to do is to acquire our own usecount.
+ *
+ * Ideally, the usecount should be obtained by vnode_get->vnode_ref->vnode_put.
+ * However when this vnode is the rootvnode, that sequence will produce a
+ * lot of vnode mutex locks and unlocks on a single vnode (the rootvnode)
+ * and will be highly contended and degrade performance. Since we have
+ * an existing usecount protected by the locks we hold, we'll just use
+ * an atomic op to increment the usecount on a vnode which already has one
+ * and can't be released becasue we have the locks which protect against that
+ * happening.
+ */
+ rootdir_with_usecount = ndp->ni_rootdir;
+ old_count = os_atomic_inc_orig(&rootdir_with_usecount->v_usecount, relaxed);
+ if (old_count < 1) {
+ panic("(1) invalid pre-increment usecount (%d) for rootdir vnode %p",
+ old_count, rootdir_with_usecount);
+ } else if (old_count == INT32_MAX) {
+ panic("(1) usecount overflow for vnode %p", rootdir_with_usecount);
+ }
+
+ if ((dp != rootdir_with_usecount) && (dp != usedvp_dp)) {
+ old_count = os_atomic_inc_orig(&dp->v_usecount, relaxed);
+ if (old_count < 1) {
+ panic("(2) invalid pre-increment usecount (%d) for vnode %p", old_count, dp);
+ } else if (old_count == INT32_MAX) {
+ panic("(2) usecount overflow for vnode %p", dp);
+ }
+ startdir_with_usecount = dp;
+ }
+
+ /* Now that we have our usecount, release the locks */
+ lck_rw_unlock_shared(&rootvnode_rw_lock);
+ proc_dirs_unlock_shared(p);
+