/* * Reclaim an inode so that it can be used for other purposes. */ int ulfs_reclaim(struct vnode *vp) { struct inode *ip = VTOI(vp); if (prtactive && vp->v_usecount > 1) vprint("ulfs_reclaim: pushing active", vp); /* XXX: do we really need two of these? */ /* note: originally the first was inside a wapbl txn */ lfs_update(vp, NULL, NULL, UPDATE_CLOSE); lfs_update(vp, NULL, NULL, UPDATE_CLOSE); /* * Remove the inode from the vnode cache. */ vcache_remove(vp->v_mount, &ip->i_number, sizeof(ip->i_number)); if (ip->i_devvp) { vrele(ip->i_devvp); ip->i_devvp = 0; } #if defined(LFS_QUOTA) || defined(LFS_QUOTA2) ulfsquota_free(ip); #endif #ifdef LFS_DIRHASH if (ip->i_dirhash != NULL) ulfsdirhash_free(ip); #endif return (0); }
int ulfs_rmdir(void *v) { struct vop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; } */ *ap = v; struct vnode *vp, *dvp; struct componentname *cnp; struct inode *ip, *dp; int error; struct ulfs_lookup_results *ulr; vp = ap->a_vp; dvp = ap->a_dvp; cnp = ap->a_cnp; ip = VTOI(vp); dp = VTOI(dvp); /* XXX should handle this material another way */ ulr = &dp->i_crap; ULFS_CHECK_CRAPCOUNTER(dp); /* * No rmdir "." or of mounted directories please. */ if (dp == ip || vp->v_mountedhere != NULL) { if (dp == ip) vrele(dvp); else vput(dvp); vput(vp); return (EINVAL); } fstrans_start(dvp->v_mount, FSTRANS_SHARED); /* * Do not remove a directory that is in the process of being renamed. * Verify that the directory is empty (and valid). (Rmdir ".." won't * be valid since ".." will contain a reference to the current * directory and thus be non-empty.) */ error = 0; if (ip->i_nlink != 2 || !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) { error = ENOTEMPTY; goto out; } if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) { error = EPERM; goto out; } /* * Delete reference to directory before purging * inode. If we crash in between, the directory * will be reattached to lost+found, */ error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1); if (error) { goto out; } VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); cache_purge(dvp); /* * Truncate inode. The only stuff left in the directory is "." and * "..". The "." reference is inconsequential since we're quashing * it. */ dp->i_nlink--; DIP_ASSIGN(dp, nlink, dp->i_nlink); dp->i_flag |= IN_CHANGE; ip->i_nlink--; DIP_ASSIGN(ip, nlink, ip->i_nlink); ip->i_flag |= IN_CHANGE; error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred); cache_purge(vp); #ifdef LFS_DIRHASH if (ip->i_dirhash != NULL) ulfsdirhash_free(ip); #endif out: VN_KNOTE(vp, NOTE_DELETE); vput(vp); fstrans_done(dvp->v_mount); vput(dvp); return (error); }