Skip to content

Commit

Permalink
The new fsck recovery information to enable it to find backup
Browse files Browse the repository at this point in the history
superblocks created in revision 322297 only works on disks
with sector sizes up to 4K. This update allows the recovery
information to be created by newfs and used by fsck on disks
with sector sizes up to 64K. Note that FFS currently limits
filesystem to be mounted from disks with up to 8K sectors.
Expanding this limitation will be the subject of another
commit.

Reported by: Peter Holm
Reviewed with: kib
  • Loading branch information
mckusick authored and mckusick committed Sep 4, 2017
1 parent 525799a commit 85aaecf
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 40 deletions.
90 changes: 65 additions & 25 deletions sbin/fsck_ffs/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/disk.h>
#include <sys/stat.h>
#define FSTYPENAMES
#include <sys/disklabel.h>
Expand Down Expand Up @@ -465,7 +466,9 @@ sblock_init(void)
static int
calcsb(char *dev, int devfd, struct fs *fs)
{
struct fsrecovery fsr;
struct fsrecovery *fsr;
char *fsrbuf;
u_int secsize;

/*
* We need fragments-per-group and the partition-size.
Expand All @@ -475,32 +478,62 @@ calcsb(char *dev, int devfd, struct fs *fs)
* overwritten by a boot block, we fail. But usually they are
* there and we can use them.
*/
if (blread(devfd, (char *)&fsr,
(SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)) ||
fsr.fsr_magic != FS_UFS2_MAGIC)
if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1)
return (0);
fsrbuf = Malloc(secsize);
if (fsrbuf == NULL)
errx(EEXIT, "calcsb: cannot allocate recovery buffer");
if (blread(devfd, fsrbuf,
(SBLOCK_UFS2 - secsize) / dev_bsize, secsize) != 0)
return (0);
fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr];
if (fsr->fsr_magic != FS_UFS2_MAGIC)
return (0);
memset(fs, 0, sizeof(struct fs));
fs->fs_fpg = fsr.fsr_fpg;
fs->fs_fsbtodb = fsr.fsr_fsbtodb;
fs->fs_sblkno = fsr.fsr_sblkno;
fs->fs_magic = fsr.fsr_magic;
fs->fs_ncg = fsr.fsr_ncg;
fs->fs_fpg = fsr->fsr_fpg;
fs->fs_fsbtodb = fsr->fsr_fsbtodb;
fs->fs_sblkno = fsr->fsr_sblkno;
fs->fs_magic = fsr->fsr_magic;
fs->fs_ncg = fsr->fsr_ncg;
free(fsrbuf);
return (1);
}

/*
* Check to see if recovery information exists.
* Return 1 if it exists or cannot be created.
* Return 0 if it does not exist and can be created.
*/
static int
chkrecovery(int devfd)
{
struct fsrecovery fsr;
struct fsrecovery *fsr;
char *fsrbuf;
u_int secsize;

if (blread(devfd, (char *)&fsr,
(SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)) ||
fsr.fsr_magic != FS_UFS2_MAGIC)
return (0);
return (1);
/*
* Could not determine if backup material exists, so do not
* offer to create it.
*/
if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 ||
(fsrbuf = Malloc(secsize)) == NULL ||
blread(devfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize,
secsize) != 0)
return (1);
/*
* Recovery material has already been created, so do not
* need to create it again.
*/
fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr];
if (fsr->fsr_magic == FS_UFS2_MAGIC) {
free(fsrbuf);
return (1);
}
/*
* Recovery material has not been created and can be if desired.
*/
free(fsrbuf);
return (0);
}

/*
Expand All @@ -511,17 +544,24 @@ chkrecovery(int devfd)
static void
saverecovery(int readfd, int writefd)
{
struct fsrecovery fsr;
struct fsrecovery *fsr;
char *fsrbuf;
u_int secsize;

if (sblock.fs_magic != FS_UFS2_MAGIC ||
blread(readfd, (char *)&fsr,
(SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize, sizeof(fsr)))
ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 ||
(fsrbuf = Malloc(secsize)) == NULL ||
blread(readfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize,
secsize) != 0) {
printf("RECOVERY DATA COULD NOT BE CREATED\n");
return;
fsr.fsr_magic = sblock.fs_magic;
fsr.fsr_fpg = sblock.fs_fpg;
fsr.fsr_fsbtodb = sblock.fs_fsbtodb;
fsr.fsr_sblkno = sblock.fs_sblkno;
fsr.fsr_ncg = sblock.fs_ncg;
blwrite(writefd, (char *)&fsr, (SBLOCK_UFS2 - sizeof(fsr)) / dev_bsize,
sizeof(fsr));
}
fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr];
fsr->fsr_magic = sblock.fs_magic;
fsr->fsr_fpg = sblock.fs_fpg;
fsr->fsr_fsbtodb = sblock.fs_fsbtodb;
fsr->fsr_sblkno = sblock.fs_sblkno;
fsr->fsr_ncg = sblock.fs_ncg;
blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - secsize) / secsize, secsize);
free(fsrbuf);
}
31 changes: 18 additions & 13 deletions sbin/newfs/mkfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ mkfs(struct partition *pp, char *fsys)
ino_t maxinum;
int minfragsperinode; /* minimum ratio of frags to inodes */
char tmpbuf[100]; /* XXX this will break in about 2,500 years */
struct fsrecovery fsr;
struct fsrecovery *fsr;
char *fsrbuf;
union {
struct fs fdummy;
char cdummy[SBLOCKSIZE];
Expand Down Expand Up @@ -442,6 +443,8 @@ mkfs(struct partition *pp, char *fsys)
sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
if (sblock.fs_sbsize > SBLOCKSIZE)
sblock.fs_sbsize = SBLOCKSIZE;
if (sblock.fs_sbsize < realsectorsize)
sblock.fs_sbsize = realsectorsize;
sblock.fs_minfree = minfree;
if (metaspace > 0 && metaspace < sblock.fs_fpg / 2)
sblock.fs_metaspace = blknum(&sblock, metaspace);
Expand Down Expand Up @@ -514,7 +517,7 @@ mkfs(struct partition *pp, char *fsys)
/*
* Wipe out old UFS1 superblock(s) if necessary.
*/
if (!Nflag && Oflag != 1) {
if (!Nflag && Oflag != 1 && realsectorsize <= SBLOCK_UFS1) {
i = bread(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE);
if (i == -1)
err(1, "can't read old UFS1 superblock: %s", disk.d_error);
Expand Down Expand Up @@ -623,18 +626,20 @@ mkfs(struct partition *pp, char *fsys)
* The recovery information only works for UFS2 filesystems.
*/
if (sblock.fs_magic == FS_UFS2_MAGIC) {
i = bread(&disk,
part_ofs + (SBLOCK_UFS2 - sizeof(fsr)) / disk.d_bsize,
(char *)&fsr, sizeof(fsr));
if (i == -1)
if ((fsrbuf = malloc(realsectorsize)) == NULL || bread(&disk,
part_ofs + (SBLOCK_UFS2 - realsectorsize) / disk.d_bsize,
fsrbuf, realsectorsize) == -1)
err(1, "can't read recovery area: %s", disk.d_error);
fsr.fsr_magic = sblock.fs_magic;
fsr.fsr_fpg = sblock.fs_fpg;
fsr.fsr_fsbtodb = sblock.fs_fsbtodb;
fsr.fsr_sblkno = sblock.fs_sblkno;
fsr.fsr_ncg = sblock.fs_ncg;
wtfs((SBLOCK_UFS2 - sizeof(fsr)) / disk.d_bsize, sizeof(fsr),
(char *)&fsr);
fsr =
(struct fsrecovery *)&fsrbuf[realsectorsize - sizeof *fsr];
fsr->fsr_magic = sblock.fs_magic;
fsr->fsr_fpg = sblock.fs_fpg;
fsr->fsr_fsbtodb = sblock.fs_fsbtodb;
fsr->fsr_sblkno = sblock.fs_sblkno;
fsr->fsr_ncg = sblock.fs_ncg;
wtfs((SBLOCK_UFS2 - realsectorsize) / disk.d_bsize,
realsectorsize, fsrbuf);
free(fsrbuf);
}
/*
* Update information about this partition in pack
Expand Down
2 changes: 0 additions & 2 deletions sys/ufs/ffs/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,7 @@ struct fsck_cmd {
* A recovery structure placed at the end of the boot block area by newfs
* that can be used by fsck to search for alternate superblocks.
*/
#define RESID (4096 - 20) /* disk sector size minus recovery area size */
struct fsrecovery {
char block[RESID]; /* unused part of sector */
int32_t fsr_magic; /* magic number */
int32_t fsr_fsbtodb; /* fsbtodb and dbtofsb shift constant */
int32_t fsr_sblkno; /* offset of super-block in filesys */
Expand Down

0 comments on commit 85aaecf

Please sign in to comment.