2002-03-17 19:14:30 +03:00
|
|
|
/* from Id: readufs_lfs.c,v 1.5 2002/01/26 16:26:44 itohy Exp */
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FS specific support for 4.4BSD Log-structured Filesystem
|
|
|
|
*
|
|
|
|
* Written by ITOH, Yasufumi (itohy@netbsd.org).
|
|
|
|
* Public domain.
|
|
|
|
*
|
|
|
|
* Intended to be used for boot programs (first stage).
|
|
|
|
* DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <ufs/ufs/dinode.h>
|
|
|
|
#include <ufs/lfs/lfs.h>
|
|
|
|
|
|
|
|
#include "readufs.h"
|
|
|
|
|
|
|
|
static int get_lfs_inode __P((ino_t ino, struct dinode *dibuf));
|
|
|
|
|
|
|
|
static struct dinode ifile_dinode;
|
|
|
|
|
|
|
|
#define fsi (*ufsinfo)
|
|
|
|
#define fsi_lfs fsi.fs_u.u_lfs
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read and check superblock.
|
|
|
|
* If it is an LFS, save information from the superblock.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
try_lfs()
|
|
|
|
{
|
2002-03-17 19:14:30 +03:00
|
|
|
struct ufs_info *ufsinfo = &ufs_info;
|
2001-09-27 14:14:49 +04:00
|
|
|
struct dlfs sblk, sblk2;
|
|
|
|
struct dlfs *s = &sblk;
|
2002-03-17 19:14:30 +03:00
|
|
|
ufs_daddr_t sbpos;
|
|
|
|
int fsbshift;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("trying LFS\n");
|
|
|
|
#endif
|
2002-03-17 19:14:30 +03:00
|
|
|
sbpos = btodb(LFS_LABELPAD);
|
|
|
|
|
2001-09-27 14:14:49 +04:00
|
|
|
/* read primary superblock */
|
2002-03-17 19:14:30 +03:00
|
|
|
for (;;) {
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS: reading primary sblk at: 0x%x\n", sbpos);
|
|
|
|
#endif
|
|
|
|
RAW_READ(&sblk, sbpos, sizeof sblk);
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
2002-03-17 19:14:30 +03:00
|
|
|
printf("LFS: sblk: magic: 0x%x, version: %d\n",
|
|
|
|
sblk.dlfs_magic, sblk.dlfs_version);
|
2001-09-27 14:14:49 +04:00
|
|
|
#endif
|
|
|
|
|
2002-03-17 19:14:30 +03:00
|
|
|
if (sblk.dlfs_magic != LFS_MAGIC)
|
|
|
|
return 1;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
2002-03-17 19:14:30 +03:00
|
|
|
printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n",
|
|
|
|
sblk.dlfs_bsize, sblk.dlfs_fsize,
|
|
|
|
sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb,
|
|
|
|
sblk.dlfs_inopf, sblk.dlfs_inopb);
|
|
|
|
#endif
|
|
|
|
if ((fsi_lfs.version = sblk.dlfs_version) == 1) {
|
|
|
|
fsbshift = 0;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ufs_daddr_t sbpos1;
|
|
|
|
#if 0
|
|
|
|
fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT;
|
|
|
|
#endif
|
|
|
|
fsbshift = sblk.dlfs_fsbtodb;
|
|
|
|
sbpos1 = sblk.dlfs_sboffs[0] << fsbshift;
|
|
|
|
if (sbpos == sbpos1)
|
|
|
|
break;
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS: correcting primary sblk location\n");
|
|
|
|
#endif
|
|
|
|
sbpos = sbpos1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("fsbshift: %d\n", fsbshift);
|
2001-09-27 14:14:49 +04:00
|
|
|
printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (sblk.dlfs_sboffs[1] > 0) {
|
2002-03-17 19:14:30 +03:00
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS: reading secondary sblk at: 0x%x\n",
|
|
|
|
sblk.dlfs_sboffs[1] << fsbshift);
|
|
|
|
#endif
|
2001-09-27 14:14:49 +04:00
|
|
|
/* read secondary superblock */
|
2002-03-17 19:14:30 +03:00
|
|
|
RAW_READ(&sblk2, sblk.dlfs_sboffs[1] << fsbshift, sizeof sblk2);
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS: sblk2: magic: 0x%x, version: %d\n",
|
|
|
|
sblk2.dlfs_magic, sblk2.dlfs_version);
|
|
|
|
#endif
|
|
|
|
|
2002-03-17 19:14:30 +03:00
|
|
|
if (sblk2.dlfs_magic == LFS_MAGIC) {
|
|
|
|
if (fsi_lfs.version == 1) {
|
|
|
|
if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp)
|
|
|
|
s = &sblk2;
|
|
|
|
} else {
|
|
|
|
if (sblk.dlfs_serial > sblk2.dlfs_serial)
|
|
|
|
s = &sblk2;
|
|
|
|
}
|
|
|
|
}
|
2001-09-27 14:14:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This partition looks like an LFS. */
|
|
|
|
fsi.get_inode = get_lfs_inode;
|
2002-03-17 19:14:30 +03:00
|
|
|
/*
|
|
|
|
* version 1: disk addr is in disk sector --- no shifting
|
|
|
|
* version 2: disk addr is in fragment
|
|
|
|
*/
|
|
|
|
fsi.fsbtodb = fsbshift;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
/* Get information from the superblock. */
|
|
|
|
fsi.bsize = s->dlfs_bsize;
|
|
|
|
fsi.nindir = s->dlfs_nindir;
|
|
|
|
fsi_lfs.idaddr = s->dlfs_idaddr;
|
2002-03-17 19:14:30 +03:00
|
|
|
#if 0
|
|
|
|
fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize;
|
|
|
|
#else /* simplify calculation to reduce code size */
|
|
|
|
/* use fsi.bsize (larger then needed for v2, but probably no harm) */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* version 1: number of inode per block
|
|
|
|
* version 2: number of inode per fragment (but in dlfs_inopb)
|
|
|
|
*/
|
2001-09-27 14:14:49 +04:00
|
|
|
fsi_lfs.inopb = s->dlfs_inopb;
|
2002-03-17 19:14:30 +03:00
|
|
|
|
2001-09-27 14:14:49 +04:00
|
|
|
fsi_lfs.ifpb = s->dlfs_ifpb;
|
2002-03-17 19:14:30 +03:00
|
|
|
fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
/* ifile is always used to look-up other inodes, so keep its inode. */
|
|
|
|
if (get_lfs_inode(LFS_IFILE_INUM, &ifile_dinode))
|
|
|
|
return 1; /* OOPS, failed to find inode of ifile! */
|
|
|
|
|
|
|
|
fsi.fstype = UFSTYPE_LFS;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get inode from disk.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
get_lfs_inode(ino, dibuf)
|
|
|
|
ino_t ino;
|
|
|
|
struct dinode *dibuf;
|
|
|
|
{
|
|
|
|
struct ufs_info *ufsinfo = &ufs_info;
|
|
|
|
ufs_daddr_t daddr;
|
|
|
|
char *buf = alloca(fsi.bsize);
|
2002-03-17 19:14:30 +03:00
|
|
|
struct dinode *di, *diend;
|
|
|
|
int i;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
/* Get fs block which contains the specified inode. */
|
|
|
|
if (ino == LFS_IFILE_INUM)
|
|
|
|
daddr = fsi_lfs.idaddr;
|
|
|
|
else {
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
2002-03-17 19:14:30 +03:00
|
|
|
printf("LFS: ino: %d\nifpb: %d, bsize: %d\n",
|
|
|
|
ino, fsi_lfs.ifpb, fsi.bsize);
|
2001-09-27 14:14:49 +04:00
|
|
|
#endif
|
|
|
|
ufs_read(&ifile_dinode, buf,
|
2002-03-17 19:14:30 +03:00
|
|
|
ino / fsi_lfs.ifpb + fsi_lfs.ioffset,
|
2001-09-27 14:14:49 +04:00
|
|
|
fsi.bsize);
|
2002-03-17 19:14:30 +03:00
|
|
|
i = ino % fsi_lfs.ifpb;
|
|
|
|
daddr = (fsi_lfs.version == 1) ?
|
|
|
|
((IFILE_V1 *) buf + i)->if_daddr
|
|
|
|
: ((IFILE *) buf + i)->if_daddr;
|
2001-09-27 14:14:49 +04:00
|
|
|
}
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS(%d): daddr: %d\n", ino, daddr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (daddr == LFS_UNUSED_DADDR)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Read the inode block. */
|
2002-03-17 19:14:30 +03:00
|
|
|
RAW_READ(buf, daddr << fsi.fsbtodb,
|
|
|
|
#if 0
|
|
|
|
fsi_lfs.ibsize
|
|
|
|
#else /* simplify calculation to reduce code size */
|
|
|
|
fsi.bsize
|
|
|
|
#endif
|
|
|
|
);
|
2001-09-27 14:14:49 +04:00
|
|
|
|
|
|
|
/* Search for the inode. */
|
2002-03-17 19:14:30 +03:00
|
|
|
di = (struct dinode *) buf;
|
|
|
|
diend = di + fsi_lfs.inopb;
|
2001-09-27 14:14:49 +04:00
|
|
|
|
2002-03-17 19:14:30 +03:00
|
|
|
for ( ; di < diend; di++)
|
2001-09-27 14:14:49 +04:00
|
|
|
if (di->di_inumber == ino)
|
|
|
|
goto found;
|
|
|
|
/* not found */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
found:
|
|
|
|
#ifdef DEBUG_WITH_STDIO
|
|
|
|
printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, gid %d, db[0] %d\n",
|
|
|
|
ino, di->di_mode, di->di_nlink, di->di_inumber,
|
|
|
|
(int)di->di_size, di->di_uid, di->di_gid, di->di_db[0]);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
*dibuf = *di;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|