+/*
+ * 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) re-read summary information from disk.
+ * 4) invalidate all inactive vnodes.
+ * 5) invalidate all cached file data.
+ * 6) re-read inode data for all active vnodes.
+ */
+ffs_reload(mountp, cred, p)
+ register struct mount *mountp;
+ struct ucred *cred;
+ struct proc *p;
+{
+ register struct vnode *vp, *nvp, *devvp;
+ struct inode *ip;
+ struct dinode *dp;
+ struct csum *space;
+ struct buf *bp;
+ struct fs *fs;
+ int i, blks, size, error;
+
+ if ((mountp->mnt_flag & MNT_RDONLY) == 0)
+ return (EINVAL);
+ /*
+ * Step 1: invalidate all cached meta-data.
+ */
+ devvp = VFSTOUFS(mountp)->um_devvp;
+ if (vinvalbuf(devvp, 0, cred, p, 0, 0))
+ panic("ffs_reload: dirty1");
+ /*
+ * Step 2: re-read superblock from disk.
+ */
+ if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
+ return (error);
+ fs = bp->b_un.b_fs;
+ if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
+ fs->fs_bsize < sizeof(struct fs)) {
+ brelse(bp);
+ return (EIO); /* XXX needs translation */
+ }
+ fs = VFSTOUFS(mountp)->um_fs;
+ bcopy((caddr_t)&fs->fs_csp[0], (caddr_t)&bp->b_un.b_fs->fs_csp[0],
+ sizeof(fs->fs_csp));
+ bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)fs, (u_int)fs->fs_sbsize);
+ if (fs->fs_sbsize < SBSIZE)
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ ffs_oldfscompat(fs);
+ /*
+ * Step 3: re-read summary information from disk.
+ */
+ blks = howmany(fs->fs_cssize, fs->fs_fsize);
+ space = fs->fs_csp[0];
+ for (i = 0; i < blks; i += fs->fs_frag) {
+ size = fs->fs_bsize;
+ if (i + fs->fs_frag > blks)
+ size = (blks - i) * fs->fs_fsize;
+ if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
+ NOCRED, &bp))
+ return (error);
+ bcopy((caddr_t)bp->b_un.b_addr, fs->fs_csp[fragstoblks(fs, i)],
+ (u_int)size);
+ brelse(bp);
+ }
+loop:
+ for (vp = mountp->mnt_mounth; vp; vp = nvp) {
+ nvp = vp->v_mountf;
+ /*
+ * Step 4: invalidate all inactive vnodes.
+ */
+ if (vp->v_usecount == 0) {
+ vgone(vp);
+ continue;
+ }
+ /*
+ * Step 5: invalidate all cached file data.
+ */
+ if (vget(vp))
+ goto loop;
+ if (vinvalbuf(vp, 0, cred, p, 0, 0))
+ panic("ffs_reload: dirty2");
+ /*
+ * Step 6: re-read inode data for all active vnodes.
+ */
+ ip = VTOI(vp);
+ if (error = bread(devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+ (int)fs->fs_bsize, NOCRED, &bp)) {
+ vput(vp);
+ return (error);
+ }
+ dp = bp->b_un.b_dino;
+ dp += itoo(fs, ip->i_number);
+ ip->i_din = *dp;
+ brelse(bp);
+ vput(vp);
+ if (vp->v_mount != mountp)
+ goto loop;
+ }
+ return (0);
+}
+