CFR patch to improve fsdb sparse file handling
Kirk McKusick
mckusick at mckusick.com
Wed Feb 1 06:14:12 UTC 2012
Your change looks reasonable to me.
A more elaborate (e.g., compact listing) scheme that I wrote
for printing out block numbers is given below. Not sure if it
is worth adapting to use in fsdb.
Kirk McKusick
=-=-=
/*
* Copyright (c) 1998 Marshall Kirk McKusick. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/disklabel.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
union dinode {
struct ufs1_dinode *dp1;
struct ufs2_dinode *dp2;
};
struct fs *sbp;
char *fsname;
int fd;
void indirprt(int blksperindir, int lbn, ufs2_daddr_t blkno, int lastlbn);
void printblk(int lbn, ufs2_daddr_t blkno, int numblks, int lastlbn);
/*
* Possible superblock locations ordered from most to least likely.
*/
static int sblock_try[] = SBLOCKSEARCH;
int
main(argc, argv)
int argc;
char *argv[];
{
int i, len, lbn, frags, inonum, numblks, blksperindir;
char sblock[SBLOCKSIZE], ibuf[MAXBSIZE];
ufs2_daddr_t blkno;
off_t size, offset;
union dinode dp;
if (argc < 3) {
(void)fprintf(stderr,"usage: prtblknos filesystem inode ...\n");
exit(1);
}
fsname = *++argv;
/* get the superblock. */
if ((fd = open(fsname, O_RDONLY, 0)) < 0)
err(1, "%s", fsname);
for (i = 0; sblock_try[i] != -1; i++) {
if (lseek(fd, sblock_try[i], SEEK_SET) < 0)
err(1, "lseek: %s", fsname);
if (read(fd, sblock, (long)SBLOCKSIZE) != SBLOCKSIZE)
err(1, "can't read superblock: %s", fsname);
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 >= sizeof(struct fs))
break;
}
if (sblock_try[i] == -1)
errx(1, "Cannot find file system superblock\n");
/* remaining arguments are inode numbers. */
while (*++argv) {
/* get the inode number. */
if ((inonum = atoi(*argv)) <= 0)
errx(1, "%s is not a valid inode number", *argv);
(void)printf("%d:", 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 *= DEV_BSIZE; /* disk blk to bytes */
/* seek and read the block */
if (lseek(fd, offset, SEEK_SET) < 0)
err(1, "%s", fsname);
if (read(fd, ibuf, sbp->fs_bsize) != sbp->fs_bsize)
err(1, "%s", fsname);
/* get the inode within the block. */
if (sbp->fs_magic == FS_UFS1_MAGIC) {
dp.dp1 = &((struct ufs1_dinode *)(ibuf))
[ino_to_fsbo(sbp, inonum)];
size = dp.dp1->di_size;
} else {
dp.dp2 = &((struct ufs2_dinode *)(ibuf))
[ino_to_fsbo(sbp, inonum)];
size = dp.dp2->di_size;
}
numblks = howmany(size, sbp->fs_bsize);
if (numblks == 0) {
printf(" empty file\n");
continue;
}
len = numblks < NDADDR ? numblks : NDADDR;
for (i = 0; i < len; i++) {
if (i < numblks - 1)
frags = sbp->fs_frag;
else
frags = howmany(size % sbp->fs_bsize,
sbp->fs_fsize);
if (sbp->fs_magic == FS_UFS1_MAGIC)
blkno = dp.dp1->di_db[i];
else
blkno = dp.dp2->di_db[i];
printblk(i, blkno, frags, numblks);
}
blksperindir = 1;
len = numblks - NDADDR;
lbn = NDADDR;
for (i = 0; len > 0 && i < NIADDR; i++) {
if (sbp->fs_magic == FS_UFS1_MAGIC)
blkno = dp.dp1->di_ib[i];
else
blkno = dp.dp2->di_ib[i];
indirprt(blksperindir, lbn, blkno, numblks);
blksperindir *= NINDIR(sbp);
lbn += blksperindir;
len -= blksperindir;
}
/* dummy print to hopefully flush out last extent */
printblk(numblks, 0, frags, numblks);
}
(void)close(fd);
exit(0);
}
void
indirprt(blksperindir, lbn, blkno, lastlbn)
int blksperindir;
int lbn;
ufs2_daddr_t blkno;
int lastlbn;
{
char indir[MAXBSIZE];
off_t offset;
int i, last;
/* read in the indirect block. */
offset = fsbtodb(sbp, blkno); /* fs blk disk blk */
offset *= DEV_BSIZE; /* disk blk to bytes */
if (lseek(fd, offset, SEEK_SET) < 0)
err(1, "%s", fsname);
if (read(fd, indir, sbp->fs_bsize) != sbp->fs_bsize)
err(1, "%s", fsname);
last = howmany(lastlbn - lbn, blksperindir) < NINDIR(sbp) ?
howmany(lastlbn - lbn, blksperindir) : NINDIR(sbp);
if (blksperindir == 1) {
for (i = 0; i < last; i++) {
if (sbp->fs_magic == FS_UFS1_MAGIC)
blkno = ((ufs1_daddr_t *)indir)[i];
else
blkno = ((ufs2_daddr_t *)indir)[i];
printblk(lbn + i, blkno, sbp->fs_frag, lastlbn);
}
return;
}
for (i = 0; i < last; i++) {
if (sbp->fs_magic == FS_UFS1_MAGIC)
blkno = ((ufs1_daddr_t *)indir)[i];
else
blkno = ((ufs2_daddr_t *)indir)[i];
indirprt(blksperindir / NINDIR(sbp), lbn + blksperindir * i,
blkno, lastlbn);
}
}
void
printblk(lbn, blkno, numblks, lastlbn)
int lbn;
ufs2_daddr_t blkno;
int numblks;
int lastlbn;
{
static int seq;
static daddr_t firstblk;
if (lbn == 0) {
seq = 1;
firstblk = blkno;
return;
}
if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
(firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
(firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
blkno == firstblk + seq * numblks)) {
seq++;
return;
}
if (firstblk <= BLK_SNAP) {
if (seq == 1)
printf("\tlbn %d %s\n", lbn - seq,
firstblk == 0 ? "hole" :
firstblk == BLK_NOCOPY ? "nocopy" :
"snapblk");
else
printf("\tlbn %d-%d %s\n",
lbn - seq, lbn - 1,
firstblk == 0 ? "hole" :
firstblk == BLK_NOCOPY ? "nocopy" :
"snapblk");
seq = 1;
firstblk = blkno;
return;
}
if (seq == 1) {
if (numblks == 1)
printf("\tlbn %d blkno %jd\n", lbn - seq,
(intmax_t)firstblk);
else
printf("\tlbn %d blkno %jd-%jd\n", lbn - seq,
(intmax_t)firstblk,
(intmax_t)(firstblk + numblks - 1));
firstblk = blkno;
return;
}
printf("\tlbn %d-%d blkno %jd-%jd\n", lbn - seq, lbn - 1,
(intmax_t)firstblk,
(intmax_t)(firstblk + (seq - 1) * sbp->fs_frag + numblks - 1));
seq = 1;
firstblk = blkno;
}
More information about the freebsd-fs
mailing list