diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index 96849a791714..34d7674a85b7 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -134,6 +134,10 @@ mkfs(struct partition *pp, char *fsys) utime = 1000000000; else time(&utime); + if ((sblock.fs_si = malloc(sizeof(struct fs_summary_info))) == NULL) { + printf("Superblock summary info allocation failed.\n"); + exit(18); + } sblock.fs_old_flags = FS_FLAGS_UPDATED; sblock.fs_flags = 0; if (Uflag) @@ -548,6 +552,10 @@ mkfs(struct partition *pp, char *fsys) } } } + /* + * Reference the summary information so it will also be written. + */ + sblock.fs_csp = fscs; if (!Nflag && sbput(disk.d_fd, &disk.d_fs, 0) != 0) err(1, "sbput: %s", disk.d_error); if (Xflag == 1) { @@ -611,10 +619,6 @@ mkfs(struct partition *pp, char *fsys) printf("** Exiting on Xflag 3\n"); exit(0); } - /* - * Reference the summary information so it will also be written. - */ - sblock.fs_csp = fscs; if (sbput(disk.d_fd, &disk.d_fs, 0) != 0) err(1, "sbput: %s", disk.d_error); /* diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c index 317d6e9fdb1c..02d13aa29722 100644 --- a/stand/libsa/ufs.c +++ b/stand/libsa/ufs.c @@ -678,7 +678,11 @@ ufs_open(upath, f) if (rc) { if (fp->f_buf) free(fp->f_buf); - free(fp->f_fs); + if (fp->f_fs != NULL) { + free(fp->f_fs->fs_csp); + free(fp->f_fs->fs_si); + free(fp->f_fs); + } free(fp); } return (rc); @@ -723,7 +727,11 @@ ufs_close(f) } if (fp->f_buf) free(fp->f_buf); - free(fp->f_fs); + if (fp->f_fs != NULL) { + free(fp->f_fs->fs_csp); + free(fp->f_fs->fs_si); + free(fp->f_fs); + } free(fp); return (0); } diff --git a/sys/geom/journal/g_journal_ufs.c b/sys/geom/journal/g_journal_ufs.c index dbb416601677..139df189f20b 100644 --- a/sys/geom/journal/g_journal_ufs.c +++ b/sys/geom/journal/g_journal_ufs.c @@ -68,6 +68,7 @@ g_journal_ufs_clean(struct mount *mp) static void g_journal_ufs_dirty(struct g_consumer *cp) { + struct fs_summary_info *fs_si; struct fs *fs; int error; @@ -83,8 +84,12 @@ g_journal_ufs_dirty(struct g_consumer *cp) GJ_DEBUG(0, "clean=%d flags=0x%x", fs->fs_clean, fs->fs_flags); fs->fs_clean = 0; fs->fs_flags |= FS_NEEDSFSCK | FS_UNCLEAN; + fs_si = fs->fs_si; + fs->fs_si = NULL; error = ffs_sbput(cp, fs, fs->fs_sblockloc, g_use_g_write_data); + fs->fs_si = fs_si; g_free(fs->fs_csp); + g_free(fs->fs_si); g_free(fs); if (error != 0) { GJ_DEBUG(0, "Cannot mark file system %s as dirty " diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c index 8b90b70a40a9..1d2614b52747 100644 --- a/sys/geom/label/g_label_ufs.c +++ b/sys/geom/label/g_label_ufs.c @@ -122,6 +122,7 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh } out: g_free(fs->fs_csp); + g_free(fs->fs_si); g_free(fs); } diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 57903144d33f..fd6d7c4d8018 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -480,6 +480,8 @@ ffs_snapshot(mp, snapfile) */ copy_fs = malloc((u_long)fs->fs_bsize, M_UFSMNT, M_WAITOK); bcopy(fs, copy_fs, fs->fs_sbsize); + copy_fs->fs_si = malloc(sizeof(struct fs_summary_info), M_UFSMNT, + M_ZERO | M_WAITOK); if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) copy_fs->fs_clean = 1; size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE; @@ -501,6 +503,7 @@ ffs_snapshot(mp, snapfile) len, KERNCRED, &bp)) != 0) { brelse(bp); free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs->fs_si, M_UFSMNT); free(copy_fs, M_UFSMNT); copy_fs = NULL; goto out1; @@ -611,6 +614,7 @@ ffs_snapshot(mp, snapfile) vdrop(xvp); if (error) { free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs->fs_si, M_UFSMNT); free(copy_fs, M_UFSMNT); copy_fs = NULL; MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); @@ -624,6 +628,7 @@ ffs_snapshot(mp, snapfile) error = softdep_journal_lookup(mp, &xvp); if (error) { free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs->fs_si, M_UFSMNT); free(copy_fs, M_UFSMNT); copy_fs = NULL; goto out1; @@ -842,6 +847,7 @@ ffs_snapshot(mp, snapfile) } done: free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs->fs_si, M_UFSMNT); free(copy_fs, M_UFSMNT); copy_fs = NULL; out: diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 93bbdba72e7c..53980f9bc762 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -158,6 +158,7 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock, int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) { struct fs *fs; + struct fs_summary_info *fs_si; int i, error, size, blks; uint8_t *space; int32_t *lp; @@ -201,7 +202,14 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock, size += fs->fs_ncg * sizeof(int32_t); size += fs->fs_ncg * sizeof(u_int8_t); /* When running in libufs or libsa, UFS_MALLOC may fail */ + if ((fs_si = UFS_MALLOC(sizeof(*fs_si), filltype, M_WAITOK)) == NULL) { + UFS_FREE(fs, filltype); + return (ENOSPC); + } + bzero(fs_si, sizeof(*fs_si)); + fs->fs_si = fs_si; if ((space = UFS_MALLOC(size, filltype, M_WAITOK)) == NULL) { + UFS_FREE(fs->fs_si, filltype); UFS_FREE(fs, filltype); return (ENOSPC); } @@ -217,6 +225,7 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock, if (buf != NULL) UFS_FREE(buf, filltype); UFS_FREE(fs->fs_csp, filltype); + UFS_FREE(fs->fs_si, filltype); UFS_FREE(fs, filltype); return (error); } @@ -299,7 +308,7 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk, /* Have to set for old filesystems that predate this field */ fs->fs_sblockactualloc = sblockloc; /* Not yet any summary information */ - fs->fs_csp = NULL; + fs->fs_si = NULL; return (0); } return (ENOENT); @@ -325,7 +334,7 @@ ffs_sbput(void *devfd, struct fs *fs, off_t loc, * If there is summary information, write it first, so if there * is an error, the superblock will not be marked as clean. */ - if (fs->fs_csp != NULL) { + if (fs->fs_si != NULL && fs->fs_csp != NULL) { blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (uint8_t *)fs->fs_csp; for (i = 0; i < blks; i += fs->fs_frag) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 4c4ac8401fa4..c26f03bcc4bb 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -885,14 +885,11 @@ ffs_reload(struct mount *mp, struct thread *td, int flags) return (EIO); /* XXX needs translation */ } /* - * Copy pointer fields back into superblock before copying in XXX - * new superblock. These should really be in the ufsmount. XXX - * Note that important parameters (eg fs_ncg) are unchanged. + * Preserve the summary information, read-only status, and + * superblock location by copying these fields into our new + * superblock before using it to update the existing superblock. */ - newfs->fs_csp = fs->fs_csp; - newfs->fs_maxcluster = fs->fs_maxcluster; - newfs->fs_contigdirs = fs->fs_contigdirs; - newfs->fs_active = fs->fs_active; + newfs->fs_si = fs->fs_si; newfs->fs_ronly = fs->fs_ronly; sblockloc = fs->fs_sblockloc; bcopy(newfs, fs, (u_int)fs->fs_sbsize); @@ -1309,6 +1306,7 @@ ffs_mountfs(odevvp, mp, td) out: if (fs != NULL) { free(fs->fs_csp, M_UFSMNT); + free(fs->fs_si, M_UFSMNT); free(fs, M_UFSMNT); } if (cp != NULL) { @@ -1546,6 +1544,7 @@ ffs_unmount(mp, mntflags) mp->mnt_gjprovider = NULL; } free(fs->fs_csp, M_UFSMNT); + free(fs->fs_si, M_UFSMNT); free(fs, M_UFSMNT); if (ump->um_fsfail_task != NULL) free(ump->um_fsfail_task, M_UFSMNT); @@ -2294,10 +2293,7 @@ ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size) bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); fs = (struct fs *)bp->b_data; ffs_oldfscompat_write(fs, ump); - /* - * Because we may have made changes to the superblock, we need to - * recompute its check-hash. - */ + /* Recalculate the superblock hash */ fs->fs_ckhash = ffs_calc_sbhash(fs); if (devfdp->suspended) bp->b_flags |= B_VALIDSUSPWRT; diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index a583b6e2150f..17f42826afc5 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -132,16 +132,18 @@ * of pointers to blocks of struct csum; now there are just a few * pointers and the remaining space is padded with fs_ocsp[]. * - * NOCSPTRS determines the size of this padding. One pointer (fs_csp) - * is taken away to point to a contiguous array of struct csum for - * all cylinder groups; a second (fs_maxcluster) points to an array - * of cluster sizes that is computed as cylinder groups are inspected, - * and the third points to an array that tracks the creation of new - * directories. A fourth pointer, fs_active, is used when creating - * snapshots; it points to a bitmap of cylinder groups for which the - * free-block bitmap has changed since the snapshot operation began. + * NOCSPTRS determines the size of this padding. Historically this + * space was used to store pointers to structures that summaried + * filesystem usage and layout information. However, these pointers + * left various kernel pointers in the superblock which made otherwise + * identical superblocks appear to have differences. So, all the + * pointers in the superblock were moved to a fs_summary_info structure + * reducing the superblock to having only a single pointer to this + * structure. When writing the superblock to disk, this pointer is + * temporarily NULL'ed out so that the kernel pointer will not appear + * in the on-disk copy of the superblock. */ -#define NOCSPTRS ((128 / sizeof(void *)) - 4) +#define NOCSPTRS ((128 / sizeof(void *)) - 1) /* * A summary of contiguous blocks of various sizes is maintained @@ -269,6 +271,32 @@ struct csum_total { int64_t cs_spare[3]; /* future expansion */ }; +/* + * Pointers to super block summary information. Placed in a separate + * structure so there is just one pointer in the superblock. + * + * The pointers in this structure are used as follows: + * fs_contigdirs references an array that tracks the creation of new + * directories + * fs_csp references a contiguous array of struct csum for + * all cylinder groups + * fs_maxcluster references an array of cluster sizes that is computed + * as cylinder groups are inspected + * fs_active is used when creating snapshots; it points to a bitmap + * of cylinder groups for which the free-block bitmap has changed + * since the snapshot operation began. + */ +struct fs_summary_info { + uint8_t *si_contigdirs; /* (u) # of contig. allocated dirs */ + struct csum *si_csp; /* (u) cg summary info buffer */ + int32_t *si_maxcluster; /* (u) max cluster in each cyl group */ + u_int *si_active; /* (u) used by snapshots to track fs */ +}; +#define fs_contigdirs fs_si->si_contigdirs +#define fs_csp fs_si->si_csp +#define fs_maxcluster fs_si->si_maxcluster +#define fs_active fs_si->si_active + /* * Super block for an FFS filesystem. */ @@ -340,10 +368,7 @@ struct fs { /* these fields retain the current block allocation info */ int32_t fs_cgrotor; /* last cg searched */ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ - u_int8_t *fs_contigdirs; /* (u) # of contig. allocated dirs */ - struct csum *fs_csp; /* (u) cg summary info buffer */ - int32_t *fs_maxcluster; /* (u) max cluster in each cyl group */ - u_int *fs_active; /* (u) used by snapshots to track fs */ + struct fs_summary_info *fs_si;/* In-core pointer to summary info */ int32_t fs_old_cpc; /* cyl per cycle in postbl */ int32_t fs_maxbsize; /* maximum blocking factor permitted */ int64_t fs_unrefs; /* number of unreferenced inodes */ diff --git a/usr.sbin/fstyp/ufs.c b/usr.sbin/fstyp/ufs.c index 4002fc89c9ee..e4de1283e769 100644 --- a/usr.sbin/fstyp/ufs.c +++ b/usr.sbin/fstyp/ufs.c @@ -53,6 +53,9 @@ fstyp_ufs(FILE *fp, char *label, size_t labelsize) switch (sbget(fileno(fp), &fs, STDSB)) { case 0: strlcpy(label, fs->fs_volname, labelsize); + free(fs->fs_csp); + free(fs->fs_si); + free(fs); return (0); case ENOENT: /* Cannot find file system superblock */ diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c index 18b1e398ec09..fa1ee1c65fe7 100644 --- a/usr.sbin/quot/quot.c +++ b/usr.sbin/quot/quot.c @@ -567,6 +567,9 @@ quot(char *name, char *mp) printf(" (%s)",mp); putchar('\n'); (*func)(fd, fs, name); + free(fs->fs_csp); + free(fs->fs_si); + free(fs); close(fd); }