From owner-freebsd-fs@FreeBSD.ORG Wed Feb 1 06:14:12 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8B73C1065672; Wed, 1 Feb 2012 06:14:12 +0000 (UTC) (envelope-from mckusick@mckusick.com) Received: from chez.mckusick.com (unknown [IPv6:2001:5a8:4:7e72:4a5b:39ff:fe12:452]) by mx1.freebsd.org (Postfix) with ESMTP id 457C38FC08; Wed, 1 Feb 2012 06:14:12 +0000 (UTC) Received: from chez.mckusick.com (localhost [127.0.0.1]) by chez.mckusick.com (8.14.3/8.14.3) with ESMTP id q116E4Fo057942; Tue, 31 Jan 2012 22:14:04 -0800 (PST) (envelope-from mckusick@chez.mckusick.com) Message-Id: <201202010614.q116E4Fo057942@chez.mckusick.com> To: Don Lewis In-reply-to: <201202010100.q1110pfM092973@gw.catspoiler.org> Date: Tue, 31 Jan 2012 22:14:04 -0800 From: Kirk McKusick X-Spam-Status: No, score=0.0 required=5.0 tests=MISSING_MID, UNPARSEABLE_RELAY autolearn=failed version=3.2.5 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on chez.mckusick.com Cc: freebsd-fs@freebsd.org Subject: Re: CFR patch to improve fsdb sparse file handling X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Feb 2012 06:14:12 -0000 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 #include #include #include #include #include #include #include #include #include #include #include #include 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; }