struct ufs1_dinode * getnextinode(ino_t inumber) { long size; daddr_t dblk; static struct ufs1_dinode *dp; if (inumber != nextino++ || inumber > maxino) { errx(1, "bad inode number %ju to nextinode", (intmax_t)inumber); } if (inumber >= lastinum) { readcnt++; dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); if (readcnt % readpercg == 0) { size = partialsize; lastinum += partialcnt; } else { size = inobufsize; lastinum += fullcnt; } bread(dblk, (char *)inodebuf, size); dp = inodebuf; } return (dp++); }
union dinode * getnextinode(ino_t inumber) { long size; ufs2_daddr_t dblk; union dinode *dp; static caddr_t nextinop; if (inumber != nextino++ || inumber > lastvalidinum) errx(1, "bad inode number %ju to nextinode", (uintmax_t)inumber); if (inumber >= lastinum) { readcnt++; dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); if (readcnt % readpercg == 0) { size = partialsize; lastinum += partialcnt; } else { size = inobufsize; lastinum += fullcnt; } /* * If bread returns an error, it will already have zeroed * out the buffer, so we do not need to do so here. */ bread(dblk, inodebuf, size); nextinop = inodebuf; } dp = (union dinode *)nextinop; if (sblock.fs_magic == FS_UFS1_MAGIC) nextinop += sizeof(struct ufs1_dinode); else nextinop += sizeof(struct ufs2_dinode); return (dp); }
static struct ufs1_dinode * get_inode(int fd, struct fs *super, ino_t ino) { static struct ufs1_dinode *ip; static ino_t last; if (fd < 0) { /* flush cache */ if (ip) { free(ip); ip = NULL; } return 0; } if (!ip || ino < last || ino >= last + INOCNT(super)) { if (!ip && !(ip = (struct ufs1_dinode *)malloc(INOSZ(super)))) errx(1, "allocate inodes"); last = (ino / INOCNT(super)) * INOCNT(super); if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, 0) < (off_t)0 || read(fd,ip,INOSZ(super)) != (ssize_t)INOSZ(super)) err(1, "read inodes"); } return ip + ino % INOCNT(super); }
/* * Allocate an inode on the disk */ void iput(union dinode *ip, ino_t ino) { ufs2_daddr_t d; bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg, sblock.fs_cgsize); if (acg.cg_magic != CG_MAGIC) { printf("cg 0: bad magic number\n"); exit(31); } acg.cg_cs.cs_nifree--; setbit(cg_inosused(&acg), ino); wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, (char *)&acg); sblock.fs_cstotal.cs_nifree--; fscs[0].cs_nifree--; if (ino >= (unsigned long)sblock.fs_ipg * sblock.fs_ncg) { printf("fsinit: inode value out of range (%ju).\n", (uintmax_t)ino); exit(32); } d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino)); bread(&disk, part_ofs + d, (char *)iobuf, sblock.fs_bsize); if (sblock.fs_magic == FS_UFS1_MAGIC) ((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] = ip->dp1; else ((struct ufs2_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] = ip->dp2; wtfs(d, sblock.fs_bsize, (char *)iobuf); }
static long ReadInode( long inodeNum, InodePtr inode, long * flags, long * time ) { long fragNum = ino_to_fsba(gFS, inodeNum); long blockOffset = ino_to_fsbo(gFS, inodeNum) * sizeof(Inode); ReadBlock(fragNum, blockOffset, sizeof(Inode), (char *)inode, 1); byte_swap_dinode_in(inode); if (time != 0) *time = inode->di_mtime; if (flags != 0) { switch (inode->di_mode & IFMT) { case IFREG: *flags = kFileTypeFlat; break; case IFDIR: *flags = kFileTypeDirectory; break; case IFLNK: *flags = kFileTypeLink; break; default : *flags = kFileTypeUnknown; break; } *flags |= inode->di_mode & kPermMask; if (inode->di_uid != 0) *flags |= kOwnerNotRoot; } return 0; }
/* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode * to disk if the IN_MODIFIED flag is set (it may be set initially, or by * the timestamp update). The IN_LAZYMOD flag is set to force a write * later if not now. If we write now, then clear both IN_MODIFIED and * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is * set, then wait for the write to complete. */ int ext2_update(struct vnode *vp, int waitfor) { struct m_ext2fs *fs; struct buf *bp; struct inode *ip; int error; ASSERT_VOP_ELOCKED(vp, "ext2_update"); ext2_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) return (0); ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); fs = ip->i_e2fs; if(fs->e2fs_ronly) return (0); if ((error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { brelse(bp); return (error); } ext2_i2ei(ip, (struct ext2fs_dinode *)((char *)bp->b_data + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number))); if (waitfor && !DOINGASYNC(vp)) return (bwrite(bp)); else { bdwrite(bp); return (0); } }
struct ufs1_dinode * getnextinode(ufs1_ino_t inumber) { long size; ufs_daddr_t dblk; static struct ufs1_dinode *dp; if (inumber != nextino++ || inumber > maxino) errx(EEXIT, "bad inode number %d to nextinode", inumber); if (inumber >= lastinum) { readcnt++; dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); if (readcnt % readpercg == 0) { size = partialsize; lastinum += partialcnt; } else { size = inobufsize; lastinum += fullcnt; } /* * If bread returns an error, it will already have zeroed * out the buffer, so we do not need to do so here. */ bread(fsreadfd, (char *)inodebuf, dblk, size); dp = inodebuf; } return (dp++); }
union dinode * getino(ino_t inum, int *modep) { static ino_t minino, maxino; static caddr_t inoblock; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL) quit("cannot allocate inode memory.\n"); curino = inum; if (inum >= minino && inum < maxino) goto gotit; bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock, (int)sblock->fs_bsize); minino = inum - (inum % INOPB(sblock)); maxino = minino + INOPB(sblock); gotit: if (sblock->fs_magic == FS_UFS1_MAGIC) { dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino]; *modep = (dp1->di_mode & IFMT); return ((union dinode *)dp1); } dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino]; *modep = (dp2->di_mode & IFMT); return ((union dinode *)dp2); }
/* * This function provides access to an individual inode. We find out in which * block the requested inode is located, read it from disk if needed, and * return the pointer into that block. We maintain a cache of one block to * not read the same block again and again if we iterate linearly over all * inodes. */ struct ufs1_dinode * ginode(ino_t inumber, int fsi) { ufs_daddr_t iblk; static ino_t startinum=0; /* first inode in cached block */ struct ufs1_dinode *pi; DBG_ENTER; pi=(struct ufs1_dinode *)(void *)ablk; if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { /* * The block needed is not cached, so we have to read it from * disk now. */ iblk = ino_to_fsba(&sblock, inumber); rdfs(fsbtodb(&sblock, iblk), (size_t)sblock.fs_bsize, &ablk, fsi); startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } DBG_LEAVE; return (&(pi[inumber % INOPB(&sblock)])); }
/* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode * to disk if the IN_MODIFIED flag is set (it may be set initially, or by * the timestamp update). The IN_LAZYMOD flag is set to force a write * later if not now. If we write now, then clear both IN_MODIFIED and * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is * set, then wait for the write to complete. */ int ffs_update(struct vnode *vp, int waitfor) { struct fs *fs; struct buf *bp; struct inode *ip; int error; ufs_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) return (0); ip->i_flag &= ~(IN_LAZYMOD | IN_MODIFIED); fs = ip->i_fs; if (fs->fs_ronly) return (0); /* * The vnode type is usually set to VBAD if an unrecoverable I/O * error has occured (such as when reading the inode). Clear the * modified bits but do not write anything out in this case. */ if (vp->v_type == VBAD) return (0); /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ ip->i_din.di_ouid = ip->i_uid; /* XXX */ ip->i_din.di_ogid = ip->i_gid; /* XXX */ } /* XXX */ error = bread(ip->i_devvp, fsbtodoff(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->fs_bsize, &bp); if (error) { brelse(bp); return (error); } if (DOINGSOFTDEP(vp)) softdep_update_inodeblock(ip, bp, waitfor); else if (ip->i_effnlink != ip->i_nlink) panic("ffs_update: bad link cnt"); *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = ip->i_din; if (waitfor && !DOINGASYNC(vp)) { return (bwrite(bp)); } else if (vm_page_count_severe() || buf_dirty_count_severe()) { return (bwrite(bp)); } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); return (0); } }
/* * Read a new inode into a file structure. */ static int read_inode(ino32_t inumber, struct open_file *f) { struct file *fp = (struct file *)f->f_fsdata; struct fs *fs = fp->f_fs; char *buf; size_t rsize; int rc; daddr_t inode_sector = 0; /* XXX: gcc */ #ifdef LIBSA_LFS struct ufs_dinode *dip; int cnt; #endif #ifdef LIBSA_LFS if (inumber == fs->lfs_ifile) inode_sector = FSBTODB(fs, fs->lfs_idaddr); else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0) return rc; #else inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); #endif /* * Read inode and save it. */ buf = fp->f_buf; twiddle(); rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, inode_sector, fs->fs_bsize, buf, &rsize); if (rc) return rc; if (rsize != fs->fs_bsize) return EIO; #ifdef LIBSA_LFS cnt = INOPBx(fs); dip = (struct ufs_dinode *)buf + (cnt - 1); for (; dip->di_inumber != inumber; --dip) { /* kernel code panics, but boot blocks which panic are Bad. */ if (--cnt == 0) return EINVAL; } fp->f_di = *dip; #else fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)]; #endif /* * Clear out the old buffers */ fp->f_ind_cache_block = ~0; fp->f_buf_blkno = -1; return rc; }
static union dinode * get_inode(int fd, struct fs *super, ino_t ino) { static caddr_t ipbuf; static struct cg *cgp; static ino_t last; static int cg; struct ufs2_dinode *di2; if (fd < 0) { /* flush cache */ if (ipbuf) { free(ipbuf); ipbuf = NULL; if (super != NULL && super->fs_magic == FS_UFS2_MAGIC) { free(cgp); cgp = NULL; } } return 0; } if (!ipbuf || ino < last || ino >= last + INOCNT(super)) { if (super->fs_magic == FS_UFS2_MAGIC && (!cgp || cg != ino_to_cg(super, ino))) { cg = ino_to_cg(super, ino); if (!cgp && !(cgp = malloc(super->fs_cgsize))) errx(1, "allocate cg"); if (pread(fd, cgp, super->fs_cgsize, (off_t)cgtod(super, cg) << super->fs_fshift) != super->fs_cgsize) if (read(fd, cgp, super->fs_cgsize) != super->fs_cgsize) err(1, "read cg"); if (!cg_chkmagic(cgp)) errx(1, "cg has bad magic"); } if (!ipbuf && !(ipbuf = malloc(INOSZ(super)))) err(1, "allocate inodes"); last = (ino / INOCNT(super)) * INOCNT(super); if (lseek(fd, (off_t)ino_to_fsba(super, last) << super->fs_fshift, SEEK_SET) < 0 || read(fd, ipbuf, INOSZ(super)) != INOSZ(super)) { err(1, "read inodes"); } } if (super->fs_magic == FS_UFS1_MAGIC) return ((union dinode *) &((struct ufs1_dinode *)ipbuf)[ino % INOCNT(super)]); di2 = &((struct ufs2_dinode *)ipbuf)[ino % INOCNT(super)]; /* If the inode is unused, it might be unallocated too, so zero it. */ if (isclr(cg_inosused(cgp), ino % super->fs_ipg)) memset(di2, 0, sizeof(*di2)); return ((union dinode *)di2); }
int putino(struct uufsd *disk) { struct fs *fs; fs = &disk->d_fs; if (disk->d_inoblock == NULL) { ERROR(disk, "No inode block allocated"); return (-1); } if (bwrite(disk, fsbtodb(fs, ino_to_fsba(&disk->d_fs, disk->d_inomin)), disk->d_inoblock, disk->d_fs.fs_bsize) <= 0) return (-1); return (0); }
struct ufs1_dinode * getino(ufs1_ino_t inum) { static daddr_t minino, maxino; static struct ufs1_dinode inoblock[MAXINOPB]; curino = inum; if (inum >= (unsigned)minino && inum < (unsigned)maxino) return (&inoblock[inum - minino]); bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), (char *)inoblock, (int)sblock->fs_bsize); minino = inum - (inum % INOPB(sblock)); maxino = minino + INOPB(sblock); return (&inoblock[inum - minino]); }
/* * Read a new inode into a file structure. */ static int read_inode(ino_t inumber, struct open_file *f) { struct file *fp = (struct file *)f->f_fsdata; struct fs *fs = fp->f_fs; char *buf; size_t rsize; int rc; if (fs == NULL) panic("fs == NULL"); /* * Read inode and save it. */ buf = malloc(fs->fs_bsize); twiddle(); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize); if (rc) goto out; if (rsize != fs->fs_bsize) { rc = EIO; goto out; } { struct ufs1_dinode *dp; dp = (struct ufs1_dinode *)buf; fp->f_di = dp[ino_to_fsbo(fs, inumber)]; } /* * Clear out the old buffers */ { int level; for (level = 0; level < NIADDR; level++) fp->f_blkno[level] = -1; fp->f_buf_blkno = -1; } out: free(buf); return (rc); }
static int find(char *path) { char *rest, ch; int block, off, loc, ino = ROOTINO; struct dirent *dp; char list_only; list_only = (path[0] == '?' && path[1] == '\0'); loop: devread(iobuf, fsbtodb(fs, ino_to_fsba(fs, ino)) + boff, fs->fs_bsize); bcopy((void *)&((struct dinode *)iobuf)[ino % fs->fs_inopb], (void *)&inode.i_din, sizeof (struct dinode)); if (!*path) return 1; while (*path == '/') path++; if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR)) return 0; for (rest = path; (ch = *rest) && ch != '/'; rest++) ; *rest = 0; loc = 0; do { if (loc >= inode.i_size) { if (list_only) { putchar('\n'); return -1; } else { return 0; } } if (!(off = blkoff(fs, loc))) { block = lblkno(fs, loc); devread(iobuf, fsbtodb(fs, block_map(block)) + boff, blksize(fs, &inode, block)); } dp = (struct dirent *)(iobuf + off); loc += dp->d_reclen; if (dp->d_fileno && list_only) { puts(dp->d_name); putchar(' '); } } while (!dp->d_fileno || strcmp(path, dp->d_name)); ino = dp->d_fileno; *(path = rest) = ch; goto loop; }
int getino(struct uufsd *disk, void **dino, ino_t inode, int *mode) { ino_t min, max; caddr_t inoblock; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; struct fs *fs; ERROR(disk, NULL); fs = &disk->d_fs; inoblock = disk->d_inoblock; min = disk->d_inomin; max = disk->d_inomax; if (inoblock == NULL) { inoblock = malloc(fs->fs_bsize); if (inoblock == NULL) { ERROR(disk, "unable to allocate inode block"); return (-1); } disk->d_inoblock = inoblock; } if (inode >= min && inode < max) goto gotit; bread(disk, fsbtodb(fs, ino_to_fsba(fs, inode)), inoblock, fs->fs_bsize); disk->d_inomin = min = inode - (inode % INOPB(fs)); disk->d_inomax = max = min + INOPB(fs); gotit: switch (disk->d_ufs) { case 1: dp1 = &((struct ufs1_dinode *)inoblock)[inode - min]; *mode = dp1->di_mode & IFMT; *dino = dp1; return (0); case 2: dp2 = &((struct ufs2_dinode *)inoblock)[inode - min]; *mode = dp2->di_mode & IFMT; *dino = dp2; return (0); default: break; } ERROR(disk, "unknown UFS filesystem type"); return (-1); }
/* * General purpose interface for reading inodes. */ struct ufs1_dinode * ginode(ufs1_ino_t inumber) { ufs_daddr_t iblk; if (inumber < ROOTINO || inumber > maxino) errx(EEXIT, "bad inode number %d to ginode", inumber); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { iblk = ino_to_fsba(&sblock, inumber); if (pbp != 0) pbp->b_flags &= ~B_INUSE; pbp = getdatablk(iblk, sblock.fs_bsize); startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); }
int ffs_reload_vnode(struct vnode *vp, void *args) { struct ffs_reload_args *fra = args; struct inode *ip; struct buf *bp; int error; /* * Step 4: invalidate all inactive vnodes. */ if (vp->v_usecount == 0) { vgonel(vp, fra->p); return (0); } /* * Step 5: invalidate all cached file data. */ if (vget(vp, LK_EXCLUSIVE, fra->p)) return (0); if (vinvalbuf(vp, 0, fra->cred, fra->p, 0, 0)) panic("ffs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(fra->devvp, fsbtodb(fra->fs, ino_to_fsba(fra->fs, ip->i_number)), (int)fra->fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); vput(vp); return (error); } *ip->i_din1 = *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fra->fs, ip->i_number)); ip->i_effnlink = DIP(ip, nlink); brelse(bp); vput(vp); return (0); }
ino_t cgialloc(struct uufsd *disk) { struct ufs2_dinode *dp2; u_int8_t *inosused; struct cg *cgp; struct fs *fs; ino_t ino; int i; fs = &disk->d_fs; cgp = &disk->d_cg; inosused = cg_inosused(cgp); for (ino = 0; ino < fs->fs_ipg; ino++) if (isclr(inosused, ino)) goto gotit; return (0); gotit: if (fs->fs_magic == FS_UFS2_MAGIC && ino + INOPB(fs) > cgp->cg_initediblk && cgp->cg_initediblk < cgp->cg_niblk) { char block[MAXBSIZE]; bzero(block, (int)fs->fs_bsize); dp2 = (struct ufs2_dinode *)█ for (i = 0; i < INOPB(fs); i++) { dp2->di_gen = arc4random() / 2 + 1; dp2++; } if (bwrite(disk, ino_to_fsba(fs, cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk), block, fs->fs_bsize)) return (0); cgp->cg_initediblk += INOPB(fs); } setbit(inosused, ino); cgp->cg_irotor = ino; cgp->cg_cs.cs_nifree--; fs->fs_cstotal.cs_nifree--; fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--; fs->fs_fmod = 1; return (ino + (cgp->cg_cgx * fs->fs_ipg)); }
/* * Update the access, modified, and inode change times as specified by the * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is * used to specify that the inode needs to be updated but that the times have * already been set. The access and modified times are taken from the second * and third parameters; the inode change time is always taken from the current * time. If waitfor is set, then wait for the disk write of the inode to * complete. */ int ext2fs_update(struct inode *ip, int waitfor) { struct m_ext2fs *fs; struct buf *bp; int error; caddr_t cp; if (ITOV(ip)->v_mount->mnt_flag & MNT_RDONLY) return (0); EXT2FS_ITIMES(ip); if ((ip->i_flag & IN_MODIFIED) == 0) return (0); ip->i_flag &= ~IN_MODIFIED; fs = ip->i_e2fs; error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, &bp); if (error) { brelse(bp); return (error); } ip->i_flag &= ~(IN_MODIFIED); cp = (caddr_t)bp->b_data + (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs)); /* * See note about 16-bit UID/GID limitation in ext2fs_vget(). Now * that we are about to write the inode, construct the split UID and * GID fields out of the two 32-bit fields we kept in memory. */ ip->i_e2fs_uid_low = (u_int16_t)ip->i_e2fs_uid; ip->i_e2fs_gid_low = (u_int16_t)ip->i_e2fs_gid; ip->i_e2fs_uid_high = ip->i_e2fs_uid >> 16; ip->i_e2fs_gid_high = ip->i_e2fs_gid >> 16; e2fs_isave(fs, ip->i_e2din, (struct ext2fs_dinode *)cp); if (waitfor) return (bwrite(bp)); else { bdwrite(bp); return (0); } }
int ext2fs_reload_vnode(struct vnode *vp, void *args) { struct ext2fs_reload_args *era = args; struct buf *bp; struct inode *ip; int error; caddr_t cp; /* * Step 4: invalidate all inactive vnodes. */ if (vp->v_usecount == 0) { vgonel(vp, era->p); return (0); } /* * Step 5: invalidate all cached file data. */ if (vget(vp, LK_EXCLUSIVE, era->p)) return (0); if (vinvalbuf(vp, 0, era->cred, era->p, 0, 0)) panic("ext2fs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(era->devvp, fsbtodb(era->fs, ino_to_fsba(era->fs, ip->i_number)), (int)era->fs->e2fs_bsize, &bp); if (error) { vput(vp); return (error); } cp = (caddr_t)bp->b_data + (ino_to_fsbo(era->fs, ip->i_number) * EXT2_DINODE_SIZE(era->fs)); e2fs_iload((struct ext2fs_dinode *)cp, ip->i_e2din); brelse(bp); vput(vp); return (0); }
/* * General purpose interface for reading inodes. */ union dinode * ginode(ino_t inumber) { ufs2_daddr_t iblk; if (inumber < ROOTINO || inumber > maxino) errx(EEXIT, "bad inode number %ju to ginode", (uintmax_t)inumber); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { iblk = ino_to_fsba(&sblock, inumber); if (pbp != NULL) pbp->b_flags &= ~B_INUSE; pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES); startinum = rounddown(inumber, INOPB(&sblock)); } if (sblock.fs_magic == FS_UFS1_MAGIC) return ((union dinode *) &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]); return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]); }
/* * Allocate an inode on the disk */ void iput(union dinode *ip, ino_t ino) { daddr64_t d; if (Oflag <= 1) ip->dp1.di_gen = (u_int32_t)arc4random(); else ip->dp2.di_gen = (u_int32_t)arc4random(); rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, (char *)&acg); if (acg.cg_magic != CG_MAGIC) errx(41, "cg 0: bad magic number"); acg.cg_cs.cs_nifree--; setbit(cg_inosused(&acg), ino); wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, (char *)&acg); sblock.fs_cstotal.cs_nifree--; fscs[0].cs_nifree--; if (ino >= sblock.fs_ipg * sblock.fs_ncg) errx(32, "fsinit: inode value %d out of range", ino); d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino)); rdfs(d, sblock.fs_bsize, iobuf); if (Oflag <= 1) ((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] = ip->dp1; else ((struct ufs2_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] = ip->dp2; wtfs(d, sblock.fs_bsize, iobuf); }
/* * Read a new inode into a file structure. */ static int read_inode(ino32_t inumber, struct open_file *f) { struct file *fp = (struct file *)f->f_fsdata; struct m_ext2fs *fs = fp->f_fs; char *buf; size_t rsize; int rc; daddr_t inode_sector; struct ext2fs_dinode *dip; inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); /* * Read inode and save it. */ buf = fp->f_buf; twiddle(); rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, inode_sector, fs->e2fs_bsize, buf, &rsize); if (rc) return rc; if (rsize != fs->e2fs_bsize) return EIO; dip = (struct ext2fs_dinode *)(buf + EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber)); e2fs_iload(dip, &fp->f_di, EXT2_DINODE_SIZE(fs)); /* * Clear out the old buffers */ fp->f_ind_cache_block = ~0; fp->f_buf_blkno = -1; return rc; }
/* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode * to disk if the IN_MODIFIED flag is set (it may be set initially, or by * the timestamp update). The IN_LAZYMOD flag is set to force a write * later if not now. If we write now, then clear both IN_MODIFIED and * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is * set, then wait for the write to complete. */ int ext2_update(struct vnode *vp, int waitfor) { struct ext2_sb_info *fs; struct buf *bp; struct inode *ip; int error; ext2_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0) return (0); ip->i_flag &= ~(IN_LAZYMOD | IN_MODIFIED); if (vp->v_mount->mnt_flag & MNT_RDONLY) return (0); fs = ip->i_e2fs; error = bread(ip->i_devvp, fsbtodoff(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->s_blocksize, &bp); if (error) { brelse(bp); return (error); } ext2_di2ei( &ip->i_din, (struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number))); /* if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) return (bwrite(bp)); else { */ bdwrite(bp); return (0); /* } */ }
/* * Look up an EXT2FS dinode number to find its incore vnode, otherwise read it * in from disk. If it is in core, wait for the lock bit to clear, then * return the inode locked. Detection and handling of mount points must be * done by the calling routine. */ static int ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { struct m_ext2fs *fs; struct inode *ip; struct ext2mount *ump; struct buf *bp; struct vnode *vp; struct cdev *dev; struct thread *td; int i, error; int used_blocks; td = curthread; error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL); if (error || *vpp != NULL) return (error); ump = VFSTOEXT2(mp); dev = ump->um_dev; /* * If this malloc() is performed after the getnewvnode() * it might block, leaving a vnode with a NULL v_data to be * found by ext2_sync() if a sync happens to fire right then, * which will cause a panic because ext2_sync() blindly * dereferences vp->v_data (as well it should). */ ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); /* Allocate a new vnode/inode. */ if ((error = getnewvnode("ext2fs", mp, &ext2_vnodeops, &vp)) != 0) { *vpp = NULL; free(ip, M_EXT2NODE); return (error); } vp->v_data = ip; ip->i_vnode = vp; ip->i_e2fs = fs = ump->um_e2fs; ip->i_ump = ump; ip->i_number = ino; lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); error = insmntque(vp, mp); if (error != 0) { free(ip, M_EXT2NODE); *vpp = NULL; return (error); } error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL); if (error || *vpp != NULL) return (error); /* Read in the disk contents for the inode, copy into the inode. */ if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { /* * The inode does not contain anything useful, so it would * be misleading to leave it on its hash chain. With mode * still zero, it will be unlinked and returned to the free * list by vput(). */ brelse(bp); vput(vp); *vpp = NULL; return (error); } /* convert ext2 inode to dinode */ ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ino)), ip); ip->i_block_group = ino_to_cg(fs, ino); ip->i_next_alloc_block = 0; ip->i_next_alloc_goal = 0; /* * Now we want to make sure that block pointers for unused * blocks are zeroed out - ext2_balloc depends on this * although for regular files and directories only */ if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) { used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize; for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++) ip->i_db[i] = 0; } /* ext2_print_inode(ip); */ bqrelse(bp); /* * Initialize the vnode from the inode, check for aliases. * Note that the underlying vnode may have changed. */ if ((error = ext2_vinit(mp, &ext2_fifoops, &vp)) != 0) { vput(vp); *vpp = NULL; return (error); } /* * Finish inode initialization. */ /* * Set up a generation number for this inode if it does not * already have one. This should only happen on old filesystems. */ if (ip->i_gen == 0) { ip->i_gen = random() / 2 + 1; if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) ip->i_flag |= IN_MODIFIED; } *vpp = vp; return (0); }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) invalidate all cluster summary information. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. * XXX we are missing some steps, in particular # 3, this has to be reviewed. */ static int ext2_reload(struct mount *mp, struct thread *td) { struct vnode *vp, *mvp, *devvp; struct inode *ip; struct buf *bp; struct ext2fs *es; struct m_ext2fs *fs; struct csum *sump; int error, i; int32_t *lp; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); /* * Step 1: invalidate all cached meta-data. */ devvp = VFSTOEXT2(mp)->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); if (vinvalbuf(devvp, 0, 0, 0) != 0) panic("ext2_reload: dirty1"); VOP_UNLOCK(devvp, 0); /* * Step 2: re-read superblock from disk. * constants have been adjusted for ext2 */ if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0) return (error); es = (struct ext2fs *)bp->b_data; if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { brelse(bp); return (EIO); /* XXX needs translation */ } fs = VFSTOEXT2(mp)->um_e2fs; bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); if((error = compute_sb_data(devvp, es, fs)) != 0) { brelse(bp); return (error); } #ifdef UNKLAR if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; #endif brelse(bp); /* * Step 3: invalidate all cluster summary information. */ if (fs->e2fs_contigsumsize > 0) { lp = fs->e2fs_maxcluster; sump = fs->e2fs_clustersum; for (i = 0; i < fs->e2fs_gcount; i++, sump++) { *lp++ = fs->e2fs_contigsumsize; sump->cs_init = 0; bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1); } } loop: MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { /* * Step 4: invalidate all cached file data. */ if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); goto loop; } if (vinvalbuf(vp, 0, 0, 0)) panic("ext2_reload: dirty2"); /* * Step 5: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, NOCRED, &bp); if (error) { VOP_UNLOCK(vp, 0); vrele(vp); MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); return (error); } ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip); brelse(bp); VOP_UNLOCK(vp, 0); vrele(vp); } return (0); }
/* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. The IN_MODIFIED * flag is used to specify that the inode needs to be updated but that the * times have already been set. The access and modified times are taken from * the second and third parameters; the inode change time is always taken * from the current time. If waitfor is set, then wait for the disk write * of the inode to complete. */ int ffs_update(struct inode *ip, struct timespec *atime, struct timespec *mtime, int waitfor) { struct vnode *vp; struct fs *fs; struct buf *bp; int error; struct timespec ts; vp = ITOV(ip); if (vp->v_mount->mnt_flag & MNT_RDONLY) { ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); return (0); } if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && waitfor != MNT_WAIT) return (0); getnanotime(&ts); if (ip->i_flag & IN_ACCESS) { DIP_ASSIGN(ip, atime, atime ? atime->tv_sec : ts.tv_sec); DIP_ASSIGN(ip, atimensec, atime ? atime->tv_nsec : ts.tv_nsec); } if (ip->i_flag & IN_UPDATE) { DIP_ASSIGN(ip, mtime, mtime ? mtime->tv_sec : ts.tv_sec); DIP_ASSIGN(ip, mtimensec, mtime ? mtime->tv_nsec : ts.tv_nsec); ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) { DIP_ASSIGN(ip, ctime, ts.tv_sec); DIP_ASSIGN(ip, ctimensec, ts.tv_nsec); } ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); fs = ip->i_fs; /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_inodefmt < FS_44INODEFMT) { ip->i_din1->di_ouid = ip->i_ffs1_uid; ip->i_din1->di_ogid = ip->i_ffs1_gid; } error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->fs_bsize, &bp); if (error) { brelse(bp); return (error); } if (DOINGSOFTDEP(vp)) softdep_update_inodeblock(ip, bp, waitfor); else if (ip->i_effnlink != DIP(ip, nlink)) panic("ffs_update: bad link cnt"); #ifdef FFS2 if (ip->i_ump->um_fstype == UM_UFS2) *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; else #endif *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; if (waitfor && !DOINGASYNC(vp)) { return (bwrite(bp)); } else { bdwrite(bp); return (0); } }
/* * Look up a FFS dinode number to find its incore vnode, otherwise read it * in from disk. If it is in core, wait for the lock bit to clear, then * return the inode locked. Detection and handling of mount points must be * done by the calling routine. */ int ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct fs *fs; struct inode *ip; struct ufs1_dinode *dp1; #ifdef FFS2 struct ufs2_dinode *dp2; #endif struct ufsmount *ump; struct buf *bp; struct vnode *vp; dev_t dev; int error; ump = VFSTOUFS(mp); dev = ump->um_dev; retry: if ((*vpp = ufs_ihashget(dev, ino)) != NULL) return (0); /* Allocate a new vnode/inode. */ if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) { *vpp = NULL; return (error); } #ifdef VFSDEBUG vp->v_flag |= VLOCKSWORK; #endif /* XXX - we use the same pool for ffs and mfs */ ip = pool_get(&ffs_ino_pool, PR_WAITOK); bzero((caddr_t)ip, sizeof(struct inode)); lockinit(&ip->i_lock, PINOD, "inode", 0, 0); ip->i_ump = ump; VREF(ip->i_devvp); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; ip->i_dev = dev; ip->i_number = ino; ip->i_vtbl = &ffs_vtbl; /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the * disk portion of this inode to be read. */ error = ufs_ihashins(ip); if (error) { /* * VOP_INACTIVE will treat this as a stale file * and recycle it quickly */ vrele(vp); if (error == EEXIST) goto retry; return (error); } /* Read in the disk contents for the inode, copy into the inode. */ error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), (int)fs->fs_bsize, NOCRED, &bp); if (error) { /* * The inode does not contain anything useful, so it would * be misleading to leave it on its hash chain. With mode * still zero, it will be unlinked and returned to the free * list by vput(). */ vput(vp); brelse(bp); *vpp = NULL; return (error); } #ifdef FFS2 if (ip->i_ump->um_fstype == UM_UFS2) { ip->i_din2 = pool_get(&ffs_dinode2_pool, PR_WAITOK); dp2 = (struct ufs2_dinode *) bp->b_data + ino_to_fsbo(fs, ino); *ip->i_din2 = *dp2; } else #endif { ip->i_din1 = pool_get(&ffs_dinode1_pool, PR_WAITOK); dp1 = (struct ufs1_dinode *) bp->b_data + ino_to_fsbo(fs, ino); *ip->i_din1 = *dp1; } brelse(bp); if (DOINGSOFTDEP(vp)) softdep_load_inodeblock(ip); else ip->i_effnlink = DIP(ip, nlink); /* * Initialize the vnode from the inode, check for aliases. * Note that the underlying vnode may have changed. */ error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp); if (error) { vput(vp); *vpp = NULL; return (error); } /* * Set up a generation number for this inode if it does not * already have one. This should only happen on old filesystems. */ if (DIP(ip, gen) == 0) { DIP_ASSIGN(ip, gen, arc4random() & INT_MAX); if (DIP(ip, gen) == 0 || DIP(ip, gen) == -1) DIP_ASSIGN(ip, gen, 1); /* Shouldn't happen */ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) ip->i_flag |= IN_MODIFIED; } /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. */ if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_inodefmt < FS_44INODEFMT) { ip->i_ffs1_uid = ip->i_din1->di_ouid; ip->i_ffs1_gid = ip->i_din1->di_ogid; } *vpp = vp; return (0); }