#include <sys/param.h>
#include <sys/endian.h>
#include <sys/limits.h>
#ifndef _KERNEL
#include <stdbool.h>
#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>
uint32_t calculate_crc32c(uint32_t, const void *, size_t);
uint32_t ffs_calc_sbhash(struct fs *);
struct malloc_type;
#define UFS_MALLOC(size, type, flags) malloc(size)
#define UFS_FREE(ptr, type) free(ptr)
#define maxphys MAXPHYS
#else
#include <sys/systm.h>
#include <sys/gsb_crc32.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/ucred.h>
#include <sys/sysctl.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#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)
#endif
int
ffs_verify_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
{
uint32_t ckhash, save_ckhash;
if (dip->di_mode == 0 || (fs->fs_metackhash & CK_INODE) == 0)
return (0);
save_ckhash = dip->di_ckhash;
dip->di_ckhash = 0;
ckhash = calculate_crc32c(~0L, (void *)dip, sizeof(*dip));
dip->di_ckhash = save_ckhash;
if (save_ckhash == ckhash)
return (0);
return (EINVAL);
}
void
ffs_update_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
{
if (dip->di_mode == 0 || (fs->fs_metackhash & CK_INODE) == 0)
return;
dip->di_ckhash = 0;
dip->di_ckhash = calculate_crc32c(~0L, (void *)dip, sizeof(*dip));
}
static off_t sblock_try[] = SBLOCKSEARCH;
static int readsuper(void *, struct fs **, off_t, int,
int (*)(void *, off_t, void **, int));
static void ffs_oldfscompat_read(struct fs *, ufs2_daddr_t);
static int validate_sblock(struct fs *, int);
int
ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags,
struct malloc_type *filltype,
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
{
struct fs *fs;
struct fs_summary_info *fs_si;
int i, error;
uint64_t size, blks;
uint8_t *space;
int32_t *lp;
char *buf;
fs = NULL;
*fsp = NULL;
if (sblock != UFS_STDSB) {
if ((error = readsuper(devfd, &fs, sblock,
flags | UFS_ALTSBLK, readfunc)) != 0) {
if (fs != NULL)
UFS_FREE(fs, filltype);
return (error);
}
} else {
for (i = 0; sblock_try[i] != -1; i++) {
if ((error = readsuper(devfd, &fs, sblock_try[i],
flags, readfunc)) == 0) {
if ((flags & UFS_NOCSUM) != 0) {
*fsp = fs;
return (0);
}
break;
}
if (fs != NULL) {
UFS_FREE(fs, filltype);
fs = NULL;
}
if (error == ENOENT)
continue;
return (error);
}
if (sblock_try[i] == -1)
return (ENOENT);
}
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(uint8_t);
if ((fs_si = UFS_MALLOC(sizeof(*fs_si), filltype, M_NOWAIT)) == NULL) {
UFS_FREE(fs, filltype);
return (ENOMEM);
}
bzero(fs_si, sizeof(*fs_si));
fs->fs_si = fs_si;
if ((space = UFS_MALLOC(size, filltype, M_NOWAIT)) == NULL) {
UFS_FREE(fs->fs_si, filltype);
UFS_FREE(fs, filltype);
return (ENOMEM);
}
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;
buf = NULL;
error = (*readfunc)(devfd,
dbtob(fsbtodb(fs, fs->fs_csaddr + i)), (void **)&buf, size);
if (error) {
if (buf != NULL)
UFS_FREE(buf, filltype);
UFS_FREE(fs->fs_csp, filltype);
UFS_FREE(fs->fs_si, filltype);
UFS_FREE(fs, filltype);
return (error);
}
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(uint8_t);
fs->fs_contigdirs = (uint8_t *)space;
bzero(fs->fs_contigdirs, size);
*fsp = fs;
return (0);
}
static int
readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int flags,
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
{
struct fs *fs;
int error, res;
uint32_t ckhash;
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 && (flags & UFS_ALTSBLK) == 0 &&
fs->fs_bsize == SBLOCK_UFS2 && sblockloc == SBLOCK_UFS2)
return (ENOENT);
ffs_oldfscompat_read(fs, sblockloc);
if ((error = validate_sblock(fs, flags)) > 0)
return (error);
if ((fs->fs_flags & FS_METACKHASH) == 0)
fs->fs_metackhash = 0;
fs->fs_metackhash &= CK_SUPPORTED;
fs->fs_flags &= FS_SUPPORTED;
if (fs->fs_ckhash != (ckhash = ffs_calc_sbhash(fs))) {
if ((flags & (UFS_NOMSG | UFS_NOHASHFAIL)) ==
(UFS_NOMSG | UFS_NOHASHFAIL))
return (0);
if ((flags & UFS_NOMSG) != 0)
return (EINTEGRITY);
#ifdef _KERNEL
res = uprintf("Superblock check-hash failed: recorded "
"check-hash 0x%x != computed check-hash 0x%x%s\n",
fs->fs_ckhash, ckhash,
(flags & UFS_NOHASHFAIL) != 0 ? " (Ignored)" : "");
#else
res = 0;
#endif
if (res == 0)
printf("Superblock check-hash failed: recorded "
"check-hash 0x%x != computed check-hash "
"0x%x%s\n", fs->fs_ckhash, ckhash,
(flags & UFS_NOHASHFAIL) ? " (Ignored)" : "");
if ((flags & UFS_NOHASHFAIL) != 0)
return (0);
return (EINTEGRITY);
}
fs->fs_sblockactualloc = sblockloc;
fs->fs_si = NULL;
return (0);
}
static void
ffs_oldfscompat_read(struct fs *fs, ufs2_daddr_t sblockloc)
{
uint64_t maxfilesize;
if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
fs->fs_flags = fs->fs_old_flags;
fs->fs_old_flags |= FS_FLAGS_UPDATED;
fs->fs_sblockloc = sblockloc;
}
switch (fs->fs_magic) {
case FS_UFS2_MAGIC:
break;
case FS_UFS1_MAGIC:
if (fs->fs_maxbsize != fs->fs_bsize) {
fs->fs_maxbsize = fs->fs_bsize;
fs->fs_time = fs->fs_old_time;
fs->fs_size = fs->fs_old_size;
fs->fs_dsize = fs->fs_old_dsize;
fs->fs_csaddr = fs->fs_old_csaddr;
fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
}
if (fs->fs_old_inodefmt < FS_44INODEFMT) {
fs->fs_maxfilesize = ((uint64_t)1 << 31) - 1;
fs->fs_qbmask = ~fs->fs_bmask;
fs->fs_qfmask = ~fs->fs_fmask;
}
fs->fs_save_maxfilesize = fs->fs_maxfilesize;
maxfilesize = (uint64_t)0x80000000 * fs->fs_bsize - 1;
if (fs->fs_maxfilesize > maxfilesize)
fs->fs_maxfilesize = maxfilesize;
break;
}
if (fs->fs_avgfilesize <= 0)
fs->fs_avgfilesize = AVFILESIZ;
if (fs->fs_avgfpdir <= 0)
fs->fs_avgfpdir = AFPDIR;
}
void
ffs_oldfscompat_write(struct fs *fs)
{
switch (fs->fs_magic) {
case FS_UFS1_MAGIC:
if (fs->fs_sblockloc != SBLOCK_UFS1 &&
(fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
printf(
"WARNING: %s: correcting fs_sblockloc from %jd to %d\n",
fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1);
fs->fs_sblockloc = SBLOCK_UFS1;
}
fs->fs_old_time = fs->fs_time;
fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
if (fs->fs_save_maxfilesize != 0)
fs->fs_maxfilesize = fs->fs_save_maxfilesize;
break;
case FS_UFS2_MAGIC:
if (fs->fs_sblockloc != SBLOCK_UFS2 &&
(fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
printf(
"WARNING: %s: correcting fs_sblockloc from %jd to %d\n",
fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2);
fs->fs_sblockloc = SBLOCK_UFS2;
}
break;
}
}
static int prttimechgs = 0;
#ifdef _KERNEL
SYSCTL_NODE(_vfs, OID_AUTO, ffs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"FFS filesystem");
SYSCTL_INT(_vfs_ffs, OID_AUTO, prttimechgs, CTLFLAG_RWTUN, &prttimechgs, 0,
"print UFS1 time changes made to inodes");
#endif
bool
ffs_oldfscompat_inode_read(struct fs *fs, union dinodep dp, time_t now)
{
bool change;
change = false;
switch (fs->fs_magic) {
case FS_UFS2_MAGIC:
break;
case FS_UFS1_MAGIC:
if (dp.dp1->di_ctime > now) {
if (prttimechgs)
printf("ctime %ud changed to %ld\n",
dp.dp1->di_ctime, (long)now);
dp.dp1->di_ctime = now;
change = true;
}
if (dp.dp1->di_mtime > now) {
if (prttimechgs)
printf("mtime %ud changed to %ld\n",
dp.dp1->di_mtime, (long)now);
dp.dp1->di_mtime = now;
dp.dp1->di_ctime = now;
change = true;
}
if (dp.dp1->di_atime > now) {
if (prttimechgs)
printf("atime %ud changed to %ld\n",
dp.dp1->di_atime, (long)now);
dp.dp1->di_atime = now;
dp.dp1->di_ctime = now;
change = true;
}
break;
}
return (change);
}
#define ILOG2(num) (fls(num) - 1)
#ifdef STANDALONE_SMALL
#define MPRINT(...) do { } while (0)
#else
#define MPRINT(...) if (prtmsg) printf(__VA_ARGS__)
#endif
#define FCHK(lhs, op, rhs, fmt) \
if (lhs op rhs) { \
MPRINT("UFS%d superblock failed: %s (" #fmt ") %s %s (" \
#fmt ")\n", fs->fs_magic == FS_UFS1_MAGIC ? 1 : 2, \
#lhs, (intmax_t)lhs, #op, #rhs, (intmax_t)rhs); \
if (error < 0) \
return (ENOENT); \
if (error == 0) \
error = ENOENT; \
}
#define WCHK(lhs, op, rhs, fmt) \
if (lhs op rhs) { \
MPRINT("UFS%d superblock failed: %s (" #fmt ") %s %s (" \
#fmt ")%s\n", fs->fs_magic == FS_UFS1_MAGIC ? 1 : 2,\
#lhs, (intmax_t)lhs, #op, #rhs, (intmax_t)rhs, wmsg);\
if (error == 0) \
error = warnerr; \
if (warnerr == 0) \
lhs = rhs; \
}
#define FCHK2(lhs1, op1, rhs1, lhs2, op2, rhs2, fmt) \
if (lhs1 op1 rhs1 && lhs2 op2 rhs2) { \
MPRINT("UFS%d superblock failed: %s (" #fmt ") %s %s (" \
#fmt ") && %s (" #fmt ") %s %s (" #fmt ")\n", \
fs->fs_magic == FS_UFS1_MAGIC ? 1 : 2, #lhs1, \
(intmax_t)lhs1, #op1, #rhs1, (intmax_t)rhs1, #lhs2, \
(intmax_t)lhs2, #op2, #rhs2, (intmax_t)rhs2); \
if (error < 0) \
return (ENOENT); \
if (error == 0) \
error = ENOENT; \
}
static int
validate_sblock(struct fs *fs, int flags)
{
uint64_t i, sectorsize;
uint64_t maxfilesize, sizepb;
int error, prtmsg, warnerr;
char *wmsg;
error = 0;
sectorsize = dbtob(1);
prtmsg = ((flags & UFS_NOMSG) == 0);
warnerr = (flags & UFS_NOWARNFAIL) == UFS_NOWARNFAIL ? 0 : ENOENT;
wmsg = warnerr ? "" : " (Ignored)";
if (((fs->fs_magic != FS_UFS2_MAGIC) &&
(bswap32(fs->fs_magic) == FS_UFS2_MAGIC)) ||
((fs->fs_magic != FS_UFS1_MAGIC) &&
(bswap32(fs->fs_magic) == FS_UFS1_MAGIC))) {
MPRINT("UFS superblock failed due to endian mismatch "
"between machine and filesystem\n");
return(EILSEQ);
}
if ((flags & UFS_FSRONLY) == UFS_FSRONLY &&
(fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC)) {
error = -1;
if (fs->fs_magic == FS_UFS2_MAGIC) {
FCHK(fs->fs_sblockloc, !=, SBLOCK_UFS2, %#jx);
} else if (fs->fs_magic == FS_UFS1_MAGIC) {
FCHK(fs->fs_sblockloc, <, 0, %jd);
FCHK(fs->fs_sblockloc, >, SBLOCK_UFS1, %jd);
}
FCHK(fs->fs_frag, <, 1, %jd);
FCHK(fs->fs_frag, >, MAXFRAG, %jd);
FCHK(fs->fs_bsize, <, MINBSIZE, %jd);
FCHK(fs->fs_bsize, >, MAXBSIZE, %jd);
FCHK(fs->fs_bsize, <, roundup(sizeof(struct fs), DEV_BSIZE),
%jd);
FCHK(fs->fs_fsize, <, sectorsize, %jd);
FCHK(fs->fs_fsize * fs->fs_frag, !=, fs->fs_bsize, %jd);
FCHK(powerof2(fs->fs_fsize), ==, 0, %jd);
FCHK(fs->fs_sbsize, >, SBLOCKSIZE, %jd);
FCHK(fs->fs_sbsize, <, (signed)sizeof(struct fs), %jd);
FCHK(fs->fs_sbsize % sectorsize, !=, 0, %jd);
FCHK(fs->fs_fpg, <, 3 * fs->fs_frag, %jd);
FCHK(fs->fs_ncg, <, 1, %jd);
FCHK(fs->fs_fsbtodb, !=, ILOG2(fs->fs_fsize / sectorsize), %jd);
FCHK(fs->fs_old_cgoffset, <, 0, %jd);
FCHK2(fs->fs_old_cgoffset, >, 0, ~fs->fs_old_cgmask, <, 0, %jd);
FCHK(fs->fs_old_cgoffset * (~fs->fs_old_cgmask), >, fs->fs_fpg,
%jd);
FCHK(fs->fs_sblkno, !=, roundup(
howmany(fs->fs_sblockloc + SBLOCKSIZE, fs->fs_fsize),
fs->fs_frag), %jd);
FCHK(CGSIZE(fs), >, fs->fs_bsize, %jd);
if ((flags & UFS_NOCSUM) != 0)
return (error);
FCHK((uint64_t)fs->fs_ipg * fs->fs_ncg, >,
(((int64_t)(1)) << 32) - INOPB(fs), %jd);
FCHK(fs->fs_cstotal.cs_nifree, <, 0, %jd);
FCHK(fs->fs_cstotal.cs_nifree, >,
(uint64_t)fs->fs_ipg * fs->fs_ncg, %jd);
FCHK(fs->fs_cstotal.cs_ndir, >,
((uint64_t)fs->fs_ipg * fs->fs_ncg) -
fs->fs_cstotal.cs_nifree, %jd);
FCHK(fs->fs_size, <, 8 * fs->fs_frag, %jd);
FCHK(fs->fs_size, <=, ((int64_t)fs->fs_ncg - 1) * fs->fs_fpg,
%jd);
FCHK(fs->fs_size, >, (int64_t)fs->fs_ncg * fs->fs_fpg, %jd);
FCHK(fs->fs_csaddr, <, 0, %jd);
FCHK(fs->fs_cssize, !=,
fragroundup(fs, fs->fs_ncg * sizeof(struct csum)), %jd);
FCHK(fs->fs_csaddr + howmany(fs->fs_cssize, fs->fs_fsize), >,
fs->fs_size, %jd);
FCHK(fs->fs_csaddr, <, cgdmin(fs, dtog(fs, fs->fs_csaddr)),
%jd);
FCHK(dtog(fs, fs->fs_csaddr + howmany(fs->fs_cssize,
fs->fs_fsize)), >, dtog(fs, fs->fs_csaddr), %jd);
return (error);
}
if (fs->fs_magic == FS_UFS2_MAGIC) {
if ((flags & UFS_ALTSBLK) == 0)
FCHK2(fs->fs_sblockactualloc, !=, SBLOCK_UFS2,
fs->fs_sblockactualloc, !=, 0, %jd);
FCHK(fs->fs_sblockloc, !=, SBLOCK_UFS2, %#jx);
FCHK(fs->fs_maxsymlinklen, !=, ((UFS_NDADDR + UFS_NIADDR) *
sizeof(ufs2_daddr_t)), %jd);
FCHK(fs->fs_nindir, !=, fs->fs_bsize / sizeof(ufs2_daddr_t),
%jd);
FCHK(fs->fs_inopb, !=,
fs->fs_bsize / sizeof(struct ufs2_dinode), %jd);
} else if (fs->fs_magic == FS_UFS1_MAGIC) {
if ((flags & UFS_ALTSBLK) == 0)
FCHK(fs->fs_sblockactualloc, >, SBLOCK_UFS1, %jd);
FCHK(fs->fs_sblockloc, <, 0, %jd);
FCHK(fs->fs_sblockloc, >, SBLOCK_UFS1, %jd);
FCHK(fs->fs_nindir, !=, fs->fs_bsize / sizeof(ufs1_daddr_t),
%jd);
FCHK(fs->fs_inopb, !=,
fs->fs_bsize / sizeof(struct ufs1_dinode), %jd);
FCHK(fs->fs_maxsymlinklen, !=, ((UFS_NDADDR + UFS_NIADDR) *
sizeof(ufs1_daddr_t)), %jd);
WCHK(fs->fs_old_inodefmt, !=, FS_44INODEFMT, %jd);
WCHK(fs->fs_old_rotdelay, !=, 0, %jd);
WCHK(fs->fs_old_rps, !=, 60, %jd);
WCHK(fs->fs_old_nspf, !=, fs->fs_fsize / sectorsize, %jd);
WCHK(fs->fs_old_interleave, !=, 1, %jd);
WCHK(fs->fs_old_trackskew, !=, 0, %jd);
WCHK(fs->fs_old_cpc, !=, 0, %jd);
WCHK(fs->fs_old_postblformat, !=, 1, %jd);
FCHK(fs->fs_old_nrpos, !=, 1, %jd);
WCHK(fs->fs_old_nsect, !=, fs->fs_old_spc, %jd);
WCHK(fs->fs_old_npsect, !=, fs->fs_old_spc, %jd);
} else {
return (ENOENT);
}
FCHK(fs->fs_bsize, <, MINBSIZE, %jd);
FCHK(fs->fs_bsize, >, MAXBSIZE, %jd);
FCHK(fs->fs_bsize, <, roundup(sizeof(struct fs), DEV_BSIZE), %jd);
FCHK(powerof2(fs->fs_bsize), ==, 0, %jd);
FCHK(fs->fs_frag, <, 1, %jd);
FCHK(fs->fs_frag, >, MAXFRAG, %jd);
FCHK(fs->fs_frag, !=, numfrags(fs, fs->fs_bsize), %jd);
FCHK(fs->fs_fsize, <, sectorsize, %jd);
FCHK(fs->fs_fsize * fs->fs_frag, !=, fs->fs_bsize, %jd);
FCHK(powerof2(fs->fs_fsize), ==, 0, %jd);
FCHK(fs->fs_fpg, <, 3 * fs->fs_frag, %jd);
FCHK(fs->fs_ncg, <, 1, %jd);
FCHK(fs->fs_ipg, <, fs->fs_inopb, %jd);
FCHK((uint64_t)fs->fs_ipg * fs->fs_ncg, >,
(((int64_t)(1)) << 32) - INOPB(fs), %jd);
FCHK(fs->fs_cstotal.cs_nifree, <, 0, %jd);
FCHK(fs->fs_cstotal.cs_nifree, >, (uint64_t)fs->fs_ipg * fs->fs_ncg,
%jd);
FCHK(fs->fs_cstotal.cs_ndir, <, 0, %jd);
FCHK(fs->fs_cstotal.cs_ndir, >,
((uint64_t)fs->fs_ipg * fs->fs_ncg) - fs->fs_cstotal.cs_nifree,
%jd);
FCHK(fs->fs_sbsize, >, SBLOCKSIZE, %jd);
FCHK(fs->fs_sbsize, <, (signed)sizeof(struct fs), %jd);
if (fs->fs_maxbsize == 0)
fs->fs_maxbsize = fs->fs_bsize;
FCHK(fs->fs_maxbsize, <, fs->fs_bsize, %jd);
FCHK(powerof2(fs->fs_maxbsize), ==, 0, %jd);
FCHK(fs->fs_maxbsize, >, FS_MAXCONTIG * fs->fs_bsize, %jd);
FCHK(fs->fs_bmask, !=, ~(fs->fs_bsize - 1), %#jx);
FCHK(fs->fs_fmask, !=, ~(fs->fs_fsize - 1), %#jx);
FCHK(fs->fs_qbmask, !=, ~fs->fs_bmask, %#jx);
FCHK(fs->fs_qfmask, !=, ~fs->fs_fmask, %#jx);
FCHK(fs->fs_bshift, !=, ILOG2(fs->fs_bsize), %jd);
FCHK(fs->fs_fshift, !=, ILOG2(fs->fs_fsize), %jd);
FCHK(fs->fs_fragshift, !=, ILOG2(fs->fs_frag), %jd);
FCHK(fs->fs_fsbtodb, !=, ILOG2(fs->fs_fsize / sectorsize), %jd);
FCHK(fs->fs_old_cgoffset, <, 0, %jd);
FCHK2(fs->fs_old_cgoffset, >, 0, ~fs->fs_old_cgmask, <, 0, %jd);
FCHK(fs->fs_old_cgoffset * (~fs->fs_old_cgmask), >, fs->fs_fpg, %jd);
FCHK(CGSIZE(fs), >, fs->fs_bsize, %jd);
if (error)
return (error);
FCHK(fs->fs_sbsize % sectorsize, !=, 0, %jd);
FCHK(fs->fs_ipg % fs->fs_inopb, !=, 0, %jd);
FCHK(fs->fs_sblkno, !=, roundup(
howmany(fs->fs_sblockloc + SBLOCKSIZE, fs->fs_fsize),
fs->fs_frag), %jd);
FCHK(fs->fs_cblkno, !=, fs->fs_sblkno +
roundup(howmany(SBLOCKSIZE, fs->fs_fsize), fs->fs_frag), %jd);
FCHK(fs->fs_iblkno, !=, fs->fs_cblkno + fs->fs_frag, %jd);
FCHK(fs->fs_dblkno, !=, fs->fs_iblkno + fs->fs_ipg / INOPF(fs), %jd);
FCHK(fs->fs_cgsize, >, fs->fs_bsize, %jd);
FCHK(fs->fs_cgsize, <, fs->fs_fsize, %jd);
FCHK(fs->fs_cgsize % fs->fs_fsize, !=, 0, %jd);
#ifdef notdef
WCHK(fs->fs_dsize, !=, fs->fs_size - fs->fs_sblkno -
fs->fs_ncg * (fs->fs_dblkno - fs->fs_sblkno) -
howmany(fs->fs_cssize, fs->fs_fsize), %jd);
#endif
WCHK(fs->fs_metaspace, <, 0, %jd);
WCHK(fs->fs_metaspace, >, fs->fs_fpg / 2, %jd);
WCHK(fs->fs_minfree, >, 99, %jd%%);
maxfilesize = fs->fs_bsize * UFS_NDADDR - 1;
for (sizepb = fs->fs_bsize, i = 0; i < UFS_NIADDR; i++) {
sizepb *= NINDIR(fs);
maxfilesize += sizepb;
}
WCHK(fs->fs_maxfilesize, >, maxfilesize, %jd);
FCHK(fs->fs_size, <, 8 * fs->fs_frag, %jd);
FCHK(fs->fs_size, <=, ((int64_t)fs->fs_ncg - 1) * fs->fs_fpg, %jd);
FCHK(fs->fs_size, >, (int64_t)fs->fs_ncg * fs->fs_fpg, %jd);
if ((flags & UFS_NOCSUM) != 0)
return (error);
FCHK(fs->fs_csaddr, <, 0, %jd);
FCHK(fs->fs_cssize, !=,
fragroundup(fs, fs->fs_ncg * sizeof(struct csum)), %jd);
FCHK(fs->fs_csaddr + howmany(fs->fs_cssize, fs->fs_fsize), >,
fs->fs_size, %jd);
FCHK(fs->fs_csaddr, <, cgdmin(fs, dtog(fs, fs->fs_csaddr)), %jd);
FCHK(dtog(fs, fs->fs_csaddr + howmany(fs->fs_cssize, fs->fs_fsize)), >,
dtog(fs, fs->fs_csaddr), %jd);
WCHK(fs->fs_maxcontig, <, 0, %jd);
WCHK(fs->fs_maxcontig, >, MAX(256, maxphys / fs->fs_bsize), %jd);
FCHK2(fs->fs_maxcontig, ==, 0, fs->fs_contigsumsize, !=, 0, %jd);
FCHK2(fs->fs_maxcontig, >, 1, fs->fs_contigsumsize, !=,
MIN(fs->fs_maxcontig, FS_MAXCONTIG), %jd);
return (error);
}
int
ffs_sbsearch(void *devfd, struct fs **fsp, int reqflags,
struct malloc_type *filltype,
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
{
struct fsrecovery *fsr;
struct fs *protofs;
void *fsrbuf;
char *cp;
long nocsum, flags, msg, cg;
off_t sblk, secsize;
int error;
msg = (reqflags & UFS_NOMSG) == 0;
nocsum = reqflags & UFS_NOCSUM;
flags = UFS_NOMSG | nocsum;
error = ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc);
if (error == 0 || error == EILSEQ) {
if (msg && error == EILSEQ)
printf("UFS superblock failed due to endian mismatch "
"between machine and filesystem\n");
return (error);
}
flags |= UFS_NOHASHFAIL;
if (msg)
flags &= ~UFS_NOMSG;
if (ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc) == 0)
return (0);
if (msg)
printf("Attempted recovery for standard superblock: failed\n");
flags = UFS_FSRONLY | UFS_NOHASHFAIL | UFS_NOCSUM | UFS_NOMSG;
if (ffs_sbget(devfd, &protofs, UFS_STDSB, flags, filltype,
readfunc) == 0) {
if (msg)
printf("Attempt extraction of recovery data from "
"standard superblock.\n");
} else {
if (msg)
printf("Attempted extraction of recovery data from "
"standard superblock: failed\nAttempt to find "
"boot zone recovery data.\n");
error = ENOENT;
fsrbuf = NULL;
for (secsize = dbtob(1); secsize <= SBLOCKSIZE; secsize *= 2)
if ((error = (*readfunc)(devfd, (SBLOCK_UFS2 - secsize),
&fsrbuf, secsize)) == 0)
break;
if (error != 0)
goto trynowarn;
cp = fsrbuf;
fsr = (struct fsrecovery *)&cp[secsize - sizeof *fsr];
if (fsr->fsr_magic != FS_UFS2_MAGIC ||
(protofs = UFS_MALLOC(SBLOCKSIZE, filltype, M_NOWAIT))
== NULL) {
UFS_FREE(fsrbuf, filltype);
goto trynowarn;
}
memset(protofs, 0, sizeof(struct fs));
protofs->fs_fpg = fsr->fsr_fpg;
protofs->fs_fsbtodb = fsr->fsr_fsbtodb;
protofs->fs_sblkno = fsr->fsr_sblkno;
protofs->fs_magic = fsr->fsr_magic;
protofs->fs_ncg = fsr->fsr_ncg;
UFS_FREE(fsrbuf, filltype);
}
flags = nocsum;
if (!msg)
flags |= UFS_NOMSG;
for (cg = 0; cg < protofs->fs_ncg; cg++) {
sblk = fsbtodb(protofs, cgsblock(protofs, cg));
if (msg)
printf("Try cg %ld at sblock loc %jd\n", cg,
(intmax_t)sblk);
if (ffs_sbget(devfd, fsp, dbtob(sblk), flags, filltype,
readfunc) == 0) {
if (msg)
printf("Succeeded with alternate superblock "
"at %jd\n", (intmax_t)sblk);
UFS_FREE(protofs, filltype);
return (0);
}
}
UFS_FREE(protofs, filltype);
trynowarn:
flags = UFS_NOWARNFAIL | UFS_NOMSG | nocsum;
if (msg) {
printf("Finding an alternate superblock failed.\nCheck for "
"only non-critical errors in standard superblock\n");
flags &= ~UFS_NOMSG;
}
if (ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc) != 0) {
if (msg)
printf("Failed, superblock has critical errors\n");
return (ENOENT);
}
if (msg)
printf("Success, using standard superblock with "
"non-critical errors.\n");
return (0);
}
int
ffs_sbput(void *devfd, struct fs *fs, off_t loc,
int (*writefunc)(void *devfd, off_t loc, void *buf, int size))
{
struct fs_summary_info *fs_si;
int i, error, blks, size;
uint8_t *space;
if (fs->fs_si != NULL && fs->fs_csp != NULL) {
blks = howmany(fs->fs_cssize, fs->fs_fsize);
space = (uint8_t *)fs->fs_csp;
for (i = 0; i < blks; i += fs->fs_frag) {
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;
ffs_oldfscompat_write(fs);
#ifdef _KERNEL
fs->fs_time = time_second;
#else
fs->fs_time = time(NULL);
#endif
fs_si = fs->fs_si;
fs->fs_si = NULL;
fs->fs_ckhash = ffs_calc_sbhash(fs);
error = (*writefunc)(devfd, loc, fs, fs->fs_sbsize);
if (error < 0)
return (-error - 1);
fs->fs_si = fs_si;
return (error);
}
uint32_t
ffs_calc_sbhash(struct fs *fs)
{
uint32_t ckhash, save_ckhash;
if ((fs->fs_metackhash & CK_SUPERBLOCK) == 0)
return (fs->fs_ckhash);
save_ckhash = fs->fs_ckhash;
fs->fs_ckhash = 0;
ckhash = calculate_crc32c(~0L, (void *)fs, fs->fs_sbsize);
fs->fs_ckhash = save_ckhash;
return (ckhash);
}
void
ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt)
{
int inblk;
int field, subfield;
int siz, pos;
inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
fragmap <<= 1;
for (siz = 1; siz < fs->fs_frag; siz++) {
if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
continue;
field = around[siz];
subfield = inside[siz];
for (pos = siz; pos <= fs->fs_frag; pos++) {
if ((fragmap & field) == subfield) {
fraglist[siz] += cnt;
pos += siz;
field <<= siz;
subfield <<= siz;
}
field <<= 1;
subfield <<= 1;
}
}
}
int
ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
{
unsigned char mask;
switch ((int)fs->fs_frag) {
case 8:
return (cp[h] == 0xff);
case 4:
mask = 0x0f << ((h & 0x1) << 2);
return ((cp[h >> 1] & mask) == mask);
case 2:
mask = 0x03 << ((h & 0x3) << 1);
return ((cp[h >> 2] & mask) == mask);
case 1:
mask = 0x01 << (h & 0x7);
return ((cp[h >> 3] & mask) == mask);
default:
#ifdef _KERNEL
panic("ffs_isblock");
#endif
break;
}
return (0);
}
int
ffs_isfreeblock(struct fs *fs, uint8_t *cp, ufs1_daddr_t h)
{
switch ((int)fs->fs_frag) {
case 8:
return (cp[h] == 0);
case 4:
return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
case 2:
return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
case 1:
return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
default:
#ifdef _KERNEL
panic("ffs_isfreeblock");
#endif
break;
}
return (0);
}
void
ffs_clrblock(struct fs *fs, uint8_t *cp, ufs1_daddr_t h)
{
switch ((int)fs->fs_frag) {
case 8:
cp[h] = 0;
return;
case 4:
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
return;
case 2:
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
return;
case 1:
cp[h >> 3] &= ~(0x01 << (h & 0x7));
return;
default:
#ifdef _KERNEL
panic("ffs_clrblock");
#endif
break;
}
}
void
ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
{
switch ((int)fs->fs_frag) {
case 8:
cp[h] = 0xff;
return;
case 4:
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
return;
case 2:
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
return;
case 1:
cp[h >> 3] |= (0x01 << (h & 0x7));
return;
default:
#ifdef _KERNEL
panic("ffs_setblock");
#endif
break;
}
}
void
ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt)
{
int32_t *sump;
int32_t *lp;
uint8_t *freemapp, *mapp;
int i, start, end, forw, back, map;
uint64_t bit;
if (fs->fs_contigsumsize <= 0)
return;
freemapp = cg_clustersfree(cgp);
sump = cg_clustersum(cgp);
if (cnt > 0)
setbit(freemapp, blkno);
else
clrbit(freemapp, blkno);
start = blkno + 1;
end = start + fs->fs_contigsumsize;
if (end >= cgp->cg_nclusterblks)
end = cgp->cg_nclusterblks;
mapp = &freemapp[start / NBBY];
map = *mapp++;
bit = 1U << (start % NBBY);
for (i = start; i < end; i++) {
if ((map & bit) == 0)
break;
if ((i & (NBBY - 1)) != (NBBY - 1)) {
bit <<= 1;
} else {
map = *mapp++;
bit = 1;
}
}
forw = i - start;
start = blkno - 1;
end = start - fs->fs_contigsumsize;
if (end < 0)
end = -1;
mapp = &freemapp[start / NBBY];
map = *mapp--;
bit = 1U << (start % NBBY);
for (i = start; i > end; i--) {
if ((map & bit) == 0)
break;
if ((i & (NBBY - 1)) != 0) {
bit >>= 1;
} else {
map = *mapp--;
bit = 1U << (NBBY - 1);
}
}
back = start - i;
i = back + forw + 1;
if (i > fs->fs_contigsumsize)
i = fs->fs_contigsumsize;
sump[i] += cnt;
if (back > 0)
sump[back] -= cnt;
if (forw > 0)
sump[forw] -= cnt;
lp = &sump[fs->fs_contigsumsize];
for (i = fs->fs_contigsumsize; i > 0; i--)
if (*lp-- > 0)
break;
fs->fs_maxcluster[cgp->cg_cgx] = i;
}