Refactoring of reading and writing of the UFS/FFS superblock.

Specifically reading is done if ffs_sbget() and writing is done
in ffs_sbput(). These functions are exported to libufs via the
sbget() and sbput() functions which then used in the various
filesystem utilities. This work is in preparation for adding
subperblock check hashes.

No functional change intended.

Reviewed by: kib
This commit is contained in:
mckusick 2018-01-26 00:58:32 +00:00
parent 840451d418
commit f5e73a2c14
33 changed files with 858 additions and 797 deletions

View File

@ -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

View File

@ -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
*/

View File

@ -47,79 +47,48 @@ __FBSDID("$FreeBSD$");
#include <libufs.h>
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);
}

View File

@ -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 .

View File

@ -4,6 +4,7 @@
PACKAGE=runtime
PROG= clri
MAN= clri.8
LIBADD= ufs
WARNS?= 2
.include <bsd.prog.mk>

View File

@ -54,17 +54,14 @@ __FBSDID("$FreeBSD$");
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libufs.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
/*
* 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);

View File

@ -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

View File

@ -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) */

View File

@ -59,6 +59,7 @@ static const char rcsid[] =
#include <errno.h>
#include <fcntl.h>
#include <fstab.h>
#include <libufs.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
@ -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))

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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.

View File

@ -4,6 +4,7 @@
PACKAGE=runtime
PROG= fsirand
MAN= fsirand.8
LIBADD= ufs
WARNS?= 3
.include <bsd.prog.mk>

View File

@ -46,6 +46,7 @@ static const char rcsid[] =
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libufs.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@ -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) {

View File

@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <paths.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fstab.h>
#include <inttypes.h>
@ -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");

View File

@ -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.
*/

View File

@ -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

View File

@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <fstab.h>
#include <grp.h>
#include <libufs.h>
#include <libutil.h>
#include <pwd.h>
#include <stdint.h>
@ -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);
}
/*

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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)
{

View File

@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$");
#include <geom/geom.h>
#include <geom/journal/g_journal.h>
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);
}
}

View File

@ -32,11 +32,14 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/vnode.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ffs/ffs_extern.h>
#include <geom/geom.h>
#include <geom/label/g_label.h>
@ -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

View File

@ -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

View File

@ -37,9 +37,20 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#ifndef _KERNEL
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/errno.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#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 <sys/systm.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@ -57,6 +68,10 @@ __FBSDID("$FreeBSD$");
#include <ufs/ffs/ffs_extern.h>
#include <ufs/ffs/fs.h>
#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.

View File

@ -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 <sys/sysctl.h>
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

View File

@ -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 */

View File

@ -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

View File

@ -33,77 +33,32 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <libufs.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#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);
}

View File

@ -2,6 +2,7 @@
PROG= quot
MAN= quot.8
LIBADD= ufs
WARNS?= 2

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <fstab.h>
#include <errno.h>
#include <libufs.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
@ -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;
}