Ejemplo n.º 1
0
/*
 * Last reference to an inode.  If necessary, write or delete it.
 *
 * ext2_inactive(struct vnode *a_vp)
 */
int
ext2_inactive(struct vop_inactive_args *ap)
{
    struct vnode *vp = ap->a_vp;
    struct inode *ip = VTOI(vp);
    int mode, error = 0;

    ext2_discard_prealloc(ip);
    if (prtactive && vp->v_sysref.refcnt > 1)
        vprint("ext2_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 (!ext2_getinoquota(ip))
            (void)ext2_chkiq(ip, -1, NOCRED, FORCE);
#endif
        error = EXT2_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;
        EXT2_VFREE(vp, ip->i_number, mode);
    }
    if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))
        EXT2_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);
}
Ejemplo n.º 2
0
/*
 * Write a directory entry after a call to namei, using the parameters
 * that it left in the directory inode.  The argument ip is the inode which
 * the new directory entry will refer to.  Dvp is a pointer to the directory
 * to be written, which was left locked by namei. Remaining parameters
 * (dp->i_offset, dp->i_count) indicate how the space for the new
 * entry is to be obtained.
 */
int
ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
{
	struct ext2_dir_entry_2 *ep, *nep;
	struct inode *dp;
	struct buf *bp;
	struct ext2_dir_entry_2 newdir;
	struct iovec aiov;
	struct uio auio;
	u_int dsize;
	int error, loc, newentrysize, spacefree;
	char *dirbuf;
	int     DIRBLKSIZ = ip->i_e2fs->s_blocksize;


	dp = VTOI(dvp);
	newdir.inode = ip->i_number;
	newdir.name_len = cnp->cn_namelen;
	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
	    EXT2_FEATURE_INCOMPAT_FILETYPE))
		newdir.file_type = DTTOFT(IFTODT(ip->i_mode));
	else
		newdir.file_type = EXT2_FT_UNKNOWN;
	bcopy(cnp->cn_nameptr, newdir.name, (unsigned)cnp->cn_namelen + 1);
	newentrysize = EXT2_DIR_REC_LEN(newdir.name_len);
	if (dp->i_count == 0) {
		/*
		 * If dp->i_count is 0, then namei could find no
		 * space in the directory. Here, dp->i_offset will
		 * be on a directory block boundary and we will write the
		 * new entry into a fresh block.
		 */
		if (dp->i_offset & (DIRBLKSIZ - 1))
			panic("ext2_direnter: newblk");
		auio.uio_offset = dp->i_offset;
		newdir.rec_len = DIRBLKSIZ;
		auio.uio_resid = newentrysize;
		aiov.iov_len = newentrysize;
		aiov.iov_base = (caddr_t)&newdir;
		auio.uio_iov = &aiov;
		auio.uio_iovcnt = 1;
		auio.uio_rw = UIO_WRITE;
		auio.uio_segflg = UIO_SYSSPACE;
		auio.uio_td = NULL;
		error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
		if (DIRBLKSIZ >
		    VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
			/* XXX should grow with balloc() */
			panic("ext2_direnter: frag size");
		else if (!error) {
			dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
			dp->i_flag |= IN_CHANGE;
		}
		return (error);
	}

	/*
	 * If dp->i_count is non-zero, then namei found space
	 * for the new entry in the range dp->i_offset to
	 * dp->i_offset + dp->i_count in the directory.
	 * To use this space, we may have to compact the entries located
	 * there, by copying them together towards the beginning of the
	 * block, leaving the free space in one usable chunk at the end.
	 */

	/*
	 * Increase size of directory if entry eats into new space.
	 * This should never push the size past a new multiple of
	 * DIRBLKSIZE.
	 *
	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
	 */
	if (dp->i_offset + dp->i_count > dp->i_size)
		dp->i_size = dp->i_offset + dp->i_count;
	/*
	 * Get the block containing the space for the new directory entry.
	 */
	if ((error = EXT2_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
		return (error);
	/*
	 * Find space for the new entry. In the simple case, the entry at
	 * offset base will have the space. If it does not, then namei
	 * arranged that compacting the region dp->i_offset to
	 * dp->i_offset + dp->i_count would yield the
	 * space.
	 */
	ep = (struct ext2_dir_entry_2 *)dirbuf;
	dsize = EXT2_DIR_REC_LEN(ep->name_len);
	spacefree = ep->rec_len - dsize;
	for (loc = ep->rec_len; loc < dp->i_count; ) {
		nep = (struct ext2_dir_entry_2 *)(dirbuf + loc);
		if (ep->inode) {
			/* trim the existing slot */
			ep->rec_len = dsize;
			ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
		} else {
			/* overwrite; nothing there; header is ours */
			spacefree += dsize;
		}
		dsize = EXT2_DIR_REC_LEN(nep->name_len);
		spacefree += nep->rec_len - dsize;
		loc += nep->rec_len;
		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
	}
	/*
	 * Update the pointer fields in the previous entry (if any),
	 * copy in the new entry, and write out the block.
	 */
	if (ep->inode == 0) {
		if (spacefree + dsize < newentrysize)
			panic("ext2_direnter: compact1");
		newdir.rec_len = spacefree + dsize;
	} else {
		if (spacefree < newentrysize)
			panic("ext2_direnter: compact2");
		newdir.rec_len = spacefree;
		ep->rec_len = dsize;
		ep = (struct ext2_dir_entry_2 *)((char *)ep + dsize);
	}
	bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
	error = bwrite(bp);
	dp->i_flag |= IN_CHANGE | IN_UPDATE;
	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
		error = EXT2_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
				      cnp->cn_cred);
	return (error);
}