/* * Allocate an inode in the file system. * * we leave the actual allocation strategy to the (modified) * ext2_new_inode(), to make sure we get the policies right */ int ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) { struct inode *pip; struct ext2_sb_info *fs; struct inode *ip; ino_t ino; int i, error; *vpp = NULL; pip = VTOI(pvp); fs = pip->i_e2fs; if (fs->s_es->s_free_inodes_count == 0) goto noinodes; /* call the Linux routine - it returns the inode number only */ ino = ext2_new_inode(pip, mode); if (ino == 0) goto noinodes; error = VFS_VGET(pvp->v_mount, NULL, ino, vpp); if (error) { EXT2_VFREE(pvp, ino, mode); return (error); } ip = VTOI(*vpp); /* the question is whether using VGET was such good idea at all - Linux doesn't read the old inode in when it's allocating a new one. I will set at least i_size & i_blocks the zero. */ ip->i_mode = 0; ip->i_size = 0; ip->i_blocks = 0; ip->i_flags = 0; /* now we want to make sure that the block pointers are zeroed out */ for (i = 0; i < NDADDR; i++) ip->i_db[i] = 0; for (i = 0; i < NIADDR; i++) ip->i_ib[i] = 0; /* * Set up a new generation number for this inode. * XXX check if this makes sense in ext2 */ if (ip->i_gen == 0 || ++ip->i_gen == 0) ip->i_gen = krandom() / 2 + 1; /* kprintf("ext2_valloc: allocated inode %d\n", ino); */ return (0); noinodes: ext2_fserr(fs, cred->cr_uid, "out of inodes"); uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); return (ENOSPC); }
/* * 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); }