/* * Allocate an inode in the file system. * * If allocating a directory, use ext2fs_dirpref to select the inode. * If allocating in a directory, the following hierarchy is followed: * 1) allocate the preferred inode. * 2) allocate an inode in the same cylinder group. * 3) quadratically rehash into other cylinder groups, until an * available inode is located. * If no inode preference is given the following hierarchy is used * to allocate an inode: * 1) allocate an inode in cylinder group 0. * 2) quadratically rehash into other cylinder groups, until an * available inode is located. */ int ext2fs_inode_alloc(struct inode *pip, mode_t mode, struct ucred *cred, struct vnode **vpp) { struct vnode *pvp; struct m_ext2fs *fs; struct inode *ip; ufsino_t ino, ipref; int cg, error; *vpp = NULL; pvp = ITOV(pip); fs = pip->i_e2fs; if (fs->e2fs.e2fs_ficount == 0) goto noinodes; if ((mode & IFMT) == IFDIR) cg = ext2fs_dirpref(fs); else cg = ino_to_cg(fs, pip->i_number); ipref = cg * fs->e2fs.e2fs_ipg + 1; ino = (ufsino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg); if (ino == 0) goto noinodes; error = VFS_VGET(pvp->v_mount, ino, vpp); if (error) { ext2fs_inode_free(pip, ino, mode); return (error); } ip = VTOI(*vpp); if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) { printf("mode = 0%o, nlinks %u, inum = %u, fs = %s\n", ip->i_e2fs_mode, ip->i_e2fs_nlink, ip->i_number, fs->e2fs_fsmnt); panic("ext2fs_valloc: dup alloc"); } memset(ip->i_e2din, 0, sizeof(struct ext2fs_dinode)); /* * Set up a new generation number for this inode. */ if (++ext2gennumber < (u_long)time_second) ext2gennumber = time_second; ip->i_e2fs_gen = ext2gennumber; return (0); noinodes: ext2fs_fserr(fs, cred->cr_uid, "out of inodes"); uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt); return (ENOSPC); }
/* * Last reference to an inode. If necessary, write or delete it. */ int ext2fs_inactive(void *v) { struct vop_inactive_args *ap = v; struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct proc *p = ap->a_p; struct timespec ts; int error = 0; #ifdef DIAGNOSTIC extern int prtactive; if (prtactive && vp->v_usecount != 0) vprint("ext2fs_inactive: pushing active", vp); #endif /* Get rid of inodes related to stale file handles. */ if (ip->i_e2din == NULL || ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime) goto out; error = 0; if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { if (ext2fs_size(ip) != 0) { error = ext2fs_truncate(ip, (off_t)0, 0, NOCRED); } getnanotime(&ts); ip->i_e2fs_dtime = ts.tv_sec; ip->i_flag |= IN_CHANGE | IN_UPDATE; ext2fs_inode_free(ip, ip->i_number, ip->i_e2fs_mode); } if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { ext2fs_update(ip, 0); } out: VOP_UNLOCK(vp, p); /* * If we are done with the inode, reclaim it * so that it can be reused immediately. */ if (ip->i_e2din == NULL || ip->i_e2fs_dtime != 0) vrecycle(vp, p); return (error); }