/* * Add a ref to an active vnode. This function should never be called * with an inactive vnode (use vget() instead), but might be called * with other states. */ void vref(struct vnode *vp) { KASSERT((VREFCNT(vp) > 0 && vp->v_state != VS_INACTIVE), ("vref: bad refcnt %08x %d", vp->v_refcnt, vp->v_state)); atomic_add_int(&vp->v_refcnt, 1); }
/* * Reclaim an inode so that it can be used for other purposes. * * ufs_reclaim(struct vnode *a_vp) */ int ufs_reclaim(struct vop_reclaim_args *ap) { struct inode *ip; struct vnode *vp = ap->a_vp; struct ufsmount *ump; #ifdef QUOTA int i; #endif ump = VFSTOUFS(vp->v_mount); if (prtactive && VREFCNT(vp) > 1) vprint("ufs_reclaim: pushing active", vp); ip = VTOI(vp); /* * Lazy updates. */ if (ip) { if (ip->i_flag & IN_LAZYMOD) { ip->i_flag |= IN_MODIFIED; ffs_update(vp, 0); } } #ifdef INVARIANTS if (ip && (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) { kprintf("WARNING: INODE %ld flags %08x: modified inode being released!\n", (long)ip->i_number, (int)ip->i_flag); ip->i_flag |= IN_MODIFIED; ffs_update(vp, 0); } #endif /* * Remove the inode from its hash chain and purge namecache * data associated with the vnode. */ vp->v_data = NULL; if (ip) { ufs_ihashrem(ump, ip); if (ip->i_devvp) { vrele(ip->i_devvp); ip->i_devvp = 0; } #ifdef QUOTA for (i = 0; i < MAXQUOTAS; i++) { if (ip->i_dquot[i] != NODQUOT) { ufs_dqrele(vp, ip->i_dquot[i]); ip->i_dquot[i] = NODQUOT; } } #endif #ifdef UFS_DIRHASH if (ip->i_dirhash != NULL) ufsdirhash_free(ip); #endif kfree(ip, VFSTOUFS(vp->v_mount)->um_malloctype); } return (0); }
/* * Last reference to an inode. If necessary, write or delete it. * * ufs_inactive(struct vnode *a_vp) */ int ufs_inactive(struct vop_inactive_args *ap) { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); int mode, error = 0; if (prtactive && VREFCNT(vp) > 1) vprint("ufs_inactive: pushing active", vp); /* * Ignore inodes related to stale file handles. */ if (ip == NULL || ip->i_mode == 0) goto out; if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { #ifdef QUOTA if (!ufs_getinoquota(ip)) (void)ufs_chkiq(ip, -1, NOCRED, FORCE); #endif /* Must have a VM object to truncate */ error = ffs_truncate(vp, (off_t)0, 0, NOCRED); ip->i_rdev = 0; mode = ip->i_mode; ip->i_mode = 0; ip->i_flag |= IN_CHANGE | IN_UPDATE; ffs_vfree(vp, ip->i_number, mode); } if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) ffs_update(vp, 0); out: /* * If we are done with the inode, reclaim it * so that it can be reused immediately. */ if (ip == NULL || ip->i_mode == 0) vrecycle(vp); return (error); }
/* * nwfs_remove call. It isn't possible to emulate UFS behaivour because * NetWare doesn't allow delete/rename operations on an opened file. * * nwfs_remove(struct vnode *a_dvp, * struct vnode *a_vp, struct componentname *a_cnp) */ static int nwfs_remove(struct vop_old_remove_args *ap) { struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct nwnode *np = VTONW(vp); struct nwmount *nmp = VTONWFS(vp); int error; if (vp->v_type == VDIR || np->opened || VREFCNT(vp) > 1) { error = EPERM; } else if (!ncp_conn_valid(NWFSTOCONN(nmp))) { error = EIO; } else { error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id, cnp->cn_namelen,cnp->cn_nameptr,cnp->cn_td,cnp->cn_cred); if (error == 0) np->n_flag |= NSHOULDFREE; else if (error == 0x899c) error = EACCES; } return (error); }
/* * Last reference to an node. If necessary, write or delete it. * * hpfs_inactive(struct vnode *a_vp) */ int hpfs_inactive(struct vop_inactive_args *ap) { struct vnode *vp = ap->a_vp; struct hpfsnode *hp = VTOHP(vp); int error; dprintf(("hpfs_inactive(0x%x): \n", hp->h_no)); if (hp->h_flag & H_CHANGE) { dprintf(("hpfs_inactive: node changed, update\n")); error = hpfs_update (hp); if (error) return (error); } if (hp->h_flag & H_PARCHANGE) { dprintf(("hpfs_inactive: parent node changed, update\n")); error = hpfs_updateparent (hp); if (error) return (error); } if (prtactive && VREFCNT(vp) > 1) vprint("hpfs_inactive: pushing active", vp); if (hp->h_flag & H_INVAL) { #if defined(__DragonFly__) vrecycle(vp); #else /* defined(__NetBSD__) */ vgone(vp); #endif return (0); } return (0); }
static int ntfs_unmount(struct mount *mp, int mntflags) { struct ntfsmount *ntmp; int error, ronly, flags, i; dprintf(("ntfs_unmount: unmounting...\n")); ntmp = VFSTONTFS(mp); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; flags = 0; if(mntflags & MNT_FORCE) flags |= FORCECLOSE; dprintf(("ntfs_unmount: vflushing...\n")); error = vflush(mp, 0, flags | SKIPSYSTEM); if (error) { kprintf("ntfs_unmount: vflush failed: %d\n",error); return (error); } /* Check if only system vnodes are left */ for(i=0;i<NTFS_SYSNODESNUM;i++) if((ntmp->ntm_sysvn[i]) && (VREFCNT(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY); /* Dereference all system vnodes */ for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); /* vflush system vnodes */ error = vflush(mp, 0, flags); if (error) kprintf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); /* Check if the type of device node isn't VBAD before * touching v_cdevinfo. If the device vnode is revoked, the * field is NULL and touching it causes null pointer derefercence. */ if (ntmp->ntm_devvp->v_type != VBAD) ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL; vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0); error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, NULL); vn_unlock(ntmp->ntm_devvp); vrele(ntmp->ntm_devvp); /* free the toupper table, if this has been last mounted ntfs volume */ ntfs_toupper_unuse(); dprintf(("ntfs_umount: freeing memory...\n")); ntfs_u28_uninit(ntmp); ntfs_82u_uninit(ntmp); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; kfree(ntmp->ntm_ad, M_NTFSMNT); kfree(ntmp, M_NTFSMNT); return (error); }
/* * 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); }
/* * Allocate a VM object for a vnode, typically a regular file vnode. * * Some additional information is required to generate a properly sized * object which covers the entire buffer cache buffer straddling the file * EOF. Userland does not see the extra pages as the VM fault code tests * against v_filesize. */ vm_object_t vnode_pager_alloc(void *handle, off_t length, vm_prot_t prot, off_t offset, int blksize, int boff) { vm_object_t object; struct vnode *vp; off_t loffset; vm_pindex_t lsize; /* * Pageout to vnode, no can do yet. */ if (handle == NULL) return (NULL); /* * XXX hack - This initialization should be put somewhere else. */ if (vnode_pbuf_freecnt < 0) { vnode_pbuf_freecnt = nswbuf / 2 + 1; } /* * Serialize potential vnode/object teardowns and interlocks */ vp = (struct vnode *)handle; lwkt_gettoken(&vp->v_token); /* * If the object is being terminated, wait for it to * go away. */ object = vp->v_object; if (object) { vm_object_hold(object); KKASSERT((object->flags & OBJ_DEAD) == 0); } if (VREFCNT(vp) <= 0) panic("vnode_pager_alloc: no vnode reference"); /* * Round up to the *next* block, then destroy the buffers in question. * Since we are only removing some of the buffers we must rely on the * scan count to determine whether a loop is necessary. * * Destroy any pages beyond the last buffer. */ if (boff < 0) boff = (int)(length % blksize); if (boff) loffset = length + (blksize - boff); else loffset = length; lsize = OFF_TO_IDX(round_page64(loffset)); if (object == NULL) { /* * And an object of the appropriate size */ object = vm_object_allocate_hold(OBJT_VNODE, lsize); object->handle = handle; vp->v_object = object; vp->v_filesize = length; if (vp->v_mount && (vp->v_mount->mnt_kern_flag & MNTK_NOMSYNC)) vm_object_set_flag(object, OBJ_NOMSYNC); vref(vp); } else { vm_object_reference_quick(object); /* also vref's */ if (object->size != lsize) { kprintf("vnode_pager_alloc: Warning, objsize " "mismatch %jd/%jd vp=%p obj=%p\n", (intmax_t)object->size, (intmax_t)lsize, vp, object); } if (vp->v_filesize != length) { kprintf("vnode_pager_alloc: Warning, filesize " "mismatch %jd/%jd vp=%p obj=%p\n", (intmax_t)vp->v_filesize, (intmax_t)length, vp, object); } } vm_object_drop(object); lwkt_reltoken(&vp->v_token); return (object); }