/* * union_inactive: * * Called with the vnode locked. We are expected to unlock the vnode. * * union_inactive(struct vnode *a_vp, struct thread *a_td) */ static int union_inactive(struct vop_inactive_args *ap) { struct vnode *vp = ap->a_vp; /*struct thread *td = ap->a_td;*/ struct union_node *un = VTOUNION(vp); struct vnode **vpp; /* * Do nothing (and _don't_ bypass). * Wait to vrele lowervp until reclaim, * so that until then our union_node is in the * cache and reusable. * * NEEDSWORK: Someday, consider inactive'ing * the lowervp and then trying to reactivate it * with capabilities (v_id) * like they do in the name lookup cache code. * That's too much work for now. */ if (un->un_dircache != 0) { for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) vrele(*vpp); kfree (un->un_dircache, M_TEMP); un->un_dircache = 0; } #if 0 if ((un->un_flags & UN_ULOCK) && un->un_uppervp) { un->un_flags &= ~UN_ULOCK; vn_unlock(un->un_uppervp); } #endif if ((un->un_flags & UN_CACHED) == 0) vgone_vxlocked(vp); return (0); }
/* * The syncer vnode is no longer referenced. * * sync_inactive { struct vnode *a_vp, struct proc *a_p } */ static int sync_inactive(struct vop_inactive_args *ap) { vgone_vxlocked(ap->a_vp); return (0); }
/* * nwfs_file rename call * * nwfs_rename(struct vnode *a_fdvp, struct vnode *a_fvp, * struct componentname *a_fcnp, struct vnode *a_tdvp, * struct vnode *a_tvp, struct componentname *a_tcnp) */ static int nwfs_rename(struct vop_old_rename_args *ap) { struct vnode *fvp = ap->a_fvp; struct vnode *tvp = ap->a_tvp; struct vnode *fdvp = ap->a_fdvp; struct vnode *tdvp = ap->a_tdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; struct nwmount *nmp=VTONWFS(fvp); u_int16_t oldtype = 6; int error=0; /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; goto out; } if (tvp && VREFCNT(tvp) > 1) { error = EBUSY; goto out; } if (tvp && tvp != fvp) { error = ncp_DeleteNSEntry(nmp, VTONW(tdvp)->n_fid.f_id, tcnp->cn_namelen, tcnp->cn_nameptr, tcnp->cn_td, tcnp->cn_cred); if (error == 0x899c) error = EACCES; if (error) goto out; } if (fvp->v_type == VDIR) { oldtype |= NW_TYPE_SUBDIR; } else if (fvp->v_type == VREG) { oldtype |= NW_TYPE_FILE; } else return EINVAL; error = ncp_nsrename(NWFSTOCONN(nmp), nmp->n_volume, nmp->name_space, oldtype, &nmp->m.nls, VTONW(fdvp)->n_fid.f_id, fcnp->cn_nameptr, fcnp->cn_namelen, VTONW(tdvp)->n_fid.f_id, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_td,tcnp->cn_cred); if (error == 0x8992) error = EEXIST; out: if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); vrele(fdvp); vrele(fvp); nwfs_attr_cacheremove(fdvp); nwfs_attr_cacheremove(tdvp); /* * Need to get rid of old vnodes, because netware will change * file id on rename */ vgone_vxlocked(fvp); if (tvp) vgone_vxlocked(tvp); /* * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. */ if (error == ENOENT) error = 0; return (error); }
/* * Try to reuse a vnode from the free list. This function is somewhat * advisory in that NULL can be returned as a normal case, even if free * vnodes are present. * * The scan is limited because it can result in excessive CPU use during * periods of extreme vnode use. * * NOTE: The returned vnode is not completely initialized. */ static struct vnode * cleanfreevnode(int maxcount) { struct vnode *vp; int count; int trigger = (long)vmstats.v_page_count / (activevnodes * 2 + 1); /* * Try to deactivate some vnodes cached on the active list. */ if (countcachedvnodes(0) < inactivevnodes) goto skip; for (count = 0; count < maxcount * 2; count++) { spin_lock(&vfs_spin); vp = TAILQ_NEXT(&vnode_active_rover, v_list); TAILQ_REMOVE(&vnode_active_list, &vnode_active_rover, v_list); if (vp == NULL) { TAILQ_INSERT_HEAD(&vnode_active_list, &vnode_active_rover, v_list); } else { TAILQ_INSERT_AFTER(&vnode_active_list, vp, &vnode_active_rover, v_list); } if (vp == NULL) { spin_unlock(&vfs_spin); continue; } if ((vp->v_refcnt & VREF_MASK) != 0) { spin_unlock(&vfs_spin); vp->v_act += VACT_INC; if (vp->v_act > VACT_MAX) /* SMP race ok */ vp->v_act = VACT_MAX; continue; } /* * decrement by less if the vnode's object has a lot of * VM pages. XXX possible SMP races. */ if (vp->v_act > 0) { vm_object_t obj; if ((obj = vp->v_object) != NULL && obj->resident_page_count >= trigger) { vp->v_act -= 1; } else { vp->v_act -= VACT_INC; } if (vp->v_act < 0) vp->v_act = 0; spin_unlock(&vfs_spin); continue; } /* * Try to deactivate the vnode. */ if ((atomic_fetchadd_int(&vp->v_refcnt, 1) & VREF_MASK) == 0) atomic_add_int(&mycpu->gd_cachedvnodes, -1); atomic_set_int(&vp->v_refcnt, VREF_FINALIZE); spin_unlock(&vfs_spin); vrele(vp); } skip: /* * Loop trying to lock the first vnode on the free list. * Cycle if we can't. */ for (count = 0; count < maxcount; count++) { spin_lock(&vfs_spin); vp = TAILQ_FIRST(&vnode_inactive_list); if (vp == NULL) { spin_unlock(&vfs_spin); break; } /* * non-blocking vx_get will also ref the vnode on success. */ if (vx_get_nonblock(vp)) { KKASSERT(vp->v_state == VS_INACTIVE); TAILQ_REMOVE(&vnode_inactive_list, vp, v_list); TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list); spin_unlock(&vfs_spin); continue; } /* * Because we are holding vfs_spin the vnode should currently * be inactive and VREF_TERMINATE should still be set. * * Once vfs_spin is released the vnode's state should remain * unmodified due to both the lock and ref on it. */ KKASSERT(vp->v_state == VS_INACTIVE); spin_unlock(&vfs_spin); #ifdef TRACKVNODE if ((u_long)vp == trackvnode) kprintf("cleanfreevnode %p %08x\n", vp, vp->v_flag); #endif /* * Do not reclaim/reuse a vnode while auxillary refs exists. * This includes namecache refs due to a related ncp being * locked or having children, a VM object association, or * other hold users. * * Do not reclaim/reuse a vnode if someone else has a real * ref on it. This can occur if a filesystem temporarily * releases the vnode lock during VOP_RECLAIM. */ if (vp->v_auxrefs || (vp->v_refcnt & ~VREF_FINALIZE) != VREF_TERMINATE + 1) { failed: if (vp->v_state == VS_INACTIVE) { spin_lock(&vfs_spin); if (vp->v_state == VS_INACTIVE) { TAILQ_REMOVE(&vnode_inactive_list, vp, v_list); TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list); } spin_unlock(&vfs_spin); } vx_put(vp); continue; } /* * VINACTIVE and VREF_TERMINATE are expected to both be set * for vnodes pulled from the inactive list, and cannot be * changed while we hold the vx lock. * * Try to reclaim the vnode. */ KKASSERT(vp->v_flag & VINACTIVE); KKASSERT(vp->v_refcnt & VREF_TERMINATE); if ((vp->v_flag & VRECLAIMED) == 0) { if (cache_inval_vp_nonblock(vp)) goto failed; vgone_vxlocked(vp); /* vnode is still VX locked */ } /* * At this point if there are no other refs or auxrefs on * the vnode with the inactive list locked, and we remove * the vnode from the inactive list, it should not be * possible for anyone else to access the vnode any more. * * Since the vnode is in a VRECLAIMED state, no new * namecache associations could have been made and the * vnode should have already been removed from its mountlist. * * Since we hold a VX lock on the vnode it cannot have been * reactivated (moved out of the inactive list). */ KKASSERT(TAILQ_EMPTY(&vp->v_namecache)); spin_lock(&vfs_spin); if (vp->v_auxrefs || (vp->v_refcnt & ~VREF_FINALIZE) != VREF_TERMINATE + 1) { spin_unlock(&vfs_spin); goto failed; } KKASSERT(vp->v_state == VS_INACTIVE); TAILQ_REMOVE(&vnode_inactive_list, vp, v_list); --inactivevnodes; vp->v_state = VS_DYING; spin_unlock(&vfs_spin); /* * Nothing should have been able to access this vp. Only * our ref should remain now. */ atomic_clear_int(&vp->v_refcnt, VREF_TERMINATE|VREF_FINALIZE); KASSERT(vp->v_refcnt == 1, ("vp %p badrefs %08x", vp, vp->v_refcnt)); /* * Return a VX locked vnode suitable for reuse. */ return(vp); } return(NULL); }