From 34816cb9aeca7b0ad3289c2de04cad0cd1b111ed Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Fri, 19 Jun 2020 01:02:53 +0000 Subject: [PATCH] Move the pointers stored in the superblock into a separate fs_summary_info structure. This change was originally done by the CheriBSD project as they need larger pointers that do not fit in the existing superblock. This cleanup of the superblock eases the task of the commit that immediately follows this one. Suggested by: brooks Reviewed by: kib PR: 246983 Sponsored by: Netflix --- sbin/newfs/mkfs.c | 12 +++++--- stand/libsa/ufs.c | 12 ++++++-- sys/geom/journal/g_journal_ufs.c | 5 ++++ sys/geom/label/g_label_ufs.c | 1 + sys/ufs/ffs/ffs_snapshot.c | 6 ++++ sys/ufs/ffs/ffs_subr.c | 13 ++++++-- sys/ufs/ffs/ffs_vfsops.c | 18 +++++------ sys/ufs/ffs/fs.h | 51 ++++++++++++++++++++++++-------- usr.sbin/fstyp/ufs.c | 3 ++ usr.sbin/quot/quot.c | 3 ++ 10 files changed, 92 insertions(+), 32 deletions(-) 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); }