diff --git a/lib/libufs/Makefile b/lib/libufs/Makefile index d24526e829c1..16487bebc957 100644 --- a/lib/libufs/Makefile +++ b/lib/libufs/Makefile @@ -17,6 +17,8 @@ MLINKS+= cgread.3 cgwrite.3 MLINKS+= cgread.3 cgwrite1.3 MLINKS+= cgread.3 cgput.3 MLINKS+= sbread.3 sbwrite.3 +MLINKS+= sbread.3 sbget.3 +MLINKS+= sbread.3 sbput.3 MLINKS+= ufs_disk_close.3 ufs_disk_fillout.3 MLINKS+= ufs_disk_close.3 ufs_disk_fillout_blank.3 MLINKS+= ufs_disk_close.3 ufs_disk_write.3 diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index 400704596148..4598a9999ce2 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -98,6 +98,20 @@ __BEGIN_DECLS * libufs prototypes. */ +/* + * ffs_subr.c + */ +void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); +void ffs_fragacct(struct fs *, int, int32_t [], int); +int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_sbget(void *, struct fs **, off_t, char *, + int (*)(void *, off_t, void **, int)); +int ffs_sbput(void *, struct fs *, off_t, + int (*)(void *, off_t, void *, int)); + /* * block.c */ @@ -129,6 +143,9 @@ int putino(struct uufsd *); */ int sbread(struct uufsd *); int sbwrite(struct uufsd *, int); +/* low level superblock read/write functions */ +int sbget(int, struct fs **, off_t); +int sbput(int, struct fs *, int); /* * type.c @@ -138,16 +155,6 @@ int ufs_disk_fillout(struct uufsd *, const char *); int ufs_disk_fillout_blank(struct uufsd *, const char *); int ufs_disk_write(struct uufsd *); -/* - * ffs_subr.c - */ -void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); -void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); -void ffs_fragacct(struct fs *, int, int32_t [], int); -int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); -int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); -void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); - /* * crc32c.c */ diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c index 06cf97d51581..5242a6db88db 100644 --- a/lib/libufs/sblock.c +++ b/lib/libufs/sblock.c @@ -47,79 +47,48 @@ __FBSDID("$FreeBSD$"); #include -static int superblocks[] = SBLOCKSEARCH; - int sbread(struct uufsd *disk) { - uint8_t block[MAXBSIZE]; struct fs *fs; - int sb, superblock; - int i, size, blks; - uint8_t *space; ERROR(disk, NULL); - fs = &disk->d_fs; - superblock = superblocks[0]; - - for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { - if (bread(disk, superblock, disk->d_sb, SBLOCKSIZE) == -1) { + if ((errno = sbget(disk->d_fd, &fs, -1)) != 0) { + switch (errno) { + case EIO: ERROR(disk, "non-existent or truncated superblock"); - return (-1); - } - if (fs->fs_magic == FS_UFS1_MAGIC) - disk->d_ufs = 1; - if (fs->fs_magic == FS_UFS2_MAGIC && - fs->fs_sblockloc == superblock) - disk->d_ufs = 2; - if (fs->fs_bsize <= MAXBSIZE && - (size_t)fs->fs_bsize >= sizeof(*fs)) { - if (disk->d_ufs) - break; + break; + case ENOENT: + ERROR(disk, "no usable known superblock found"); + break; + case ENOSPC: + ERROR(disk, "failed to allocate space for superblock " + "information"); + break; + case EINVAL: + ERROR(disk, "The previous newfs operation on this " + "volume did not complete.\nYou must complete " + "newfs before using this volume."); + break; + default: + ERROR(disk, "unknown superblock read error"); + errno = EIO; + break; } disk->d_ufs = 0; - } - if (superblock == -1 || disk->d_ufs == 0) { - /* - * Other error cases will result in errno being set, here we - * must set it to indicate no superblock could be found with - * which to associate this disk/filesystem. - */ - ERROR(disk, "no usable known superblock found"); - errno = ENOENT; return (-1); } + memcpy(&disk->d_fs, fs, fs->fs_sbsize); + free(fs); + fs = &disk->d_fs; + if (fs->fs_magic == FS_UFS1_MAGIC) + disk->d_ufs = 1; + if (fs->fs_magic == FS_UFS2_MAGIC) + disk->d_ufs = 2; disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1); - disk->d_sblock = superblock / disk->d_bsize; - /* - * Read in the superblock summary information. - */ - size = fs->fs_cssize; - blks = howmany(size, fs->fs_fsize); - size += fs->fs_ncg * sizeof(int32_t); - space = malloc(size); - if (space == NULL) { - ERROR(disk, "failed to allocate space for summary information"); - return (-1); - } - fs->fs_csp = (struct csum *)space; - 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 (bread(disk, fsbtodb(fs, fs->fs_csaddr + i), block, size) - == -1) { - ERROR(disk, "Failed to read sb summary information"); - free(fs->fs_csp); - return (-1); - } - bcopy(block, space, size); - space += size; - } - fs->fs_maxcluster = (uint32_t *)space; + disk->d_sblock = fs->fs_sblockloc / disk->d_bsize; disk->d_sbcsum = fs->fs_csp; - return (0); } @@ -127,45 +96,107 @@ int sbwrite(struct uufsd *disk, int all) { struct fs *fs; - int blks, size; - uint8_t *space; - unsigned i; ERROR(disk, NULL); fs = &disk->d_fs; - - if (!disk->d_sblock) { - disk->d_sblock = disk->d_fs.fs_sblockloc / disk->d_bsize; - } - - if (bwrite(disk, disk->d_sblock, fs, SBLOCKSIZE) == -1) { - ERROR(disk, "failed to write superblock"); - return (-1); - } - /* - * Write superblock summary information. - */ - blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = (uint8_t *)disk->d_sbcsum; - 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 (bwrite(disk, fsbtodb(fs, fs->fs_csaddr + i), space, size) - == -1) { - ERROR(disk, "Failed to write sb summary information"); - return (-1); + if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) { + switch (errno) { + case EIO: + ERROR(disk, "failed to write superblock"); + break; + default: + ERROR(disk, "unknown superblock write error"); + errno = EIO; + break; } - space += size; - } - if (all) { - for (i = 0; i < fs->fs_ncg; i++) - if (bwrite(disk, fsbtodb(fs, cgsblock(fs, i)), - fs, SBLOCKSIZE) == -1) { - ERROR(disk, "failed to update a superblock"); - return (-1); - } + return (-1); } return (0); } + +/* + * These are the low-level functions that actually read and write + * the superblock and its associated data. The actual work is done by + * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c. + */ +static int use_pread(void *devfd, off_t loc, void **bufp, int size); +static int use_pwrite(void *devfd, off_t loc, void *buf, int size); + +/* + * Read a superblock from the devfd device allocating memory returned + * in fsp. Also read the superblock summary information. + */ +int +sbget(int devfd, struct fs **fsp, off_t sblockloc) +{ + + return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread)); +} + +/* + * A read function for use by user-level programs using libufs. + */ +static int +use_pread(void *devfd, off_t loc, void **bufp, int size) +{ + int fd; + + fd = *(int *)devfd; + if ((*bufp = malloc(size)) == NULL) + return (ENOSPC); + if (pread(fd, *bufp, size, loc) != size) + return (EIO); + return (0); +} + +/* + * Write a superblock to the devfd device from the memory pointed to by fs. + * Also write out the superblock summary information but do not free the + * summary information memory. + * + * Additionally write out numaltwrite of the alternate superblocks. Use + * fs->fs_ncg to write out all of the alternate superblocks. + */ +int +sbput(int devfd, struct fs *fs, int numaltwrite) +{ + struct csum *savedcsp; + off_t savedactualloc; + int i, error; + + if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, + use_pwrite)) != 0) + return (error); + if (numaltwrite == 0) + return (0); + savedactualloc = fs->fs_sblockactualloc; + savedcsp = fs->fs_csp; + fs->fs_csp = NULL; + for (i = 0; i < numaltwrite; i++) { + fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i))); + if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, + use_pwrite)) != 0) { + fs->fs_sblockactualloc = savedactualloc; + fs->fs_csp = savedcsp; + return (-1); + } + } + fs->fs_sblockactualloc = savedactualloc; + fs->fs_csp = savedcsp; + return (0); +} + +/* + * A write function for use by user-level programs using sbput in libufs. + */ +static int +use_pwrite(void *devfd, off_t loc, void *buf, int size) +{ + int fd; + + fd = *(int *)devfd; + if (pwrite(fd, buf, size, loc) != size) + return (EIO); + return (0); +} diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3 index 8b5e8c0d4d6b..42342b2f3271 100644 --- a/lib/libufs/sbread.3 +++ b/lib/libufs/sbread.3 @@ -2,6 +2,8 @@ .\" Date: June 04, 2003 .\" Description: .\" Manual page for libufs functions: +.\" sbget(3) +.\" sbput(3) .\" sbread(3) .\" sbwrite(3) .\" @@ -9,11 +11,11 @@ .\" .\" $FreeBSD$ .\" -.Dd June 4, 2003 +.Dd January 19, 2018 .Dt SBREAD 3 .Os .Sh NAME -.Nm sbread , sbwrite +.Nm sbget , sbput , sbread , sbwrite .Nd read and write superblocks of a UFS file system .Sh LIBRARY .Lb libufs @@ -25,35 +27,95 @@ .In ufs/ffs/fs.h .In libufs.h .Ft int +.Fn sbget "int devfd" "struct fs **fsp" "off_t sblockloc" +.Ft int +.Fn sbput "int devfd" "struct fs *fs" "int numaltwrite" +.Ft int .Fn sbread "struct uufsd *disk" .Ft int .Fn sbwrite "struct uufsd *disk" "int all" .Sh DESCRIPTION The -.Fn sbread +.Fn sbget and -.Fn sbwrite -functions provide superblock reads and writes for +.Fn sbread +functions provide superblock reads for .Xr libufs 3 consumers. The -.Fn sbread +.Fn sbput and .Fn sbwrite -functions operate on the superblock field, +functions provide superblock writes for +.Xr libufs 3 +consumers. +.Pp +The +.Fn sbget +function first allocates a buffer to hold the superblock. +Using the +.Va devfd +file descriptor that references the filesystem disk, +.Fn sbget +reads the superblock located at the byte offset specified by +.Va sblockloc +into the allocated buffer. +If successful, it returns a pointer to the buffer containing the superblock in +.Va fsp . +The +.Fn sbget +function is safe to use in threaded applications. +.Pp +The +.Fn sbput +function writes the superblock specified by +.Va fs +to the location from which it was read on the disk referenced by the +.Va devfd +file descriptor. +Additionally, the +.Fn sbput +function will update the first +.Va numaltwrite +alternate superblock locations. +To update all the alternate superblocks, +specify a +.Va numaltwrite +value of +.Va fs->fs_ncg . +The +.Fn sbput +function is safe to use in threaded applications. +Note that the +.Fn sbput +function needs to be called only if the superblock has been +modified and the on-disk copy needs to be updated. +.Pp +The +.Fn sbread +function reads the standard filesystem superblock into the .Va d_sb , -associated with a given userland UFS disk structure. +structure embedded in the given user-land UFS disk structure. +.Pp +The +.Fn sbwrite +function writes the superblock from the +.Va d_sb , +structure embedded in the given user-land UFS disk structure +to the location from which it was read. Additionally, the .Fn sbwrite -function will write to all superblock locations if the +function will write to all the alternate superblock locations if the .Fa all value is non-zero. .Sh RETURN VALUES -.Rv -std sbread sbwrite +.Rv -std sbget sbput sbread sbwrite .Sh ERRORS -The function +The +.Fn sbget +and .Fn sbread -may fail and set +functions may fail and set .Va errno for any of the errors specified for the library function .Xr bread 3 . @@ -62,9 +124,11 @@ Additionally, it may follow the error methodologies in situations where no usable superblock could be found. .Pp -The function +The +.Fn sbput +and .Fn sbwrite -may fail and set +functions may fail and set .Va errno for any of the errors specified for the library function .Xr bwrite 3 . diff --git a/sbin/clri/Makefile b/sbin/clri/Makefile index 114f56382a18..5f8777f30391 100644 --- a/sbin/clri/Makefile +++ b/sbin/clri/Makefile @@ -4,6 +4,7 @@ PACKAGE=runtime PROG= clri MAN= clri.8 +LIBADD= ufs WARNS?= 2 .include diff --git a/sbin/clri/clri.c b/sbin/clri/clri.c index 7745aa56d18f..3407297ceb6f 100644 --- a/sbin/clri/clri.c +++ b/sbin/clri/clri.c @@ -54,17 +54,14 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include #include #include -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - static void usage(void) { @@ -75,41 +72,35 @@ usage(void) int main(int argc, char *argv[]) { - struct fs *sbp; + struct fs *fs; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; char *ibuf[MAXBSIZE]; long generation, bsize; off_t offset; - int i, fd, inonum; - char *fs, sblock[SBLOCKSIZE]; + int fd, ret, inonum; + char *fsname; void *v = ibuf; if (argc < 3) usage(); - fs = *++argv; - sbp = NULL; + fsname = *++argv; /* get the superblock. */ - if ((fd = open(fs, O_RDWR, 0)) < 0) - err(1, "%s", fs); - for (i = 0; sblock_try[i] != -1; i++) { - if (lseek(fd, (off_t)(sblock_try[i]), SEEK_SET) < 0) - err(1, "%s", fs); - if (read(fd, sblock, sizeof(sblock)) != sizeof(sblock)) - errx(1, "%s: can't read superblock", fs); - sbp = (struct fs *)sblock; - if ((sbp->fs_magic == FS_UFS1_MAGIC || - (sbp->fs_magic == FS_UFS2_MAGIC && - sbp->fs_sblockloc == sblock_try[i])) && - sbp->fs_bsize <= MAXBSIZE && - sbp->fs_bsize >= (int)sizeof(struct fs)) - break; + if ((fd = open(fsname, O_RDWR, 0)) < 0) + err(1, "%s", fsname); + if ((ret = sbget(fd, &fs, -1)) != 0) { + switch (ret) { + case ENOENT: + warn("Cannot find file system superblock"); + return (1); + default: + warn("Unable to read file system superblock"); + return (1); + } } - if (sblock_try[i] == -1) - errx(2, "cannot find file system superblock"); - bsize = sbp->fs_bsize; + bsize = fs->fs_bsize; /* remaining arguments are inode numbers. */ while (*++argv) { @@ -119,20 +110,20 @@ main(int argc, char *argv[]) (void)printf("clearing %d\n", inonum); /* read in the appropriate block. */ - offset = ino_to_fsba(sbp, inonum); /* inode to fs blk */ - offset = fsbtodb(sbp, offset); /* fs blk disk blk */ + offset = ino_to_fsba(fs, inonum); /* inode to fs blk */ + offset = fsbtodb(fs, offset); /* fs blk disk blk */ offset *= DEV_BSIZE; /* disk blk to bytes */ /* seek and read the block */ if (lseek(fd, offset, SEEK_SET) < 0) - err(1, "%s", fs); + err(1, "%s", fsname); if (read(fd, ibuf, bsize) != bsize) - err(1, "%s", fs); + err(1, "%s", fsname); - if (sbp->fs_magic == FS_UFS2_MAGIC) { + if (fs->fs_magic == FS_UFS2_MAGIC) { /* get the inode within the block. */ dp2 = &(((struct ufs2_dinode *)v) - [ino_to_fsbo(sbp, inonum)]); + [ino_to_fsbo(fs, inonum)]); /* clear the inode, and bump the generation count. */ generation = dp2->di_gen + 1; @@ -141,7 +132,7 @@ main(int argc, char *argv[]) } else { /* get the inode within the block. */ dp1 = &(((struct ufs1_dinode *)v) - [ino_to_fsbo(sbp, inonum)]); + [ino_to_fsbo(fs, inonum)]); /* clear the inode, and bump the generation count. */ generation = dp1->di_gen + 1; @@ -151,9 +142,9 @@ main(int argc, char *argv[]) /* backup and write the block */ if (lseek(fd, (off_t)-bsize, SEEK_CUR) < 0) - err(1, "%s", fs); + err(1, "%s", fsname); if (write(fd, ibuf, bsize) != bsize) - err(1, "%s", fs); + err(1, "%s", fsname); (void)fsync(fd); } (void)close(fd); diff --git a/sbin/dump/Makefile b/sbin/dump/Makefile index 7c89570292db..c7feae765ebb 100644 --- a/sbin/dump/Makefile +++ b/sbin/dump/Makefile @@ -19,6 +19,7 @@ LINKS= ${BINDIR}/dump ${BINDIR}/rdump CFLAGS+=-DRDUMP SRCS= itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c cache.c MAN= dump.8 +LIBADD= ufs MLINKS= dump.8 rdump.8 WARNS?= 2 diff --git a/sbin/dump/dump.h b/sbin/dump/dump.h index 7aeb3a90d73f..7119df41b42b 100644 --- a/sbin/dump/dump.h +++ b/sbin/dump/dump.h @@ -86,7 +86,6 @@ time_t tstart_writing; /* when started writing the first tape block */ time_t tend_writing; /* after writing the last tape block */ int passno; /* current dump pass number */ struct fs *sblock; /* the file system super block */ -char sblock_buf[MAXBSIZE]; long dev_bsize; /* block size of underlying disk device */ int dev_bshift; /* log2(dev_bsize) */ int tp_bshift; /* log2(TP_BSIZE) */ diff --git a/sbin/dump/main.c b/sbin/dump/main.c index 167812bce7d5..127b5ca33f97 100644 --- a/sbin/dump/main.c +++ b/sbin/dump/main.c @@ -59,6 +59,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -84,11 +85,6 @@ long dev_bsize = 1; /* recalculated below */ long blocksperfile; /* output blocks per file */ char *host = NULL; /* remote host (if any) */ -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - static char *getmntpt(char *, int *); static long numarg(const char *, long, long); static void obsolete(int *, char **[]); @@ -104,7 +100,7 @@ main(int argc, char *argv[]) struct fstab *dt; char *map, *mntpt; int ch, mode, mntflags; - int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; + int i, ret, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1; int just_estimate = 0; ino_t maxino; char *tmsg; @@ -437,19 +433,16 @@ main(int argc, char *argv[]) msgtail("to %s\n", tape); sync(); - sblock = (struct fs *)sblock_buf; - for (i = 0; sblock_try[i] != -1; i++) { - sblock->fs_fsize = SBLOCKSIZE; /* needed in blkread */ - blkread(sblock_try[i]>>dev_bshift, (char *) sblock, SBLOCKSIZE); - if ((sblock->fs_magic == FS_UFS1_MAGIC || - (sblock->fs_magic == FS_UFS2_MAGIC && - sblock->fs_sblockloc == sblock_try[i])) && - sblock->fs_bsize <= MAXBSIZE && - sblock->fs_bsize >= sizeof(struct fs)) - break; + if ((ret = sbget(diskfd, &sblock, -1)) != 0) { + switch (ret) { + case ENOENT: + warn("Cannot find file system superblock"); + return (1); + default: + warn("Unable to read file system superblock"); + return (1); + } } - if (sblock_try[i] == -1) - quit("Cannot find file system superblock\n"); dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1); dev_bshift = ffs(dev_bsize) - 1; if (dev_bsize != (1 << dev_bshift)) diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 83c559aa16a1..56f01501022a 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -308,7 +308,7 @@ extern u_int real_dev_bsize; /* actual disk sector size, not overridden */ extern char nflag; /* assume a no response */ extern char yflag; /* assume a yes response */ extern int bkgrdflag; /* use a snapshot to run on an active system */ -extern ufs2_daddr_t bflag; /* location of alternate super block */ +extern off_t bflag; /* location of alternate super block */ extern int debug; /* output debugging info */ extern int Eflag; /* delete empty data blocks */ extern int Zflag; /* zero empty data blocks */ diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index 69c92d7f35c9..d4a5f81bbfa7 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -348,7 +348,6 @@ getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) void flush(int fd, struct bufarea *bp) { - int i, j; if (!bp->b_dirty) return; @@ -370,14 +369,8 @@ flush(int fd, struct bufarea *bp) if (bp != &sblk) pfatal("BUFFER %p DOES NOT MATCH SBLK %p\n", bp, &sblk); - blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); - for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, - j++) { - blwrite(fswritefd, (char *)sblock.fs_csp + i, - fsbtodb(&sblock, - sblock.fs_csaddr + j * sblock.fs_frag), - MIN(sblock.fs_cssize - i, sblock.fs_bsize)); - } + if (sbput(fd, (struct fs *)bp->b_un.b_buf, 0) == 0) + fsmodified = 1; break; case BT_CYLGRP: if (cgput(&disk, (struct cg *)bp->b_un.b_buf) == 0) @@ -439,6 +432,8 @@ ckfini(int markclean) if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && sblk.b_bno != sblock.fs_sblockloc / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { + /* Change the write destination to standard superblock */ + sblock.fs_sblockactualloc = sblock.fs_sblockloc; sblk.b_bno = sblock.fs_sblockloc / dev_bsize; sbdirty(); flush(fswritefd, &sblk); diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c index f3522973404e..6ce7dfd032c4 100644 --- a/sbin/fsck_ffs/globs.c +++ b/sbin/fsck_ffs/globs.c @@ -80,7 +80,7 @@ u_int real_dev_bsize; /* actual disk sector size, not overridden */ char nflag; /* assume a no response */ char yflag; /* assume a yes response */ int bkgrdflag; /* use a snapshot to run on an active system */ -ufs2_daddr_t bflag; /* location of alternate super block */ +off_t bflag; /* location of alternate super block */ int debug; /* output debugging info */ int Eflag; /* delete empty data blocks */ int Zflag; /* zero empty data blocks */ diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index c1e8d45e21db..0cc943797c10 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -310,71 +310,49 @@ setup(char *dev) return (0); } -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - -#define BAD_MAGIC_MSG \ -"The previous newfs operation on this volume did not complete.\n" \ -"You must complete newfs before mounting this volume.\n" - /* * Read in the super block and its summary info. */ int readsb(int listerr) { - ufs2_daddr_t super; - int i, bad; + off_t super; + int bad, ret; + struct fs *fs; - if (bflag) { - super = bflag; - readcnt[sblk.b_type]++; - if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE))) - return (0); - if (sblock.fs_magic == FS_BAD_MAGIC) { - fprintf(stderr, BAD_MAGIC_MSG); + super = bflag ? bflag * dev_bsize : -1; + readcnt[sblk.b_type]++; + if ((ret = sbget(fsreadfd, &fs, super)) != 0) { + switch (ret) { + case EINVAL: + fprintf(stderr, "The previous newfs operation " + "on this volume did not complete.\nYou must " + "complete newfs before using this volume.\n"); exit(11); - } - if (sblock.fs_magic != FS_UFS1_MAGIC && - sblock.fs_magic != FS_UFS2_MAGIC) { - fprintf(stderr, "%jd is not a file system superblock\n", - bflag); + case ENOENT: + if (bflag) + fprintf(stderr, "%jd is not a file system " + "superblock\n", super / dev_bsize); + else + fprintf(stderr, "Cannot find file system " + "superblock\n"); return (0); - } - } else { - for (i = 0; sblock_try[i] != -1; i++) { - super = sblock_try[i] / dev_bsize; - readcnt[sblk.b_type]++; - if ((blread(fsreadfd, (char *)&sblock, super, - (long)SBLOCKSIZE))) - return (0); - if (sblock.fs_magic == FS_BAD_MAGIC) { - fprintf(stderr, BAD_MAGIC_MSG); - exit(11); - } - if ((sblock.fs_magic == FS_UFS1_MAGIC || - (sblock.fs_magic == FS_UFS2_MAGIC && - sblock.fs_sblockloc == sblock_try[i])) && - sblock.fs_ncg >= 1 && - sblock.fs_bsize >= MINBSIZE && - sblock.fs_sbsize >= roundup(sizeof(struct fs), dev_bsize)) - break; - } - if (sblock_try[i] == -1) { - fprintf(stderr, "Cannot find file system superblock\n"); + case EIO: + default: + fprintf(stderr, "I/O error reading %jd\n", + super / dev_bsize); return (0); } } + memcpy(&sblock, fs, fs->fs_sbsize); + free(fs); /* * Compute block size that the file system is based on, * according to fsbtodb, and adjust superblock block number * so we can tell if this is an alternate later. */ - super *= dev_bsize; dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); - sblk.b_bno = super / dev_bsize; + sblk.b_bno = sblock.fs_sblockactualloc / dev_bsize; sblk.b_size = SBLOCKSIZE; /* * Compare all fields that should not differ in alternate super block. diff --git a/sbin/fsirand/Makefile b/sbin/fsirand/Makefile index c415b11983f1..1fc54ff44687 100644 --- a/sbin/fsirand/Makefile +++ b/sbin/fsirand/Makefile @@ -4,6 +4,7 @@ PACKAGE=runtime PROG= fsirand MAN= fsirand.8 +LIBADD= ufs WARNS?= 3 .include diff --git a/sbin/fsirand/fsirand.c b/sbin/fsirand/fsirand.c index 6b1b1371e17b..bb0f27a59301 100644 --- a/sbin/fsirand/fsirand.c +++ b/sbin/fsirand/fsirand.c @@ -46,6 +46,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -56,11 +57,6 @@ static const char rcsid[] = static void usage(void) __dead2; int fsirand(char *); -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - static int printonly = 0, force = 0, ignorelabel = 0; int @@ -117,9 +113,8 @@ fsirand(char *device) ssize_t ibufsize; struct fs *sblock; ino_t inumber; - ufs2_daddr_t sblockloc, dblk; - char sbuf[SBLOCKSIZE], sbuftmp[SBLOCKSIZE]; - int i, devfd, n, cg; + ufs2_daddr_t dblk; + int devfd, n, cg, ret; u_int32_t bsize = DEV_BSIZE; if ((devfd = open(device, printonly ? O_RDONLY : O_RDWR)) < 0) { @@ -131,30 +126,15 @@ fsirand(char *device) dp2 = NULL; /* Read in master superblock */ - (void)memset(&sbuf, 0, sizeof(sbuf)); - sblock = (struct fs *)&sbuf; - for (i = 0; sblock_try[i] != -1; i++) { - sblockloc = sblock_try[i]; - if (lseek(devfd, sblockloc, SEEK_SET) == -1) { - warn("can't seek to superblock (%jd) on %s", - (intmax_t)sblockloc, device); + if ((ret = sbget(devfd, &sblock, -1)) != 0) { + switch (ret) { + case ENOENT: + warn("Cannot find file system superblock"); + return (1); + default: + warn("Unable to read file system superblock"); return (1); } - if ((n = read(devfd, (void *)sblock, SBLOCKSIZE))!=SBLOCKSIZE) { - warnx("can't read superblock on %s: %s", device, - (n < SBLOCKSIZE) ? "short read" : strerror(errno)); - return (1); - } - if ((sblock->fs_magic == FS_UFS1_MAGIC || - (sblock->fs_magic == FS_UFS2_MAGIC && - sblock->fs_sblockloc == sblock_try[i])) && - sblock->fs_bsize <= MAXBSIZE && - sblock->fs_bsize >= (ssize_t)sizeof(struct fs)) - break; - } - if (sblock_try[i] == -1) { - fprintf(stderr, "Cannot find file system superblock\n"); - return (1); } if (sblock->fs_magic == FS_UFS1_MAGIC && @@ -167,33 +147,6 @@ fsirand(char *device) return (1); } - /* Make sure backup superblocks are sane. */ - sblock = (struct fs *)&sbuftmp; - for (cg = 0; cg < (int)sblock->fs_ncg; cg++) { - dblk = fsbtodb(sblock, cgsblock(sblock, cg)); - if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { - warn("can't seek to %jd", (intmax_t)dblk * bsize); - return (1); - } else if ((n = write(devfd, (void *)sblock, SBLOCKSIZE)) != SBLOCKSIZE) { - warn("can't read backup superblock %d on %s: %s", - cg + 1, device, (n < SBLOCKSIZE) ? "short write" - : strerror(errno)); - return (1); - } - if (sblock->fs_magic != FS_UFS1_MAGIC && - sblock->fs_magic != FS_UFS2_MAGIC) { - warnx("bad magic number in backup superblock %d on %s", - cg + 1, device); - return (1); - } - if (sblock->fs_sbsize > SBLOCKSIZE) { - warnx("size of backup superblock %d on %s is preposterous", - cg + 1, device); - return (1); - } - } - sblock = (struct fs *)&sbuf; - /* XXX - should really cap buffer at 512kb or so */ if (sblock->fs_magic == FS_UFS1_MAGIC) ibufsize = sizeof(struct ufs1_dinode) * sblock->fs_ipg; @@ -215,38 +168,14 @@ fsirand(char *device) /* Randomize fs_id and write out new sblock and backups */ sblock->fs_id[0] = (u_int32_t)time(NULL); sblock->fs_id[1] = random(); - - if (lseek(devfd, sblockloc, SEEK_SET) == -1) { - warn("can't seek to superblock (%jd) on %s", - (intmax_t)sblockloc, device); - return (1); - } - if ((n = write(devfd, (void *)sblock, SBLOCKSIZE)) != - SBLOCKSIZE) { - warn("can't write superblock on %s: %s", device, - (n < SBLOCKSIZE) ? "short write" : strerror(errno)); + if (sbput(devfd, sblock, sblock->fs_ncg) != 0) { + warn("could not write updated superblock"); return (1); } } /* For each cylinder group, randomize inodes and update backup sblock */ for (cg = 0, inumber = 0; cg < (int)sblock->fs_ncg; cg++) { - /* Update superblock if appropriate */ - if (!printonly) { - dblk = fsbtodb(sblock, cgsblock(sblock, cg)); - if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { - warn("can't seek to %jd", - (intmax_t)dblk * bsize); - return (1); - } else if ((n = write(devfd, (void *)sblock, - SBLOCKSIZE)) != SBLOCKSIZE) { - warn("can't write backup superblock %d on %s: %s", - cg + 1, device, (n < SBLOCKSIZE) ? - "short write" : strerror(errno)); - return (1); - } - } - /* Read in inodes, then print or randomize generation nums */ dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber)); if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index 7670317caae7..61f90de7ea68 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -95,12 +96,6 @@ static union { #define sblock fsun1.fs /* the new superblock */ #define osblock fsun2.fs /* the old superblock */ -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; -static ufs2_daddr_t sblockloc; - static union { struct cg cg; char pad[MAXBSIZE]; @@ -156,11 +151,10 @@ growfs(int fsi, int fso, unsigned int Nflag) fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize); if (fscs == NULL) errx(1, "calloc failed"); - for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) { - rdfs(fsbtodb(&osblock, osblock.fs_csaddr + - numfrags(&osblock, i)), (size_t)MIN(osblock.fs_cssize - i, - osblock.fs_bsize), (void *)(((char *)fscs) + i), fsi); - } + memcpy(fscs, osblock.fs_csp, osblock.fs_cssize); + free(osblock.fs_csp); + osblock.fs_csp = NULL; + sblock.fs_csp = fscs; #ifdef FS_DEBUG { @@ -234,13 +228,41 @@ growfs(int fsi, int fso, unsigned int Nflag) updcsloc(modtime, fsi, fso, Nflag); /* - * Now write the cylinder summary back to disk. + * Clean up the dynamic fields in our superblock. + * + * XXX + * The following fields are currently distributed from the superblock + * to the copies: + * fs_minfree + * fs_rotdelay + * fs_maxcontig + * fs_maxbpg + * fs_minfree, + * fs_optim + * fs_flags + * + * We probably should rather change the summary for the cylinder group + * statistics here to the value of what would be in there, if the file + * system were created initially with the new size. Therefor we still + * need to find an easy way of calculating that. + * Possibly we can try to read the first superblock copy and apply the + * "diffed" stats between the old and new superblock by still copying + * certain parameters onto that. */ - for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) { - wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), - (size_t)MIN(sblock.fs_cssize - i, sblock.fs_bsize), - (void *)(((char *)fscs) + i), fso, Nflag); - } + sblock.fs_time = modtime; + sblock.fs_fmod = 0; + sblock.fs_clean = 1; + sblock.fs_ronly = 0; + sblock.fs_cgrotor = 0; + sblock.fs_state = 0; + memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); + + /* + * Now write the new superblock, its summary information, + * and all the alternates back to disk. + */ + if (!Nflag && sbput(fso, &sblock, sblock.fs_ncg) != 0) + errc(2, EIO, "could not write updated superblock"); DBG_PRINT0("fscs written\n"); #ifdef FS_DEBUG @@ -258,53 +280,9 @@ growfs(int fsi, int fso, unsigned int Nflag) } #endif /* FS_DEBUG */ - /* - * Now write the new superblock back to disk. - */ - sblock.fs_time = modtime; - wtfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); DBG_PRINT0("sblock written\n"); DBG_DUMP_FS(&sblock, "new initial sblock"); - /* - * Clean up the dynamic fields in our superblock copies. - */ - sblock.fs_fmod = 0; - sblock.fs_clean = 1; - sblock.fs_ronly = 0; - sblock.fs_cgrotor = 0; - sblock.fs_state = 0; - memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); - sblock.fs_flags &= FS_DOSOFTDEP; - - /* - * XXX - * The following fields are currently distributed from the superblock - * to the copies: - * fs_minfree - * fs_rotdelay - * fs_maxcontig - * fs_maxbpg - * fs_minfree, - * fs_optim - * fs_flags regarding SOFTPDATES - * - * We probably should rather change the summary for the cylinder group - * statistics here to the value of what would be in there, if the file - * system were created initially with the new size. Therefor we still - * need to find an easy way of calculating that. - * Possibly we can try to read the first superblock copy and apply the - * "diffed" stats between the old and new superblock by still copying - * certain parameters onto that. - */ - - /* - * Write out the duplicate super blocks. - */ - for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { - wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), - (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); - } DBG_PRINT0("sblock copies written\n"); DBG_DUMP_FS(&sblock, "new other sblocks"); @@ -1374,11 +1352,12 @@ int main(int argc, char **argv) { DBG_FUNC("main") + struct fs *fs; const char *device; const struct statfs *statfsp; uint64_t size = 0; off_t mediasize; - int error, i, j, fsi, fso, ch, Nflag = 0, yflag = 0; + int error, j, fsi, fso, ch, ret, Nflag = 0, yflag = 0; char *p, reply[5], oldsizebuf[6], newsizebuf[6]; void *testbuf; @@ -1452,19 +1431,17 @@ main(int argc, char **argv) /* * Read the current superblock, and take a backup. */ - for (i = 0; sblock_try[i] != -1; i++) { - sblockloc = sblock_try[i] / DEV_BSIZE; - rdfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&(osblock), fsi); - if ((osblock.fs_magic == FS_UFS1_MAGIC || - (osblock.fs_magic == FS_UFS2_MAGIC && - osblock.fs_sblockloc == sblock_try[i])) && - osblock.fs_bsize <= MAXBSIZE && - osblock.fs_bsize >= (int32_t) sizeof(struct fs)) - break; + if ((ret = sbget(fsi, &fs, -1)) != 0) { + switch (ret) { + case ENOENT: + errx(1, "superblock not recognized"); + default: + errc(1, ret, "unable to read superblock"); + } } - if (sblock_try[i] == -1) - errx(1, "superblock not recognized"); - memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2)); + memcpy(&osblock, fs, fs->fs_sbsize); + free(fs); + memcpy((void *)&fsun1, (void *)&fsun2, osblock.fs_sbsize); DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */ DBG_DUMP_FS(&sblock, "old sblock"); diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index e6aab91c2fd1..c381134bee6d 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -104,15 +104,6 @@ static void wtfs(ufs2_daddr_t, int, char *); static void cgckhash(struct cg *); static u_int32_t newfs_random(void); -static int -do_sbwrite(struct uufsd *disk) -{ - if (!disk->d_sblock) - disk->d_sblock = disk->d_fs.fs_sblockloc / disk->d_bsize; - return (pwrite(disk->d_fd, &disk->d_fs, SBLOCKSIZE, (off_t)((part_ofs + - disk->d_sblock) * disk->d_bsize))); -} - void mkfs(struct partition *pp, char *fsys) { @@ -277,6 +268,7 @@ mkfs(struct partition *pp, char *fsys) if (Oflag == 1) { sblock.fs_sblockloc = SBLOCK_UFS1; + sblock.fs_sblockactualloc = SBLOCK_UFS1; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) * @@ -296,6 +288,7 @@ mkfs(struct partition *pp, char *fsys) sblock.fs_old_nrpos = 1; } else { sblock.fs_sblockloc = SBLOCK_UFS2; + sblock.fs_sblockactualloc = SBLOCK_UFS2; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) * @@ -544,7 +537,7 @@ mkfs(struct partition *pp, char *fsys) } } if (!Nflag) - do_sbwrite(&disk); + sbput(disk.d_fd, &disk.d_fs, 0); if (Xflag == 1) { printf("** Exiting on Xflag 1\n"); exit(0); @@ -562,24 +555,20 @@ mkfs(struct partition *pp, char *fsys) i = 0; width = charsperline(); /* - * allocate space for superblock, cylinder group map, and + * Allocate space for cylinder group map and * two sets of inode blocks. */ - if (sblock.fs_bsize < SBLOCKSIZE) - iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; - else - iobufsize = 4 * sblock.fs_bsize; + iobufsize = 3 * sblock.fs_bsize; if ((iobuf = calloc(1, iobufsize)) == 0) { printf("Cannot allocate I/O buffer\n"); exit(38); } /* - * Make a copy of the superblock into the buffer that we will be - * writing out in each cylinder group. + * Write out all the cylinder groups and backup superblocks. */ - bcopy((char *)&sblock, iobuf, SBLOCKSIZE); for (cg = 0; cg < sblock.fs_ncg; cg++) { - initcg(cg, utime); + if (!Nflag) + initcg(cg, utime); j = snprintf(tmpbuf, sizeof(tmpbuf), " %jd%s", (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cg)), cg < (sblock.fs_ncg-1) ? "," : ""); @@ -611,24 +600,22 @@ mkfs(struct partition *pp, char *fsys) printf("** Exiting on Xflag 3\n"); exit(0); } - if (!Nflag) { - do_sbwrite(&disk); - /* - * For UFS1 filesystems with a blocksize of 64K, the first - * alternate superblock resides at the location used for - * the default UFS2 superblock. As there is a valid - * superblock at this location, the boot code will use - * it as its first choice. Thus we have to ensure that - * all of its statistcs on usage are correct. - */ - if (Oflag == 1 && sblock.fs_bsize == 65536) - wtfs(fsbtodb(&sblock, cgsblock(&sblock, 0)), - sblock.fs_bsize, (char *)&sblock); - } - for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) - wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), - MIN(sblock.fs_cssize - i, sblock.fs_bsize), - ((char *)fscs) + i); + /* + * Reference the summary information so it will also be written. + */ + sblock.fs_csp = fscs; + sbput(disk.d_fd, &disk.d_fs, 0); + /* + * For UFS1 filesystems with a blocksize of 64K, the first + * alternate superblock resides at the location used for + * the default UFS2 superblock. As there is a valid + * superblock at this location, the boot code will use + * it as its first choice. Thus we have to ensure that + * all of its statistcs on usage are correct. + */ + if (Oflag == 1 && sblock.fs_bsize == 65536) + wtfs(fsbtodb(&sblock, cgsblock(&sblock, 0)), + sblock.fs_bsize, (char *)&sblock); /* * Read the last sector of the boot block, replace the last * 20 bytes with the recovery information, then write it back. @@ -669,6 +656,7 @@ void initcg(int cylno, time_t utime) { long blkno, start; + off_t savedactualloc; uint i, j, d, dlower, dupper; ufs2_daddr_t cbase, dmax; struct ufs1_dinode *dp1; @@ -802,10 +790,15 @@ initcg(int cylno, time_t utime) *cs = acg.cg_cs; cgckhash(&acg); /* - * Write out the duplicate super block, the cylinder group map - * and two blocks worth of inodes in a single write. + * Write out the duplicate super block. Then write the cylinder + * group map and two blocks worth of inodes in a single write. */ - start = MAX(sblock.fs_bsize, SBLOCKSIZE); + savedactualloc = sblock.fs_sblockactualloc; + sblock.fs_sblockactualloc = + dbtob(fsbtodb(&sblock, cgsblock(&sblock, cylno))); + sbput(disk.d_fd, &disk.d_fs, 0); + sblock.fs_sblockactualloc = savedactualloc; + start = 0; bcopy((char *)&acg, &iobuf[start], sblock.fs_cgsize); start += sblock.fs_bsize; dp1 = (struct ufs1_dinode *)(&iobuf[start]); @@ -819,7 +812,7 @@ initcg(int cylno, time_t utime) dp2++; } } - wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf); + wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), iobufsize, iobuf); /* * For the old file system, we have to initialize all the inodes. */ diff --git a/sbin/quotacheck/Makefile b/sbin/quotacheck/Makefile index 6adcf7a5f572..1e02b4486f9d 100644 --- a/sbin/quotacheck/Makefile +++ b/sbin/quotacheck/Makefile @@ -6,7 +6,7 @@ PROG= quotacheck SRCS= quotacheck.c preen.c fsutil.c utilities.c WARNS?= 2 MAN= quotacheck.8 -LIBADD= util +LIBADD= util ufs .PATH: ${.CURDIR:H}/fsck ${.CURDIR:H}/fsck_ffs diff --git a/sbin/quotacheck/quotacheck.c b/sbin/quotacheck/quotacheck.c index c7582b09dc53..7071aaf9dea5 100644 --- a/sbin/quotacheck/quotacheck.c +++ b/sbin/quotacheck/quotacheck.c @@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -121,7 +122,7 @@ int fi; /* open disk file descriptor */ struct fileusage * addid(u_long, int, char *, const char *); -void bread(ufs2_daddr_t, char *, long); +void blkread(ufs2_daddr_t, char *, long); void freeinodebuf(void); union dinode * getnextinode(ino_t); @@ -243,11 +244,6 @@ usage(void) exit(1); } -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - /* * Scan the specified file system to check quota(s) present on it. */ @@ -256,7 +252,8 @@ chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg) { struct fileusage *fup; union dinode *dp; - int cg, i, mode, errs = 0; + struct fs *fs; + int cg, i, ret, mode, errs = 0; ino_t ino, inosused, userino = 0, groupino = 0; dev_t dev, userdev = 0, groupdev = 0; struct stat sb; @@ -323,26 +320,24 @@ chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg) } } sync(); - dev_bsize = 1; - for (i = 0; sblock_try[i] != -1; i++) { - bread(sblock_try[i], (char *)&sblock, (long)SBLOCKSIZE); - if ((sblock.fs_magic == FS_UFS1_MAGIC || - (sblock.fs_magic == FS_UFS2_MAGIC && - sblock.fs_sblockloc == sblock_try[i])) && - sblock.fs_bsize <= MAXBSIZE && - sblock.fs_bsize >= sizeof(struct fs)) - break; - } - if (sblock_try[i] == -1) { - warn("Cannot find file system superblock"); - return (1); + if ((ret = sbget(fi, &fs, -1)) != 0) { + switch (ret) { + case ENOENT: + warn("Cannot find file system superblock"); + return (1); + default: + warn("Unable to read file system superblock"); + return (1); + } } + bcopy(fs, &sblock, fs->fs_sbsize); + free(fs); dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); maxino = sblock.fs_ncg * sblock.fs_ipg; for (cg = 0; cg < sblock.fs_ncg; cg++) { ino = cg * sblock.fs_ipg; setinodebuf(ino); - bread(fsbtodb(&sblock, cgtod(&sblock, cg)), (char *)(&cgblk), + blkread(fsbtodb(&sblock, cgtod(&sblock, cg)), (char *)(&cgblk), sblock.fs_cgsize); if (sblock.fs_magic == FS_UFS2_MAGIC) inosused = cgblk.cg_initediblk; @@ -618,10 +613,10 @@ getnextinode(ino_t inumber) lastinum += fullcnt; } /* - * If bread returns an error, it will already have zeroed + * If blkread returns an error, it will already have zeroed * out the buffer, so we do not need to do so here. */ - bread(dblk, inodebuf, size); + blkread(dblk, inodebuf, size); nextinop = inodebuf; } dp = (union dinode *)nextinop; @@ -680,12 +675,12 @@ freeinodebuf(void) * Read specified disk blocks. */ void -bread(ufs2_daddr_t bno, char *buf, long cnt) +blkread(ufs2_daddr_t bno, char *buf, long cnt) { if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || read(fi, buf, cnt) != cnt) - errx(1, "bread failed on block %ld", (long)bno); + errx(1, "blkread failed on block %ld", (long)bno); } /* diff --git a/stand/libsa/Makefile b/stand/libsa/Makefile index f95bb64806bd..3b54e67a19cf 100644 --- a/stand/libsa/Makefile +++ b/stand/libsa/Makefile @@ -141,6 +141,10 @@ SRCS+= pkgfs.c SRCS+= nandfs.c .endif +# kernel ufs support +.PATH: ${SRCTOP}/sys/ufs/ffs +SRCS+=ffs_subr.c ffs_tables.c + CFLAGS.bzipfs.c+= -I${SRCTOP}/contrib/bzip2 # explicit_bzero diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c index e0ceed804d9a..1f0b7d3591f6 100644 --- a/stand/libsa/ufs.c +++ b/stand/libsa/ufs.c @@ -133,6 +133,11 @@ static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); static int buf_read_file(struct open_file *, char **, size_t *); static int buf_write_file(struct open_file *, char *, size_t *); static int search_directory(char *, struct open_file *, ino_t *); +static int ufs_use_sa_read(void *, off_t, void **, int); + +/* from ffs_subr.c */ +int ffs_sbget(void *, struct fs **, off_t, char *, + int (*)(void *, off_t, void **, int)); /* * Read a new inode into a file structure. @@ -485,8 +490,6 @@ search_directory(name, f, inumber_p) return (ENOENT); } -static int sblock_try[] = SBLOCKSEARCH; - /* * Open a file. */ @@ -512,31 +515,11 @@ ufs_open(upath, f) bzero(fp, sizeof(struct file)); f->f_fsdata = (void *)fp; - /* allocate space and read super block */ - fs = malloc(SBLOCKSIZE); - fp->f_fs = fs; + /* read super block */ twiddle(1); - /* - * Try reading the superblock in each of its possible locations. - */ - for (i = 0; sblock_try[i] != -1; i++) { - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, - (char *)fs, &buf_size); - if (rc) - goto out; - if ((fs->fs_magic == FS_UFS1_MAGIC || - (fs->fs_magic == FS_UFS2_MAGIC && - fs->fs_sblockloc == sblock_try[i])) && - buf_size == SBLOCKSIZE && - fs->fs_bsize <= MAXBSIZE && - fs->fs_bsize >= sizeof(struct fs)) - break; - } - if (sblock_try[i] == -1) { - rc = EINVAL; + if ((rc = ffs_sbget(f, &fs, -1, 0, ufs_use_sa_read)) != 0) goto out; - } + fp->f_fs = fs; /* * Calculate indirect block levels. */ @@ -693,6 +676,28 @@ ufs_open(upath, f) return (rc); } +/* + * A read function for use by standalone-layer routines. + */ +static int +ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size) +{ + struct open_file *f; + size_t buf_size; + int error; + + f = (struct open_file *)devfd; + if ((*bufp = malloc(size)) == NULL) + return (ENOSPC); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE, + size, *bufp, &buf_size); + if (error != 0) + return (error); + if (buf_size != size) + return (EIO); + return (0); +} + static int ufs_close(f) struct open_file *f; diff --git a/sys/geom/geom.h b/sys/geom/geom.h index e283c999988f..657cc369200b 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -344,6 +344,8 @@ void * g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error int g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length); int g_delete_data(struct g_consumer *cp, off_t offset, off_t length); void g_print_bio(struct bio *bp); +int g_use_g_read_data(void *, off_t, void **, int); +int g_use_g_write_data(void *, off_t, void *, int); /* geom_kern.c / geom_kernsim.c */ diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index 9ca441ca4937..bab0041a244c 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -949,6 +949,29 @@ g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) return (ptr); } +/* + * A read function for use by ffs_sbget when used by GEOM-layer routines. + */ +int +g_use_g_read_data(void *devfd, off_t loc, void **bufp, int size) +{ + struct g_consumer *cp; + + cp = (struct g_consumer *)devfd; + /* + * Take care not to issue an invalid I/O request. The offset of + * the superblock candidate must be multiples of the provider's + * sector size, otherwise an FFS can't exist on the provider + * anyway. + */ + if (loc % cp->provider->sectorsize != 0) + return (ENOENT); + *bufp = g_read_data(cp, loc, size, NULL); + if (*bufp == NULL) + return (ENOENT); + return (0); +} + int g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) { @@ -971,6 +994,16 @@ g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) return (error); } +/* + * A write function for use by ffs_sbput when used by GEOM-layer routines. + */ +int +g_use_g_write_data(void *devfd, off_t loc, void *buf, int size) +{ + + return (g_write_data((struct g_consumer *)devfd, loc, buf, size)); +} + int g_delete_data(struct g_consumer *cp, off_t offset, off_t length) { diff --git a/sys/geom/journal/g_journal_ufs.c b/sys/geom/journal/g_journal_ufs.c index 2080808a8c93..ec25750c38ac 100644 --- a/sys/geom/journal/g_journal_ufs.c +++ b/sys/geom/journal/g_journal_ufs.c @@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$"); #include #include -static const int superblocks[] = SBLOCKSEARCH; - static int g_journal_ufs_clean(struct mount *mp) { @@ -70,33 +68,25 @@ static void g_journal_ufs_dirty(struct g_consumer *cp) { struct fs *fs; - int error, i, sb; + int error; - if (SBLOCKSIZE % cp->provider->sectorsize != 0) + if (SBLOCKSIZE % cp->provider->sectorsize != 0 || + ffs_sbget(cp, &fs, -1, NULL, g_use_g_read_data) != 0) { + GJ_DEBUG(0, "Cannot find superblock to mark file system %s " + "as dirty.", cp->provider->name); return; - for (i = 0; (sb = superblocks[i]) != -1; i++) { - if (sb % cp->provider->sectorsize != 0) - continue; - fs = g_read_data(cp, sb, SBLOCKSIZE, NULL); - if (fs == NULL) - continue; - if (fs->fs_magic != FS_UFS1_MAGIC && - fs->fs_magic != FS_UFS2_MAGIC) { - g_free(fs); - continue; - } - 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; - error = g_write_data(cp, sb, fs, SBLOCKSIZE); - g_free(fs); - if (error != 0) { - GJ_DEBUG(0, "Cannot mark file system %s as dirty " - "(error=%d).", cp->provider->name, error); - } else { - GJ_DEBUG(0, "File system %s marked as dirty.", - cp->provider->name); - } + } + 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; + error = ffs_sbput(cp, fs, fs->fs_sblockloc, g_use_g_write_data); + g_free(fs); + if (error != 0) { + GJ_DEBUG(0, "Cannot mark file system %s as dirty " + "(error=%d).", cp->provider->name, error); + } else { + GJ_DEBUG(0, "File system %s marked as dirty.", + cp->provider->name); } } diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c index b53d6e45857e..43c44586cb05 100644 --- a/sys/geom/label/g_label_ufs.c +++ b/sys/geom/label/g_label_ufs.c @@ -32,11 +32,14 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include +#include #include #include +#include +#include +#include #include #include @@ -56,106 +59,63 @@ __FBSDID("$FreeBSD$"); < G_LABEL_UFS_MAXDIFF ) #define G_LABEL_UFS_MAXDIFF 0x100 -static const int superblocks[] = SBLOCKSEARCH; - +/* + * Try to find a superblock on the provider. If successful, then + * check that the size in the superblock corresponds to the size + * of the underlying provider. Finally, look for a volume label + * and create an appropriate provider based on that. + */ static void g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int what) { struct g_provider *pp; - int sb, superblock; struct fs *fs; g_topology_assert_not(); pp = cp->provider; label[0] = '\0'; - if (SBLOCKSIZE % cp->provider->sectorsize != 0) + if (SBLOCKSIZE % pp->sectorsize != 0 || + ffs_sbget(cp, &fs, -1, NULL, g_use_g_read_data) != 0) return; - /* - * Walk through the standard places that superblocks hide and look - * for UFS magic. If we find magic, then check that the size in the - * superblock corresponds to the size of the underlying provider. - * Finally, look for a volume label and create an appropriate - * provider based on that. + * Check for magic. We also need to check if file system size + * is almost equal to providers size, because sysinstall(8) + * used to bogusly put first partition at offset 0 + * instead of 16, and glabel/ufs would find file system on slice + * instead of partition. + * + * In addition, media size can be a bit bigger than file system + * size. For instance, mkuzip can append bytes to align data + * to large sector size (it improves compression rates). */ - for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { - /* - * Take care not to issue an invalid I/O request. The offset of - * the superblock candidate must be multiples of the provider's - * sector size, otherwise an FFS can't exist on the provider - * anyway. - */ - if (superblock % cp->provider->sectorsize != 0) - continue; - - fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE, NULL); - if (fs == NULL) - continue; - /* - * Check for magic. We also need to check if file system size - * is almost equal to providers size, because sysinstall(8) - * used to bogusly put first partition at offset 0 - * instead of 16, and glabel/ufs would find file system on slice - * instead of partition. - * - * In addition, media size can be a bit bigger than file system - * size. For instance, mkuzip can append bytes to align data - * to large sector size (it improves compression rates). - */ - switch (fs->fs_magic){ - case FS_UFS1_MAGIC: - case FS_UFS2_MAGIC: - G_LABEL_DEBUG(1, "%s %s params: %jd, %d, %d, %jd\n", - fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", - pp->name, pp->mediasize, fs->fs_fsize, - fs->fs_old_size, fs->fs_providersize); - break; - default: - break; - } - - if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && - ( G_LABEL_UFS_CMP(pp, fs, fs_old_size) - || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { - /* Valid UFS1. */ - } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && - ( G_LABEL_UFS_CMP(pp, fs, fs_size) - || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { - /* Valid UFS2. */ - } else { - g_free(fs); - continue; - } - if (fs->fs_sblockloc != superblock || fs->fs_ncg < 1 || - fs->fs_bsize < MINBSIZE || - fs->fs_bsize < sizeof(struct fs)) { - g_free(fs); - continue; - } - G_LABEL_DEBUG(1, "%s file system detected on %s.", - fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name); - switch (what) { - case G_LABEL_UFS_VOLUME: - /* Check for volume label */ - if (fs->fs_volname[0] == '\0') { - g_free(fs); - continue; - } + if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && + ( G_LABEL_UFS_CMP(pp, fs, fs_old_size) + || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { + /* Valid UFS1. */ + } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && + ( G_LABEL_UFS_CMP(pp, fs, fs_size) + || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { + /* Valid UFS2. */ + } else { + g_free(fs); + return; + } + G_LABEL_DEBUG(1, "%s file system detected on %s.", + fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name); + switch (what) { + case G_LABEL_UFS_VOLUME: + /* Check for volume label */ + if (fs->fs_volname[0] != '\0') strlcpy(label, fs->fs_volname, size); - break; - case G_LABEL_UFS_ID: - if (fs->fs_id[0] == 0 && fs->fs_id[1] == 0) { - g_free(fs); - continue; - } + break; + case G_LABEL_UFS_ID: + if (fs->fs_id[0] != 0 || fs->fs_id[1] != 0) snprintf(label, size, "%08x%08x", fs->fs_id[0], fs->fs_id[1]); - break; - } - g_free(fs); break; } + g_free(fs); } static void diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 5e9be1ea914a..2df48ec91de9 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -87,6 +87,10 @@ int ffs_reallocblks(struct vop_reallocblks_args *); int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t, ufs2_daddr_t, int, int, int, struct ucred *, struct buf **); int ffs_reload(struct mount *, struct thread *, int); +int ffs_sbget(void *, struct fs **, off_t, struct malloc_type *, + int (*)(void *, off_t, void **, int)); +int ffs_sbput(void *, struct fs *, off_t, int (*)(void *, off_t, void *, + int)); int ffs_sbupdate(struct ufsmount *, int, int); void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t, @@ -95,18 +99,17 @@ void ffs_snapremove(struct vnode *vp); int ffs_snapshot(struct mount *mp, char *snapfile); void ffs_snapshot_mount(struct mount *mp); void ffs_snapshot_unmount(struct mount *mp); -void process_deferred_inactive(struct mount *mp); +void ffs_susp_initialize(void); +void ffs_susp_uninitialize(void); void ffs_sync_snap(struct mount *, int); int ffs_syncvnode(struct vnode *vp, int waitfor, int flags); int ffs_truncate(struct vnode *, off_t, int, struct ucred *); int ffs_update(struct vnode *, int); int ffs_valloc(struct vnode *, int, struct ucred *, struct vnode **); - int ffs_vfree(struct vnode *, ino_t, int); vfs_vget_t ffs_vget; int ffs_vgetf(struct mount *, ino_t, int, struct vnode **, int); -void ffs_susp_initialize(void); -void ffs_susp_uninitialize(void); +void process_deferred_inactive(struct mount *mp); #define FFSV_FORCEINSMQ 0x0001 diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 5a07ab5ae106..3504c625eb70 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -37,9 +37,20 @@ __FBSDID("$FreeBSD$"); #include #ifndef _KERNEL +#include +#include +#include +#include +#include #include #include -#else + +struct malloc_type; +#define UFS_MALLOC(size, type, flags) malloc(size) +#define UFS_FREE(ptr, type) free(ptr) +#define UFS_TIME time(NULL) + +#else /* _KERNEL */ #include #include #include @@ -57,6 +68,10 @@ __FBSDID("$FreeBSD$"); #include #include +#define UFS_MALLOC(size, type, flags) malloc(size, type, flags) +#define UFS_FREE(ptr, type) free(ptr, type) +#define UFS_TIME time_second + /* * Return buffer with the contents of block "offset" from the beginning of * directory "ip". If "res" is non-zero, fill it in with a pointer to the @@ -120,6 +135,175 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino) } #endif /* KERNEL */ +/* + * These are the low-level functions that actually read and write + * the superblock and its associated data. + */ +static off_t sblock_try[] = SBLOCKSEARCH; +static int readsuper(void *, struct fs **, off_t, + int (*)(void *, off_t, void **, int)); + +/* + * Read a superblock from the devfd device. + * + * If an alternate superblock is specified, it is read. Otherwise the + * set of locations given in the SBLOCKSEARCH list is searched for a + * superblock. Memory is allocated for the superblock by the readfunc and + * is returned. If filltype is non-NULL, additional memory is allocated + * of type filltype and filled in with the superblock summary information. + * + * If a superblock is found, zero is returned. Otherwise one of the + * following error values is returned: + * EIO: non-existent or truncated superblock. + * EIO: error reading summary information. + * ENOENT: no usable known superblock found. + * ENOSPC: failed to allocate space for the superblock. + * EINVAL: The previous newfs operation on this volume did not complete. + * The administrator must complete newfs before using this volume. + */ +int +ffs_sbget(void *devfd, struct fs **fsp, off_t altsuperblock, + struct malloc_type *filltype, + int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) +{ + struct fs *fs; + int i, ret, size, blks; + uint8_t *space; + int32_t *lp; + char *buf; + + if (altsuperblock != -1) { + if ((ret = readsuper(devfd, fsp, altsuperblock, readfunc)) != 0) + return (ret); + } else { + for (i = 0; sblock_try[i] != -1; i++) { + if ((ret = readsuper(devfd, fsp, sblock_try[i], + readfunc)) == 0) + break; + if (ret == ENOENT) + continue; + return (ret); + } + if (sblock_try[i] == -1) + return (ENOENT); + } + /* + * If not filling in summary information, NULL out fs_csp and return. + */ + fs = *fsp; + if (filltype == NULL) { + fs->fs_csp = NULL; + return (0); + } + /* + * Read in the superblock summary information. + */ + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + size += fs->fs_ncg * sizeof(u_int8_t); + space = UFS_MALLOC(size, filltype, M_WAITOK); + fs->fs_csp = (struct csum *)space; + 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; + ret = (*readfunc)(devfd, + dbtob(fsbtodb(fs, fs->fs_csaddr + i)), (void **)&buf, size); + if (ret) { + UFS_FREE(fs->fs_csp, filltype); + fs->fs_csp = NULL; + return (ret); + } + memcpy(space, buf, size); + UFS_FREE(buf, filltype); + space += size; + } + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = (int32_t *)space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + space = (uint8_t *)lp; + } + size = fs->fs_ncg * sizeof(u_int8_t); + fs->fs_contigdirs = (u_int8_t *)space; + bzero(fs->fs_contigdirs, size); + return (0); +} + +/* + * Try to read a superblock from the location specified by sblockloc. + * Return zero on success or an errno on failure. + */ +static int +readsuper(void *devfd, struct fs **fsp, off_t sblockloc, + int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) +{ + struct fs *fs; + int error; + + error = (*readfunc)(devfd, sblockloc, (void **)fsp, SBLOCKSIZE); + if (error != 0) + return (error); + fs = *fsp; + if (fs->fs_magic == FS_BAD_MAGIC) + return (EINVAL); + if (((fs->fs_magic == FS_UFS1_MAGIC && sblockloc <= SBLOCK_UFS1) || + (fs->fs_magic == FS_UFS2_MAGIC && + sblockloc == fs->fs_sblockloc)) && + fs->fs_ncg >= 1 && + fs->fs_bsize >= MINBSIZE && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= roundup(sizeof(struct fs), DEV_BSIZE)) { + /* Have to set for old filesystems that predate this field */ + fs->fs_sblockactualloc = sblockloc; + return (0); + } + return (ENOENT); +} + +/* + * Write a superblock to the devfd device from the memory pointed to by fs. + * Write out the superblock summary information if it is present. + * + * If the write is successful, zero is returned. Otherwise one of the + * following error values is returned: + * EIO: failed to write superblock. + * EIO: failed to write superblock summary information. + */ +int +ffs_sbput(void *devfd, struct fs *fs, off_t loc, + int (*writefunc)(void *devfd, off_t loc, void *buf, int size)) +{ + int i, error, blks, size; + uint8_t *space; + + /* + * 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) { + blks = howmany(fs->fs_cssize, fs->fs_fsize); + space = (uint8_t *)fs->fs_csp; + 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 = (*writefunc)(devfd, + dbtob(fsbtodb(fs, fs->fs_csaddr + i)), + space, size)) != 0) + return (error); + space += size; + } + } + fs->fs_fmod = 0; + fs->fs_time = UFS_TIME; + if ((error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize)) != 0) + return (error); + return (0); +} + /* * Update the frsum fields to reflect addition or deletion * of some frags. diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 2a63ee74b654..caf062867dbe 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -87,6 +87,8 @@ static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, ufs2_daddr_t); static void ffs_ifree(struct ufsmount *ump, struct inode *ip); static int ffs_sync_lazy(struct mount *mp); +static int ffs_use_bread(void *devfd, off_t loc, void **bufp, int size); +static int ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size); static vfs_init_t ffs_init; static vfs_uninit_t ffs_uninit; @@ -752,11 +754,6 @@ ffs_reload(struct mount *mp, struct thread *td, int flags) return (0); } -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; - /* * Common code for mount and mountroot */ @@ -767,19 +764,14 @@ ffs_mountfs(devvp, mp, td) struct thread *td; { struct ufsmount *ump; - struct buf *bp; struct fs *fs; struct cdev *dev; - void *space; - ufs2_daddr_t sblockloc; - int error, i, blks, len, ronly; - u_long size; - int32_t *lp; + int error, i, len, ronly; struct ucred *cred; struct g_consumer *cp; struct mount *nmp; - bp = NULL; + fs = NULL; ump = NULL; cred = td ? td->td_ucred : NOCRED; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; @@ -806,39 +798,16 @@ ffs_mountfs(devvp, mp, td) mp->mnt_iosize_max = dev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) mp->mnt_iosize_max = MAXPHYS; - - fs = NULL; - sblockloc = 0; - /* - * Try reading the superblock in each of its possible locations. - */ - for (i = 0; sblock_try[i] != -1; i++) { - if ((SBLOCKSIZE % cp->provider->sectorsize) != 0) { - error = EINVAL; - vfs_mount_error(mp, - "Invalid sectorsize %d for superblock size %d", - cp->provider->sectorsize, SBLOCKSIZE); - goto out; - } - if ((error = bread(devvp, btodb(sblock_try[i]), SBLOCKSIZE, - cred, &bp)) != 0) - goto out; - fs = (struct fs *)bp->b_data; - sblockloc = sblock_try[i]; - if ((fs->fs_magic == FS_UFS1_MAGIC || - (fs->fs_magic == FS_UFS2_MAGIC && - (fs->fs_sblockloc == sblockloc || - (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0))) && - fs->fs_bsize <= MAXBSIZE && - fs->fs_bsize >= sizeof(struct fs)) - break; - brelse(bp); - bp = NULL; - } - if (sblock_try[i] == -1) { - error = EINVAL; /* XXX needs translation */ + if ((SBLOCKSIZE % cp->provider->sectorsize) != 0) { + error = EINVAL; + vfs_mount_error(mp, + "Invalid sectorsize %d for superblock size %d", + cp->provider->sectorsize, SBLOCKSIZE); goto out; } + /* fetch the superblock and summary information */ + if ((error = ffs_sbget(devvp, &fs, -1, M_UFSMNT, ffs_use_bread)) != 0) + goto out; fs->fs_fmod = 0; /* none of these types of check-hashes are maintained */ fs->fs_metackhash &= ~(CK_SUPERBLOCK | CK_INODE | CK_INDIR | CK_DIR); @@ -908,7 +877,7 @@ ffs_mountfs(devvp, mp, td) ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); ump->um_cp = cp; ump->um_bo = &devvp->v_bufobj; - ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); + ump->um_fs = fs; if (fs->fs_magic == FS_UFS1_MAGIC) { ump->um_fstype = UFS1; ump->um_balloc = ffs_balloc_ufs1; @@ -925,44 +894,8 @@ ffs_mountfs(devvp, mp, td) ump->um_rdonly = ffs_rdonly; ump->um_snapgone = ffs_snapgone; mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF); - bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); - if (fs->fs_sbsize < SBLOCKSIZE) - bp->b_flags |= B_INVAL | B_NOCACHE; - brelse(bp); - bp = NULL; - fs = ump->um_fs; - ffs_oldfscompat_read(fs, ump, sblockloc); + ffs_oldfscompat_read(fs, ump, fs->fs_sblockloc); fs->fs_ronly = ronly; - size = fs->fs_cssize; - blks = howmany(size, fs->fs_fsize); - if (fs->fs_contigsumsize > 0) - size += fs->fs_ncg * sizeof(int32_t); - size += fs->fs_ncg * sizeof(u_int8_t); - space = malloc(size, M_UFSMNT, M_WAITOK); - fs->fs_csp = space; - 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, - cred, &bp)) != 0) { - free(fs->fs_csp, M_UFSMNT); - goto out; - } - bcopy(bp->b_data, space, (u_int)size); - space = (char *)space + size; - brelse(bp); - bp = NULL; - } - if (fs->fs_contigsumsize > 0) { - fs->fs_maxcluster = lp = space; - for (i = 0; i < fs->fs_ncg; i++) - *lp++ = fs->fs_contigsumsize; - space = lp; - } - size = fs->fs_ncg * sizeof(u_int8_t); - fs->fs_contigdirs = (u_int8_t *)space; - bzero(fs->fs_contigdirs, size); fs->fs_active = NULL; mp->mnt_data = ump; mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; @@ -1075,7 +1008,6 @@ ffs_mountfs(devvp, mp, td) fs->fs_mtime = time_second; if ((fs->fs_flags & FS_DOSOFTDEP) && (error = softdep_mount(devvp, mp, fs, cred)) != 0) { - free(fs->fs_csp, M_UFSMNT); ffs_flushfiles(mp, FORCECLOSE, td); goto out; } @@ -1109,8 +1041,10 @@ ffs_mountfs(devvp, mp, td) #endif /* !UFS_EXTATTR */ return (0); out: - if (bp) - brelse(bp); + if (fs != NULL) { + free(fs->fs_csp, M_UFSMNT); + free(fs, M_UFSMNT); + } if (cp != NULL) { g_topology_lock(); g_vfs_close(cp); @@ -1122,7 +1056,6 @@ ffs_mountfs(devvp, mp, td) free(mp->mnt_gjprovider, M_UFSMNT); mp->mnt_gjprovider = NULL; } - free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = NULL; } @@ -1131,6 +1064,28 @@ ffs_mountfs(devvp, mp, td) return (error); } +/* + * A read function for use by filesystem-layer routines. + */ +static int +ffs_use_bread(void *devfd, off_t loc, void **bufp, int size) +{ + struct buf *bp; + int error; + + *bufp = malloc(size, M_UFSMNT, M_WAITOK); + if ((error = bread((struct vnode *)devfd, btodb(loc), size, NOCRED, + &bp)) != 0) { + free(*bufp, M_UFSMNT); + *bufp = NULL; + return (error); + } + bcopy(bp->b_data, *bufp, size); + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + return (0); +} + #include static int bigcgs = 0; SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, ""); @@ -1907,6 +1862,18 @@ ffs_uninit(vfsp) return (ret); } +/* + * Structure used to pass information from ffs_sbupdate to its + * helper routine ffs_use_bwrite. + */ +struct devfd { + struct ufsmount *ump; + struct buf *sbbp; + int waitfor; + int suspended; + int error; +}; + /* * Write a superblock and associated information back to disk. */ @@ -1916,13 +1883,11 @@ ffs_sbupdate(ump, waitfor, suspended) int waitfor; int suspended; { - struct fs *fs = ump->um_fs; + struct fs *fs; struct buf *sbbp; - struct buf *bp; - int blks; - void *space; - int i, size, error, allerror = 0; + struct devfd devfd; + fs = ump->um_fs; if (fs->fs_ronly == 1 && (ump->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) != (MNT_RDONLY | MNT_UPDATE) && ump->um_fsckpid == 0) @@ -1933,35 +1898,53 @@ ffs_sbupdate(ump, waitfor, suspended) sbbp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc), (int)fs->fs_sbsize, 0, 0, 0); /* - * First write back the summary information. + * Initialize info needed for write function. */ - blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = fs->fs_csp; - 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; - bp = getblk(ump->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), - size, 0, 0, 0); - bcopy(space, bp->b_data, (u_int)size); - space = (char *)space + size; - if (suspended) + devfd.ump = ump; + devfd.sbbp = sbbp; + devfd.waitfor = waitfor; + devfd.suspended = suspended; + devfd.error = 0; + return (ffs_sbput(&devfd, fs, fs->fs_sblockloc, ffs_use_bwrite)); +} + +/* + * Write function for use by filesystem-layer routines. + */ +static int +ffs_use_bwrite(void *devfd, off_t loc, void *buf, int size) +{ + struct devfd *devfdp; + struct ufsmount *ump; + struct buf *bp; + struct fs *fs; + int error; + + devfdp = devfd; + ump = devfdp->ump; + fs = ump->um_fs; + /* + * Writing the superblock summary information. + */ + if (loc != fs->fs_sblockloc) { + bp = getblk(ump->um_devvp, btodb(loc), size, 0, 0, 0); + bcopy(buf, bp->b_data, (u_int)size); + if (devfdp->suspended) bp->b_flags |= B_VALIDSUSPWRT; - if (waitfor != MNT_WAIT) + if (devfdp->waitfor != MNT_WAIT) bawrite(bp); else if ((error = bwrite(bp)) != 0) - allerror = error; + devfdp->error = error; + return (0); } /* - * Now write back the superblock itself. If any errors occurred - * up to this point, then fail so that the superblock avoids - * being written out as clean. + * Writing the superblock itself. We need to do special checks for it. */ - if (allerror) { - brelse(sbbp); - return (allerror); + bp = devfdp->sbbp; + if (devfdp->error != 0) { + brelse(bp); + return (devfdp->error); } - bp = sbbp; if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 && (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { printf("WARNING: %s: correcting fs_sblockloc from %jd to %d\n", @@ -1974,19 +1957,17 @@ ffs_sbupdate(ump, waitfor, suspended) fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2); fs->fs_sblockloc = SBLOCK_UFS2; } - fs->fs_fmod = 0; - fs->fs_time = time_second; if (MOUNTEDSOFTDEP(ump->um_mountp)) softdep_setup_sbupdate(ump, (struct fs *)bp->b_data, bp); bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); ffs_oldfscompat_write((struct fs *)bp->b_data, ump); - if (suspended) + if (devfdp->suspended) bp->b_flags |= B_VALIDSUSPWRT; - if (waitfor != MNT_WAIT) + if (devfdp->waitfor != MNT_WAIT) bawrite(bp); else if ((error = bwrite(bp)) != 0) - allerror = error; - return (allerror); + devfdp->error = error; + return (devfdp->error); } static int diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index cc0a480f253e..81deda7b8517 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -348,7 +348,8 @@ struct fs { int64_t fs_unrefs; /* number of unreferenced inodes */ int64_t fs_providersize; /* size of underlying GEOM provider */ int64_t fs_metaspace; /* size of area reserved for metadata */ - int64_t fs_sparecon64[14]; /* old rotation block list head */ + int64_t fs_sparecon64[13]; /* old rotation block list head */ + int64_t fs_sblockactualloc; /* byte offset of this superblock */ int64_t fs_sblockloc; /* byte offset of standard superblock */ struct csum_total fs_cstotal; /* (u) cylinder summary information */ ufs_time_t fs_time; /* last time written */ diff --git a/usr.sbin/fstyp/Makefile b/usr.sbin/fstyp/Makefile index 34be663fc362..f3fb038ed542 100644 --- a/usr.sbin/fstyp/Makefile +++ b/usr.sbin/fstyp/Makefile @@ -37,7 +37,7 @@ CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/head CFLAGS+=-I${SRCTOP}/sys -LIBADD= geom md +LIBADD= geom md ufs .if ${MK_ZFS} != "no" LIBADD+=nvpair zfs diff --git a/usr.sbin/fstyp/ufs.c b/usr.sbin/fstyp/ufs.c index 8b27ca00fe43..340119dada4c 100644 --- a/usr.sbin/fstyp/ufs.c +++ b/usr.sbin/fstyp/ufs.c @@ -33,77 +33,32 @@ __FBSDID("$FreeBSD$"); #include +#include +#include + +#include +#include #include #include #include #include -#include -#include - #include "fstyp.h" -static const int superblocks[] = SBLOCKSEARCH; - int fstyp_ufs(FILE *fp, char *label, size_t labelsize) { - int sb, superblock; struct fs *fs; - /* - * Walk through the standard places that superblocks hide and look - * for UFS magic. If we find magic, then check that the size in the - * superblock corresponds to the size of the underlying provider. - * Finally, look for a volume label and create an appropriate - * provider based on that. - */ - for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { - fs = (struct fs *)read_buf(fp, superblock, SBLOCKSIZE); - if (fs == NULL) - continue; - /* - * Check for magic. We also need to check if file system size is equal - * to providers size, because sysinstall(8) used to bogusly put first - * partition at offset 0 instead of 16, and glabel/ufs would find file - * system on slice instead of partition. - */ -#ifdef notyet - if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && - ((pp->mediasize / fs->fs_fsize == fs->fs_old_size) || - (pp->mediasize / fs->fs_fsize == fs->fs_providersize))) { - /* Valid UFS1. */ - } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && - ((pp->mediasize / fs->fs_fsize == fs->fs_size) || - (pp->mediasize / fs->fs_fsize == fs->fs_providersize))) { - /* Valid UFS2. */ - } else { - g_free(fs); - continue; - } -#else - if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0) { - /* Valid UFS1. */ - } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0) { - /* Valid UFS2. */ - } else { - free(fs); - continue; - } -#endif - - if (fs->fs_sblockloc != superblock || fs->fs_ncg < 1 || - fs->fs_bsize < MINBSIZE || - (size_t)fs->fs_bsize < sizeof(struct fs)) { - free(fs); - continue; - } - + switch (sbget(fileno(fp), &fs, -1)) { + case 0: strlcpy(label, fs->fs_volname, labelsize); - - free(fs); return (0); + case ENOENT: + /* Cannot find file system superblock */ + return (1); + default: + /* Unable to read file system superblock */ + return (1); } - - return (1); } diff --git a/usr.sbin/quot/Makefile b/usr.sbin/quot/Makefile index 07bcc7eff1cf..3ec74b02ce5c 100644 --- a/usr.sbin/quot/Makefile +++ b/usr.sbin/quot/Makefile @@ -2,6 +2,7 @@ PROG= quot MAN= quot.8 +LIBADD= ufs WARNS?= 2 diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c index 49822e4d84ad..348946ff7dbb 100644 --- a/usr.sbin/quot/quot.c +++ b/usr.sbin/quot/quot.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -535,16 +536,10 @@ usage(void) exit(1); } -/* - * Possible superblock locations ordered from most to least likely. - */ -static int sblock_try[] = SBLOCKSEARCH; -static char superblock[SBLOCKSIZE]; - void quot(char *name, char *mp) { - int i, fd; + int fd; struct fs *fs; get_inode(-1, NULL, 0); /* flush cache */ @@ -555,25 +550,15 @@ quot(char *name, char *mp) close(fd); return; } - for (i = 0; sblock_try[i] != -1; i++) { - if (lseek(fd, sblock_try[i], 0) != sblock_try[i]) { - close(fd); - return; - } - if (read(fd, superblock, SBLOCKSIZE) != SBLOCKSIZE) { - close(fd); - return; - } - fs = (struct fs *)superblock; - if ((fs->fs_magic == FS_UFS1_MAGIC || - (fs->fs_magic == FS_UFS2_MAGIC && - fs->fs_sblockloc == sblock_try[i])) && - fs->fs_bsize <= MAXBSIZE && - fs->fs_bsize >= sizeof(struct fs)) - break; - } - if (sblock_try[i] == -1) { - warnx("%s: not a BSD filesystem",name); + switch (sbget(fd, &fs, -1)) { + case 0: + break; + case ENOENT: + warn("Cannot find file system superblock"); + close(fd); + return; + default: + warn("Unable to read file system superblock"); close(fd); return; }