Index: head/sbin/ffsinfo/ffsinfo.8 =================================================================== --- head/sbin/ffsinfo/ffsinfo.8 (revision 69925) +++ head/sbin/ffsinfo/ffsinfo.8 (revision 69926) @@ -1,132 +1,137 @@ .\" Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz .\" Copyright (c) 1980, 1989, 1993 The Regents of the University of California. .\" All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. .\" .\" 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. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgment: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors, as well as Christoph .\" Herrmann and Thomas-Henning von Kamptz. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. .\" -.\" $TSHeader: src/sbin/ffsinfo/ffsinfo.8,v 1.2 2000/12/09 15:12:31 tomsoft Exp $ +.\" $TSHeader: src/sbin/ffsinfo/ffsinfo.8,v 1.3 2000/12/12 19:30:55 tomsoft Exp $ .\" $FreeBSD$ .\" .Dd September 8, 2000 .Dt FSINFO 8 .Os BSD 4.4 .Sh NAME .Nm ffsinfo .Nd dump all meta information of an existing ufs file system .Sh SYNOPSIS .Nm ffsinfo .Op Fl L .Op Fl g Ar cylinder group .Op Fl i Ar inode .Op Fl l Ar level .Op Fl o Ar outfile -.Ar < special | file > +.Ar special | file .Sh DESCRIPTION .Nm Ffsinfo extends the .Xr dumpfs 8 program. .Pp The output is generated into the file -.Nm outfile . -Also expect the output file to be rather large. Up to 2 percent of the size -of the specified filesystem is not uncommon. -.Nm Ffsinfo -has some options to allow the defaults to be overridden. +.Pa outfile . +Also expect the output file to be rather large. +Up to 2 percent of the size of the specified filesystem is not uncommon. +.Pp +The following options are available: .\".Pp .Bl -tag -width indent .It Fl L -Specifying this options skips the tests of the disklabel. This is automatically -done, if the specified filename to dump is a plain file. +Specifying this option skips the tests of the disklabel. +This is done automatically, if the specified filename to dump is a plain file. .It Fl g Ar cylinder group -This restrictes the dump to infomation about this cylinder group only. Here -0 means the first cylinder group and -1 the last one. +This restricts the dump to infomation about this cylinder group only. +Here 0 means the first cylinder group and -1 the last one. .It Fl i Ar inode -This restrictes the dump to infomation about this particular inode only. Here -the minimum acceptable inode is 2. If this option is omitted but a cylinder -group is defined then only inodes within that cylinder group are dumped. +This restrictes the dump to infomation about this particular inode only. +Here the minimum acceptable inode is 2. +If this option is omitted but a cylinder group is defined then only inodes +within that cylinder group are dumped. .It Fl l Ar level -The level of detail which will be dumped. This value defaults -to 255 and is the bitwise and of the following table: +The level of detail which will be dumped. +This value defaults to 255 and is the bitwise and of the following table: .Bd -literal -offset left 0x001 - initial superblock 0x002 - superblock copys in each cylindergroup 0x004 - cylinder group summary in initial cylinder group 0x008 - cylinder group information 0x010 - inode allocation bitmap 0x020 - fragment allocation bitmap 0x040 - cluster maps and summary 0x080 - rotational layout tables 0x100 - inode information 0x200 - indirect block dump .Ed .It Fl o Ar outfile -This allows to change the output filename where the dump is written to. The -current default is -.Nm /var/tmp/ffsinfo . +This allows to change the output filename where the dump is written to. +The current default is +.Pa /var/tmp/ffsinfo . .El .Sh EXAMPLES .Pp .Dl ffsinfo -l 1023 /dev/vinum/testvol .Pp -will dump /dev/vinum/testvol with all available information. +will dump +.Pa /dev/vinum/testvol +with all available information. .Sh BUGS Currently .Nm -can only dump unmounted file systems. Do not try dumping a mounted file system, -your system may panic and you will not be able to use the file system any -longer. +can only dump unmounted file systems. +Do not try dumping a mounted file system, your system may panic and you will +not be able to use the file system any longer. .Pp -Also snapshots are handled like plain files. They should get a their own -level to provide for independent control of the amount of what gets dumped. It -probably also makes sense to some extend to dump the snapshot as a filesystem. +Also snapshots are handled like plain files. +They should get a their own level to provide for independent control of the +amount of what gets dumped. +It probably also makes sense to some extend to dump the snapshot as a +filesystem. .Sh SEE ALSO .Xr vinum 8 , .Xr disklabel 8 , .Xr fsck 8 , .Xr newfs 8 , .Xr tunefs 8 , .Xr growfs 8 , .Xr dumpfs 8 .\".Rs .\".Re .Sh AUTHORS .An Christoph Herrmann Aq chm@FreeBSD.ORG .An Thomas-Henning von Kamptz Aq tomsoft@FreeBSD.ORG .An The GROWFS team Aq growfs@Tomsoft.COM .Sh HISTORY The .Nm command appeared first in .Bx Free 5.0 Index: head/sbin/ffsinfo/ffsinfo.c =================================================================== --- head/sbin/ffsinfo/ffsinfo.c (revision 69925) +++ head/sbin/ffsinfo/ffsinfo.c (revision 69926) @@ -1,615 +1,640 @@ /* * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz * Copyright (c) 1980, 1989, 1993 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors, as well as Christoph * Herrmann and Thomas-Henning von Kamptz. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * - * $TSHeader: src/sbin/ffsinfo/ffsinfo.c,v 1.3 2000/12/09 15:12:31 tomsoft Exp $ + * $TSHeader: src/sbin/ffsinfo/ffsinfo.c,v 1.4 2000/12/12 19:30:55 tomsoft Exp $ * $FreeBSD$ * */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz\n\ Copyright (c) 1980, 1989, 1993 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* ********************************************************** INCLUDES ***** */ #include #include -#include #include -#include #include #include #include #include -#include #include #include #include #include -#include -#include -#include #include "debug.h" /* *********************************************************** GLOBALS ***** */ #ifdef FS_DEBUG int _dbg_lvl_ = (DL_INFO); /* DL_TRC */ #endif /* FS_DEBUG */ static union { struct fs fs; char pad[SBSIZE]; } fsun1, fsun2; #define sblock fsun1.fs #define osblock fsun2.fs static union { struct cg cg; char pad[MAXBSIZE]; } cgun1; #define acg cgun1.cg static char ablk[MAXBSIZE]; static char i1blk[MAXBSIZE]; static char i2blk[MAXBSIZE]; static char i3blk[MAXBSIZE]; static struct csum *fscs; /* ******************************************************** PROTOTYPES ***** */ static void rdfs(daddr_t, int, char *, int); -static void usage(char *); +static void usage(void); static struct disklabel *get_disklabel(int); static struct dinode *ginode(ino_t, int); static void dump_whole_inode(ino_t, int, int); /* ************************************************************** rdfs ***** */ /* * Here we read some block(s) from disk. */ void rdfs(daddr_t bno, int size, char *bf, int fsi) { DBG_FUNC("rdfs") int n; DBG_ENTER; if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) { - fprintf(stderr, "seek error: %ld\n", (long)bno); - err(33, "rdfs"); + err(33, "rdfs: seek error: %ld", (long)bno); } n = read(fsi, bf, (size_t)size); if (n != size) { - fprintf(stderr, "read error: %ld\n", (long)bno); - err(34, "rdfs"); + err(34, "rdfs: read error: %ld", (long)bno); } DBG_LEAVE; return; } /* ************************************************************** main ***** */ /* * ffsinfo(8) is a tool to dump all metadata of a filesystem. It helps to find * errors is the filesystem much easier. You can run ffsinfo before and after * an fsck(8), and compare the two ascii dumps easy with diff, and you see * directly where the problem is. You can control how much detail you want to * see with some command line arguments. You can also easy check the status * of a filesystem, like is there is enough space for growing a filesystem, * or how many active snapshots do we have. It provides much more detailed * information then dumpfs. Snapshots, as they are very new, are not really * supported. They are just mentioned currently, but it is planned to run * also over active snapshots, to even get that output. */ int main(int argc, char **argv) { DBG_FUNC("main") - char *a0, *device, *special, *cp; + char *device, *special, *cp; char ch; size_t len; struct stat st; struct disklabel *lp; struct partition *pp; int fsi; struct csum *dbg_csp; int dbg_csc; char dbg_line[80]; int cylno,i; int cfg_cg, cfg_in, cfg_lv; int cg_start, cg_stop; ino_t in; char *out_file; int Lflag=0; DBG_ENTER; cfg_lv=0xff; cfg_in=-2; cfg_cg=-2; out_file=strdup("/var/tmp/ffsinfo"); - - a0=*argv; /* save argv[0] for usage() */ + if(out_file == NULL) { + errx(1, "strdup failed"); + } + while ((ch=getopt(argc, argv, "Lg:i:l:o:")) != -1) { switch(ch) { case 'L': Lflag=1; break; case 'g': cfg_cg=atol(optarg); if(cfg_cg < -1) { - usage(a0); + usage(); } break; case 'i': cfg_in=atol(optarg); if(cfg_in < 0) { - usage(a0); + usage(); } break; case 'l': cfg_lv=atol(optarg); if(cfg_lv < 0x1||cfg_lv > 0x3ff) { - usage(a0); + usage(); } break; case 'o': free(out_file); out_file=strdup(optarg); + if(out_file == NULL) { + errx(1, "strdup failed"); + } break; case '?': /* FALLTHROUGH */ default: - usage(a0); + usage(); } } argc -= optind; argv += optind; if(argc != 1) { - usage(a0); + usage(); } device=*argv; /* * Now we try to guess the (raw)device name. */ if (0 == strrchr(device, '/') && (stat(device, &st) == -1)) { /* * No path prefix was given, so try in that order: * /dev/r%s * /dev/%s * /dev/vinum/r%s * /dev/vinum/%s. * * FreeBSD now doesn't distinguish between raw and block * devices any longer, but it should still work this way. */ len=strlen(device)+strlen(_PATH_DEV)+2+strlen("vinum/"); special=(char *)malloc(len); + if(special == NULL) { + errx(1, "malloc failed"); + } snprintf(special, len, "%sr%s", _PATH_DEV, device); if (stat(special, &st) == -1) { snprintf(special, len, "%s%s", _PATH_DEV, device); if (stat(special, &st) == -1) { snprintf(special, len, "%svinum/r%s", _PATH_DEV, device); if (stat(special, &st) == -1) { /* * For now this is the 'last resort'. */ snprintf(special, len, "%svinum/%s", _PATH_DEV, device); } } } device = special; } /* * Open our device for reading. */ fsi = open(device, O_RDONLY); if (fsi < 0) { - fprintf(stderr, "%s: %s\n", device, strerror(errno)); - exit(-1); + err(1, "%s", device); } stat(device, &st); if(S_ISREG(st.st_mode)) { /* label check not supported for files */ Lflag=1; } if(!Lflag) { /* * Try to read a label and gess the slice if not specified. * This code should guess the right thing and avaid to bother * the user user with the task of specifying the option -v on * vinum volumes. */ cp=device+strlen(device)-1; lp = get_disklabel(fsi); if(lp->d_type == DTYPE_VINUM) { pp = &lp->d_partitions[0]; } else if (isdigit(*cp)) { pp = &lp->d_partitions[2]; } else if (*cp>='a' && *cp<='h') { pp = &lp->d_partitions[*cp - 'a']; } else { - fprintf(stderr, "unknown device\n"); - exit(-1); + errx(1, "unknown device"); } /* * Check if that partition looks suited for dumping. */ if (pp->p_size < 1) { - fprintf(stderr, "partition is unavailable\n"); - exit(-1); + errx(1, "partition is unavailable"); } if (pp->p_fstype != FS_BSDFFS) { - fprintf(stderr, "partition not 4.2BSD\n"); - exit(-1); + errx(1, "partition not 4.2BSD"); } } /* * Read the current superblock. */ rdfs((daddr_t)(SBOFF/DEV_BSIZE), SBSIZE, (char *)&(sblock), fsi); if (sblock.fs_magic != FS_MAGIC) { - fprintf(stderr, "superblock not recognized\n"); - exit(-1); + errx(1, "superblock not recognized"); } DBG_OPEN(out_file); /* already here we need a superblock */ if(cfg_lv & 0x001) { - DBG_DUMP_FS(&sblock, "primary sblock"); + DBG_DUMP_FS(&sblock, + "primary sblock"); } /* * Determine here what cylinder groups to dump. */ if(cfg_cg==-2) { cg_start=0; cg_stop=sblock.fs_ncg; } else if (cfg_cg==-1) { cg_start=sblock.fs_ncg-1; cg_stop=sblock.fs_ncg; } else if (cfg_cgdi_nlink==0) { DBG_LEAVE; return; /* inode not in use */ } /* * Dump the main inode structure. */ snprintf(comment, 80, "Inode 0x%08x", inode); if (level & 0x100) { - DBG_DUMP_INO(&sblock, comment, ino); + DBG_DUMP_INO(&sblock, + comment, + ino); } if (!(level & 0x200)) { DBG_LEAVE; return; } /* * Ok, now prepare for dumping all direct and indirect pointers. */ rb=howmany(ino->di_size, sblock.fs_bsize)-NDADDR; if(rb>0) { /* * Dump single indirect block. */ rdfs(fsbtodb(&sblock, ino->di_ib[0]), sblock.fs_bsize, i1blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 0", inode); - DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); + DBG_DUMP_IBLK(&sblock, + comment, + i1blk, + (size_t)rb); rb-=howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); } if(rb>0) { /* * Dump double indirect blocks. */ rdfs(fsbtodb(&sblock, ino->di_ib[1]), sblock.fs_bsize, i2blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 1", inode); - DBG_DUMP_IBLK(&sblock, comment, i2blk, howmany(rb, - howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))); + DBG_DUMP_IBLK(&sblock, + comment, + i2blk, + howmany(rb, howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))); for(ind2ctr=0; ((ind2ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))&&(rb>0)); ind2ctr++) { ind2ptr=&((ufs_daddr_t *)&i2blk)[ind2ctr]; rdfs(fsbtodb(&sblock, *ind2ptr), sblock.fs_bsize, i1blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 1->%d", inode, ind2ctr); - DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); + DBG_DUMP_IBLK(&sblock, + comment, + i1blk, + (size_t)rb); rb-=howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); } } if(rb>0) { /* * Dump triple indirect blocks. */ rdfs(fsbtodb(&sblock, ino->di_ib[2]), sblock.fs_bsize, i3blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 2", inode); #define SQUARE(a) ((a)*(a)) - DBG_DUMP_IBLK(&sblock, comment, i3blk, howmany(rb, - SQUARE(howmany(sblock.fs_bsize, sizeof(ufs_daddr_t))))); + DBG_DUMP_IBLK(&sblock, + comment, + i3blk, + howmany(rb, + SQUARE(howmany(sblock.fs_bsize, sizeof(ufs_daddr_t))))); #undef SQUARE for(ind3ctr=0; ((ind3ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))&&(rb>0)); ind3ctr ++) { ind3ptr=&((ufs_daddr_t *)&i3blk)[ind3ctr]; rdfs(fsbtodb(&sblock, *ind3ptr), sblock.fs_bsize, i2blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 2->%d", inode, ind3ctr); - DBG_DUMP_IBLK(&sblock, comment, i2blk, howmany(rb, - howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))); + DBG_DUMP_IBLK(&sblock, + comment, + i2blk, + howmany(rb, + howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))); for(ind2ctr=0; ((ind2ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)))&&(rb>0)); ind2ctr ++) { ind2ptr=&((ufs_daddr_t *)&i2blk)[ind2ctr]; rdfs(fsbtodb(&sblock, *ind2ptr), sblock.fs_bsize, i1blk, fsi); snprintf(comment, 80, "Inode 0x%08x: indirect 2->%d->%d", inode, ind3ctr, ind3ctr); - DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); + DBG_DUMP_IBLK(&sblock, + comment, + i1blk, + (size_t)rb); rb-=howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); } } } DBG_LEAVE; return; } /* ***************************************************** get_disklabel ***** */ /* * Read the disklabel from disk. */ struct disklabel * get_disklabel(int fd) { DBG_FUNC("get_disklabel") static struct disklabel *lab; DBG_ENTER; lab=(struct disklabel *)malloc(sizeof(struct disklabel)); if (!lab) { - fprintf(stderr, "malloc failed\n"); - exit(-1); + errx(1, "malloc failed"); } if (ioctl(fd, DIOCGDINFO, (char *)lab) < 0) { - fprintf(stderr, "DIOCGDINFO failed\n"); + errx(1, "DIOCGDINFO failed"); exit(-1); } DBG_LEAVE; return (lab); } /* ************************************************************* usage ***** */ /* * Dump a line of usage. */ void -usage(char *name) +usage(void) { DBG_FUNC("usage") - char *basename; DBG_ENTER; - basename=strrchr(name, '/'); - if(!basename) { - basename=name; - } else { - basename++; - } fprintf(stderr, - "usage:\t%s\t[-L] [-g cylgrp] [-i inode] [-l level] [-o outfile]\n" - "\t\t< special | file >\n", - basename); + "usage: ffsinfo [-L] [-g cylgrp] [-i inode] [-l level] " + "[-o outfile]\n" + " special | file\n"); DBG_LEAVE; - exit(-1); + exit(1); } /* ************************************************************ ginode ***** */ /* * This function provides access to an individual inode. We find out in which * block the requested inode is located, read it from disk if needed, and * return the pointer into that block. We maintain a cache of one block to - * not read the same block again and again if we iterate lineary over all + * not read the same block again and again if we iterate linearly over all * inodes. */ struct dinode * ginode(ino_t inumber, int fsi) { DBG_FUNC("ginode") ufs_daddr_t iblk; static ino_t startinum=0; /* first inode in cached block */ struct dinode *pi; DBG_ENTER; pi=(struct dinode *)ablk; if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { /* * The block needed is not cached, so we have to read it from * disk now. */ iblk = ino_to_fsba(&sblock, inumber); rdfs(fsbtodb(&sblock, iblk), sblock.fs_bsize, (char *)&ablk, fsi); startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } DBG_LEAVE; return (&(pi[inumber % INOPB(&sblock)])); } Index: head/sbin/growfs/debug.c =================================================================== --- head/sbin/growfs/debug.c (revision 69925) +++ head/sbin/growfs/debug.c (revision 69926) @@ -1,699 +1,699 @@ /* * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz * Copyright (c) 1980, 1989, 1993 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors, as well as Christoph * Herrmann and Thomas-Henning von Kamptz. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * - * $TSHeader: src/sbin/growfs/debug.c,v 1.2 2000/11/16 18:43:49 tom Exp $ + * $TSHeader: src/sbin/growfs/debug.c,v 1.3 2000/12/12 19:31:00 tomsoft Exp $ * $FreeBSD$ * */ #ifndef lint static const char rcsid[] = - "$TSHeader: src/sbin/growfs/debug.c,v 1.2 2000/11/16 18:43:49 tom Exp $"; + "$FreeBSD$"; #endif /* not lint */ /* ********************************************************** INCLUDES ***** */ #include #include #include #include #include "debug.h" #ifdef FS_DEBUG /* *********************************************************** GLOBALS ***** */ static FILE *dbg_log=NULL; static unsigned int indent=0; /* * prototypes not done here, as they come with debug.h */ /* ********************************************************** dbg_open ***** */ /* * Open the filehandle where all debug output has to go. */ void dbg_open(const char *fn) { dbg_log=fopen(fn, "a"); return; } /* ********************************************************* dbg_close ***** */ /* * Close the filehandle where all debug output went to. */ void dbg_close(void) { if(dbg_log) { fclose(dbg_log); dbg_log=NULL; } return; } /* ****************************************************** dbg_dump_hex ***** */ /* * Dump out a full filesystem block in hex. */ void dbg_dump_hex(struct fs *sb, const char *comment, unsigned char *mem) { int i, j, k; if(!dbg_log) { return; } fprintf(dbg_log, "===== START HEXDUMP =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)mem, comment); indent++; for (i=0; ifs_bsize; i+=24) { for (j=0; j<3; j++) { for (k=0; k<8; k++) { fprintf(dbg_log, "%02x ", *mem++); } fprintf(dbg_log, " "); } fprintf(dbg_log, "\n"); } indent--; fprintf(dbg_log, "===== END HEXDUMP =====\n"); return; } /* ******************************************************* dbg_dump_fs ***** */ /* * Dump the superblock. */ void dbg_dump_fs(struct fs *sb, const char *comment) { #ifdef FSMAXSNAP int j; #endif /* FSMAXSNAP */ if(!dbg_log) { return; } fprintf(dbg_log, "===== START SUPERBLOCK =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)sb, comment); indent++; fprintf(dbg_log, "sblkno ufs_daddr_t 0x%08x\n", sb->fs_sblkno); fprintf(dbg_log, "cblkno ufs_daddr_t 0x%08x\n", sb->fs_cblkno); fprintf(dbg_log, "iblkno ufs_daddr_t 0x%08x\n", sb->fs_iblkno); fprintf(dbg_log, "dblkno ufs_daddr_t 0x%08x\n", sb->fs_dblkno); fprintf(dbg_log, "cgoffset int32_t 0x%08x\n", sb->fs_cgoffset); fprintf(dbg_log, "cgmask int32_t 0x%08x\n", sb->fs_cgmask); fprintf(dbg_log, "time time_t %10lu\n", sb->fs_time); fprintf(dbg_log, "size int32_t 0x%08x\n", sb->fs_size); fprintf(dbg_log, "dsize int32_t 0x%08x\n", sb->fs_dsize); fprintf(dbg_log, "ncg int32_t 0x%08x\n", sb->fs_ncg); fprintf(dbg_log, "bsize int32_t 0x%08x\n", sb->fs_bsize); fprintf(dbg_log, "fsize int32_t 0x%08x\n", sb->fs_fsize); fprintf(dbg_log, "frag int32_t 0x%08x\n", sb->fs_frag); fprintf(dbg_log, "minfree int32_t 0x%08x\n", sb->fs_minfree); fprintf(dbg_log, "rotdelay int32_t 0x%08x\n", sb->fs_rotdelay); fprintf(dbg_log, "rps int32_t 0x%08x\n", sb->fs_rps); fprintf(dbg_log, "bmask int32_t 0x%08x\n", sb->fs_bmask); fprintf(dbg_log, "fmask int32_t 0x%08x\n", sb->fs_fmask); fprintf(dbg_log, "bshift int32_t 0x%08x\n", sb->fs_bshift); fprintf(dbg_log, "fshift int32_t 0x%08x\n", sb->fs_fshift); fprintf(dbg_log, "maxcontig int32_t 0x%08x\n", sb->fs_maxcontig); fprintf(dbg_log, "maxbpg int32_t 0x%08x\n", sb->fs_maxbpg); fprintf(dbg_log, "fragshift int32_t 0x%08x\n", sb->fs_fragshift); fprintf(dbg_log, "fsbtodb int32_t 0x%08x\n", sb->fs_fsbtodb); fprintf(dbg_log, "sbsize int32_t 0x%08x\n", sb->fs_sbsize); fprintf(dbg_log, "csmask int32_t 0x%08x\n", sb->fs_csmask); fprintf(dbg_log, "csshift int32_t 0x%08x\n", sb->fs_csshift); fprintf(dbg_log, "nindir int32_t 0x%08x\n", sb->fs_nindir); fprintf(dbg_log, "inopb int32_t 0x%08x\n", sb->fs_inopb); fprintf(dbg_log, "nspf int32_t 0x%08x\n", sb->fs_nspf); fprintf(dbg_log, "optim int32_t 0x%08x\n", sb->fs_optim); fprintf(dbg_log, "npsect int32_t 0x%08x\n", sb->fs_npsect); fprintf(dbg_log, "interleave int32_t 0x%08x\n", sb->fs_interleave); fprintf(dbg_log, "trackskew int32_t 0x%08x\n", sb->fs_trackskew); fprintf(dbg_log, "id int32_t[2] %08x %08x\n", sb->fs_id[0], sb->fs_id[1]); fprintf(dbg_log, "csaddr ufs_daddr_t 0x%08x\n", sb->fs_csaddr); fprintf(dbg_log, "cssize int32_t 0x%08x\n", sb->fs_cssize); fprintf(dbg_log, "cgsize int32_t 0x%08x\n", sb->fs_cgsize); fprintf(dbg_log, "ntrak int32_t 0x%08x\n", sb->fs_ntrak); fprintf(dbg_log, "nsect int32_t 0x%08x\n", sb->fs_nsect); fprintf(dbg_log, "spc int32_t 0x%08x\n", sb->fs_spc); fprintf(dbg_log, "ncyl int32_t 0x%08x\n", sb->fs_ncyl); fprintf(dbg_log, "cpg int32_t 0x%08x\n", sb->fs_cpg); fprintf(dbg_log, "ipg int32_t 0x%08x\n", sb->fs_ipg); fprintf(dbg_log, "fpg int32_t 0x%08x\n", sb->fs_fpg); dbg_dump_csum("internal cstotal", &sb->fs_cstotal); fprintf(dbg_log, "fmod int8_t 0x%02x\n", sb->fs_fmod); fprintf(dbg_log, "clean int8_t 0x%02x\n", sb->fs_clean); fprintf(dbg_log, "ronly int8_t 0x%02x\n", sb->fs_ronly); fprintf(dbg_log, "flags int8_t 0x%02x\n", sb->fs_flags); fprintf(dbg_log, "fsmnt u_char[MAXMNTLEN] \"%s\"\n", sb->fs_fsmnt); fprintf(dbg_log, "cgrotor int32_t 0x%08x\n", sb->fs_cgrotor); /* * struct csum[MAXCSBUFS] - is only maintained in memory */ /* fprintf(dbg_log, " int32_t\n", sb->*fs_maxcluster);*/ fprintf(dbg_log, "cpc int32_t 0x%08x\n", sb->fs_cpc); /* * int16_t fs_opostbl[16][8] - is dumped when used in dbg_dump_sptbl */ #ifdef FSMAXSNAP for(j=0; jfs_snapinum[j]); if(!sb->fs_snapinum[j]) { /* list is dense */ break; } } #endif /* FSMAXSNAP */ fprintf(dbg_log, "contigsumsize int32_t 0x%08x\n", sb->fs_contigsumsize); fprintf(dbg_log, "maxsymlinklen int32_t 0x%08x\n", sb->fs_maxsymlinklen); fprintf(dbg_log, "inodefmt int32_t 0x%08x\n", sb->fs_inodefmt); fprintf(dbg_log, "maxfilesize u_int64_t 0x%08x%08x\n", ((unsigned int *)&(sb->fs_maxfilesize))[1], ((unsigned int *)&(sb->fs_maxfilesize))[0]); fprintf(dbg_log, "qbmask int64_t 0x%08x%08x\n", ((unsigned int *)&(sb->fs_qbmask))[1], ((unsigned int *)&(sb->fs_qbmask))[0]); fprintf(dbg_log, "qfmask int64_t 0x%08x%08x\n", ((unsigned int *)&(sb->fs_qfmask))[1], ((unsigned int *)&(sb->fs_qfmask))[0]); fprintf(dbg_log, "state int32_t 0x%08x\n", sb->fs_state); fprintf(dbg_log, "postblformat int32_t 0x%08x\n", sb->fs_postblformat); fprintf(dbg_log, "nrpos int32_t 0x%08x\n", sb->fs_nrpos); fprintf(dbg_log, "postbloff int32_t 0x%08x\n", sb->fs_postbloff); fprintf(dbg_log, "rotbloff int32_t 0x%08x\n", sb->fs_rotbloff); fprintf(dbg_log, "magic int32_t 0x%08x\n", sb->fs_magic); indent--; fprintf(dbg_log, "===== END SUPERBLOCK =====\n"); return; } /* ******************************************************* dbg_dump_cg ***** */ /* * Dump a cylinder group. */ void dbg_dump_cg(const char *comment, struct cg *cgr) { int j; if(!dbg_log) { return; } fprintf(dbg_log, "===== START CYLINDER GROUP =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)cgr, comment); indent++; fprintf(dbg_log, "magic int32_t 0x%08x\n", cgr->cg_magic); fprintf(dbg_log, "time time_t %10lu\n", cgr->cg_time); fprintf(dbg_log, "cgx int32_t 0x%08x\n", cgr->cg_cgx); fprintf(dbg_log, "ncyl int16_t 0x%04x\n", cgr->cg_ncyl); fprintf(dbg_log, "niblk int16_t 0x%04x\n", cgr->cg_niblk); fprintf(dbg_log, "ndblk int32_t 0x%08x\n", cgr->cg_ndblk); dbg_dump_csum("internal cs", &cgr->cg_cs); fprintf(dbg_log, "rotor int32_t 0x%08x\n", cgr->cg_rotor); fprintf(dbg_log, "frotor int32_t 0x%08x\n", cgr->cg_frotor); fprintf(dbg_log, "irotor int32_t 0x%08x\n", cgr->cg_irotor); for(j=0; jcg_frsum[j]); } fprintf(dbg_log, "btotoff int32_t 0x%08x\n", cgr->cg_btotoff); fprintf(dbg_log, "boff int32_t 0x%08x\n", cgr->cg_boff); fprintf(dbg_log, "iusedoff int32_t 0x%08x\n", cgr->cg_iusedoff); fprintf(dbg_log, "freeoff int32_t 0x%08x\n", cgr->cg_freeoff); fprintf(dbg_log, "nextfreeoff int32_t 0x%08x\n", cgr->cg_nextfreeoff); fprintf(dbg_log, "clustersumoff int32_t 0x%08x\n", cgr->cg_clustersumoff); fprintf(dbg_log, "clusterof int32_t 0x%08x\n", cgr->cg_clusteroff); fprintf(dbg_log, "nclusterblks int32_t 0x%08x\n", cgr->cg_nclusterblks); indent--; fprintf(dbg_log, "===== END CYLINDER GROUP =====\n"); return; } /* ***************************************************** dbg_dump_csum ***** */ /* * Dump a cylinder summary. */ void dbg_dump_csum(const char *comment, struct csum *cs) { if(!dbg_log) { return; } fprintf(dbg_log, "===== START CYLINDER SUMMARY =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)cs, comment); indent++; fprintf(dbg_log, "ndir int32_t 0x%08x\n", cs->cs_ndir); fprintf(dbg_log, "nbfree int32_t 0x%08x\n", cs->cs_nbfree); fprintf(dbg_log, "nifree int32_t 0x%08x\n", cs->cs_nifree); fprintf(dbg_log, "nffree int32_t 0x%08x\n", cs->cs_nffree); indent--; fprintf(dbg_log, "===== END CYLINDER SUMMARY =====\n"); return; } /* **************************************************** dbg_dump_inmap ***** */ /* * Dump the inode allocation map in one cylinder group. */ void dbg_dump_inmap(struct fs *sb, const char *comment, struct cg *cgr) { int j,k,l,e; unsigned char *cp; if(!dbg_log) { return; } fprintf(dbg_log, "===== START INODE ALLOCATION MAP =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)cgr, comment); indent++; cp=(unsigned char *)cg_inosused(cgr); e=sb->fs_ipg/8; for(j=0; jfs_cpg * sb->fs_spc / NSPF(sb)), NBBY); for(j=0; jfs_cpg * sb->fs_spc / NSPB(sb), NBBY); for(j=0; jfs_contigsumsize; j++) { fprintf(dbg_log, "%02d: %8ld\n", j, *lp++); } indent--; fprintf(dbg_log, "===== END CLUSTER SUMMARY =====\n"); return; } /* **************************************************** dbg_dump_sptbl ***** */ /* * Dump the block summary, and the rotational layout table. */ void dbg_dump_sptbl(struct fs *sb, const char *comment, struct cg *cgr) { int j,k; long *lp; if(!dbg_log) { return; } fprintf(dbg_log, "===== START BLOCK SUMMARY AND POSITION TABLE =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)cgr, comment); indent++; lp=(long *)cg_blktot(cgr); for(j=0; jfs_cpg; j++) { fprintf(dbg_log, "%2d: %5ld = ", j, *lp++); for(k=0; kfs_nrpos; k++) { fprintf(dbg_log, "%4d", cg_blks(sb, cgr, j)[k]); if(kfs_nrpos-1) { fprintf(dbg_log, " + "); } } fprintf(dbg_log, "\n"); } indent--; fprintf(dbg_log, "===== END BLOCK SUMMARY AND POSITION TABLE =====\n"); return; } /* ****************************************************** dbg_dump_ino ***** */ /* * Dump an inode structure. */ void dbg_dump_ino(struct fs *sb, const char *comment, struct dinode *ino) { int ictr; int remaining_blocks; if(!dbg_log) { return; } fprintf(dbg_log, "===== START INODE DUMP =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)ino, comment); indent++; fprintf(dbg_log, "mode u_int16_t 0%o\n", ino->di_mode); fprintf(dbg_log, "nlink int16_t 0x%04x\n", ino->di_nlink); fprintf(dbg_log, "size u_int64_t 0x%08x%08x\n", ((unsigned int *)&(ino->di_size))[1], ((unsigned int *)&(ino->di_size))[0]); fprintf(dbg_log, "atime int32_t 0x%08x\n", ino->di_atime); fprintf(dbg_log, "atimensec int32_t 0x%08x\n", ino->di_atimensec); fprintf(dbg_log, "mtime int32_t 0x%08x\n", ino->di_mtime); fprintf(dbg_log, "mtimensec int32_t 0x%08x\n", ino->di_mtimensec); fprintf(dbg_log, "ctime int32_t 0x%08x\n", ino->di_ctime); fprintf(dbg_log, "ctimensec int32_t 0x%08x\n", ino->di_ctimensec); remaining_blocks=howmany(ino->di_size, sb->fs_bsize); /* XXX ts - +1? */ for(ictr=0; ictr < MIN(NDADDR, remaining_blocks); ictr++) { fprintf(dbg_log, "db ufs_daddr_t[%x] 0x%08x\n", ictr, ino->di_db[ictr]); } remaining_blocks-=NDADDR; if(remaining_blocks>0) { fprintf(dbg_log, "ib ufs_daddr_t[0] 0x%08x\n", ino->di_ib[0]); } remaining_blocks-=howmany(sb->fs_bsize, sizeof(ufs_daddr_t)); if(remaining_blocks>0) { fprintf(dbg_log, "ib ufs_daddr_t[1] 0x%08x\n", ino->di_ib[1]); } #define SQUARE(a) ((a)*(a)) remaining_blocks-=SQUARE(howmany(sb->fs_bsize, sizeof(ufs_daddr_t))); #undef SQUARE if(remaining_blocks>0) { fprintf(dbg_log, "ib ufs_daddr_t[2] 0x%08x\n", ino->di_ib[2]); } fprintf(dbg_log, "flags u_int32_t 0x%08x\n", ino->di_flags); fprintf(dbg_log, "blocks int32_t 0x%08x\n", ino->di_blocks); fprintf(dbg_log, "gen int32_t 0x%08x\n", ino->di_gen); fprintf(dbg_log, "uid u_int32_t 0x%08x\n", ino->di_uid); fprintf(dbg_log, "gid u_int32_t 0x%08x\n", ino->di_gid); indent--; fprintf(dbg_log, "===== END INODE DUMP =====\n"); return; } /* ***************************************************** dbg_dump_iblk ***** */ /* * Dump an indirect block. The iteration to dump a full file has to be * written around. */ void dbg_dump_iblk(struct fs *sb, const char *comment, char *block, size_t length) { unsigned int *mem; int i, j; if(!dbg_log) { return; } fprintf(dbg_log, "===== START INDIRECT BLOCK DUMP =====\n"); fprintf(dbg_log, "# %d@%lx: %s\n", indent, (unsigned long)block, comment); indent++; mem=(unsigned int *)block; for (i=0; (size_t)ifs_bsize, sizeof(ufs_daddr_t)), length); i+=8) { fprintf(dbg_log, "%04x: ", i); for (j=0; j<8; j++) { if((size_t)(i+j) #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include #include -#include #include "debug.h" /* *************************************************** GLOBALS & TYPES ***** */ #ifdef FS_DEBUG int _dbg_lvl_ = (DL_INFO); /* DL_TRC */ #endif /* FS_DEBUG */ static union { struct fs fs; char pad[SBSIZE]; } fsun1, fsun2; #define sblock fsun1.fs /* the new superblock */ #define osblock fsun2.fs /* the old superblock */ static union { struct cg cg; char pad[MAXBSIZE]; } cgun1, cgun2; #define acg cgun1.cg /* a cylinder cgroup (new) */ #define aocg cgun2.cg /* an old cylinder group */ static char ablk[MAXBSIZE]; /* a block */ static char i1blk[MAXBSIZE]; /* some indirect blocks */ static char i2blk[MAXBSIZE]; static char i3blk[MAXBSIZE]; /* where to write back updated blocks */ static daddr_t in_src, i1_src, i2_src, i3_src; /* what object contains the reference */ enum pointer_source { GFS_PS_INODE, GFS_PS_IND_BLK_LVL1, GFS_PS_IND_BLK_LVL2, GFS_PS_IND_BLK_LVL3 }; static struct csum *fscs; /* cylinder summary */ static struct dinode zino[MAXBSIZE/sizeof(struct dinode)]; /* some inodes */ /* * An array of elements of type struct gfs_bpp describes all blocks to * be relocated in order to free the space needed for the cylinder group * summary for all cylinder groups located in the first cylinder group. */ struct gfs_bpp { daddr_t old; /* old block number */ daddr_t new; /* new block number */ #define GFS_FL_FIRST 1 #define GFS_FL_LAST 2 unsigned long flags; /* special handling required */ int found; /* how many references were updated */ }; /* ******************************************************** PROTOTYPES ***** */ static void rdfs(daddr_t, int, char *, int); static void wtfs(daddr_t, int, char *, int, int); static daddr_t alloc(void); static int charsperline(void); -static void usage(char *); +static void usage(void); static int isblock(struct fs *, unsigned char *, int); static void clrblock(struct fs *, unsigned char *, int); static void setblock(struct fs *, unsigned char *, int); static void initcg(int, time_t, int, int); static void updjcg(int, time_t, int, int, int); static void updcsloc(time_t, int, int, int); static struct disklabel *get_disklabel(int); static void return_disklabel(int, struct disklabel *, int); static struct dinode *ginode(ino_t, int, int); static void frag_adjust(daddr_t, int); static void cond_bl_upd(ufs_daddr_t *, struct gfs_bpp *, enum pointer_source, int, int); static void updclst(int); static void updrefs(int, ino_t, struct gfs_bpp *, int, int, int); /* ************************************************************ growfs ***** */ /* * Here we actually start growing the filesystem. We basically read the - * cylinder summary from the first cylinder group as we wan't to update + * cylinder summary from the first cylinder group as we want to update * this on the fly during our various operations. First we handle the * changes in the former last cylinder group. Afterwards we create all new * cylinder groups. Now we handle the cylinder group containing the * cylinder summary which might result in a relocation of the whole * structure. In the end we write back the updated cylinder summary, the * new superblock, and slightly patched versions of the super block * copies. */ static void growfs(int fsi, int fso, int Nflag) { DBG_FUNC("growfs") long i; long cylno, j; time_t utime; int width; char tmpbuf[100]; #ifdef FSIRAND static int randinit=0; DBG_ENTER; if (!randinit) { randinit = 1; srandomdev(); } #else /* not FSIRAND */ DBG_ENTER; #endif /* FSIRAND */ time(&utime); /* * Get the cylinder summary into the memory. */ fscs = (struct csum *)calloc(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)), MIN(osblock.fs_cssize - i, osblock.fs_bsize), ((char *)fscs) + i, fsi); } #ifdef FS_DEBUG { struct csum *dbg_csp; int dbg_csc; char dbg_line[80]; dbg_csp=fscs; for(dbg_csc=0; dbg_csc= width) { printf("\n"); i = 0; } i += j; printf("%s", tmpbuf); fflush(stdout); } printf("\n"); /* * Do all needed changes in the first cylinder group. * allocate blocks in new location */ updcsloc(utime, fsi, fso, Nflag); /* * Now write the cylinder summary back to disk. */ 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, fso, Nflag); } DBG_PRINT0("fscs written\n"); #ifdef FS_DEBUG { struct csum *dbg_csp; int dbg_csc; char dbg_line[80]; dbg_csp=fscs; for(dbg_csc=0; dbg_csc sblock.fs_size) { dmax = sblock.fs_size; } dlower = cgsblock(&sblock, cylno) - cbase; dupper = cgdmin(&sblock, cylno) - cbase; if (cylno == 0) { dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); } cs = fscs + cylno; memset(&acg, 0, (size_t)sblock.fs_cgsize); acg.cg_time = utime; acg.cg_magic = CG_MAGIC; acg.cg_cgx = cylno; if (cylno == sblock.fs_ncg - 1) { acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; } else { acg.cg_ncyl = sblock.fs_cpg; } acg.cg_niblk = sblock.fs_ipg; acg.cg_ndblk = dmax - cbase; if (sblock.fs_contigsumsize > 0) { acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; } acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t); acg.cg_iusedoff = acg.cg_boff + sblock.fs_cpg * sblock.fs_nrpos * sizeof(u_int16_t); acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY); if (sblock.fs_contigsumsize <= 0) { acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_cpg* sblock.fs_spc/ NSPF(&sblock), NBBY); } else { acg.cg_clustersumoff = acg.cg_freeoff + howmany (sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY) - sizeof(u_int32_t); acg.cg_clustersumoff = roundup(acg.cg_clustersumoff, sizeof(u_int32_t)); acg.cg_clusteroff = acg.cg_clustersumoff + (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); acg.cg_nextfreeoff = acg.cg_clusteroff + howmany (sblock.fs_cpg * sblock.fs_spc / NSPB(&sblock), NBBY); } if (acg.cg_nextfreeoff-(long)(&acg.cg_firstfield) > sblock.fs_cgsize) { /* * XXX This should never happen as we would have had that panic * already on filesystem creation */ - fprintf(stderr, "Panic: cylinder group too big\n"); - exit(37); + errx(37, "panic: cylinder group too big"); } acg.cg_cs.cs_nifree += sblock.fs_ipg; if (cylno == 0) for (i = 0; (size_t)i < ROOTINO; i++) { setbit(cg_inosused(&acg), i); acg.cg_cs.cs_nifree--; } for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) { #ifdef FSIRAND for (j = 0; j < sblock.fs_bsize / sizeof(struct dinode); j++) { zino[j].di_gen = random(); } #endif wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), sblock.fs_bsize, (char *)zino, fso, Nflag); } for (d = 0; d < dlower; d += sblock.fs_frag) { blkno = d / sblock.fs_frag; setblock(&sblock, cg_blksfree(&acg), blkno); if (sblock.fs_contigsumsize > 0) { setbit(cg_clustersfree(&acg), blkno); } acg.cg_cs.cs_nbfree++; cg_blktot(&acg)[cbtocylno(&sblock, d)]++; cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) [cbtorpos(&sblock, d)]++; } sblock.fs_dsize += dlower; sblock.fs_dsize += acg.cg_ndblk - dupper; if ((i = dupper % sblock.fs_frag)) { acg.cg_frsum[sblock.fs_frag - i]++; for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { setbit(cg_blksfree(&acg), dupper); acg.cg_cs.cs_nffree++; } } for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) { blkno = d / sblock.fs_frag; setblock(&sblock, cg_blksfree(&acg), blkno); if (sblock.fs_contigsumsize > 0) { setbit(cg_clustersfree(&acg), blkno); } acg.cg_cs.cs_nbfree++; cg_blktot(&acg)[cbtocylno(&sblock, d)]++; cg_blks(&sblock, &acg, cbtocylno(&sblock, d)) [cbtorpos(&sblock, d)]++; d += sblock.fs_frag; } if (d < dmax - cbase) { acg.cg_frsum[dmax - cbase - d]++; for (; d < dmax - cbase; d++) { setbit(cg_blksfree(&acg), d); acg.cg_cs.cs_nffree++; } } if (sblock.fs_contigsumsize > 0) { int32_t *sump = cg_clustersum(&acg); u_char *mapp = cg_clustersfree(&acg); int map = *mapp++; int bit = 1; int run = 0; for (i = 0; i < acg.cg_nclusterblks; i++) { if ((map & bit) != 0) { run++; } else if (run != 0) { if (run > sblock.fs_contigsumsize) { run = sblock.fs_contigsumsize; } sump[run]++; run = 0; } if ((i & (NBBY - 1)) != (NBBY - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } if (run != 0) { if (run > sblock.fs_contigsumsize) { run = sblock.fs_contigsumsize; } sump[run]++; } } sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; *cs = acg.cg_cs; wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), sblock.fs_bsize, (char *)&acg, fso, Nflag); - DBG_DUMP_CG(&sblock, "new cg", &acg); + DBG_DUMP_CG(&sblock, + "new cg", + &acg); DBG_LEAVE; return; } /* ******************************************************* frag_adjust ***** */ /* * Here we add or subtract (sign +1/-1) the available fragments in a given * block to or from the fragment statistics. By subtracting before and adding * after an operation on the free frag map we can easy update the fragment * statistic, which seems to be otherwise an rather complex operation. */ static void frag_adjust(daddr_t frag, int sign) { DBG_FUNC("frag_adjust") int fragsize; int f; DBG_ENTER; fragsize=0; /* * Here frag only needs to point to any fragment in the block we want * to examine. */ for(f=rounddown(frag, sblock.fs_frag); fold) { /* for all old blocks */ if(*block/sblock.fs_frag == f->old) { /* * The fragment is part of the block, so update. */ *block=(f->new*sblock.fs_frag+(*block%sblock.fs_frag)); f->found++; - DBG_PRINT3("scg (%d->%d)[%d] reference updated\n", f->old, f->new, *block%sblock.fs_frag); + DBG_PRINT3("scg (%d->%d)[%d] reference updated\n", + f->old, + f->new, + *block%sblock.fs_frag); /* Write the block back to disk immediately */ switch (source) { case GFS_PS_INODE: src=ablk; dst=in_src; break; case GFS_PS_IND_BLK_LVL1: src=i1blk; dst=i1_src; break; case GFS_PS_IND_BLK_LVL2: src=i2blk; dst=i2_src; break; case GFS_PS_IND_BLK_LVL3: src=i3blk; dst=i3_src; break; default: /* error */ src=NULL; break; } if(src) { /* * XXX If src is not of type inode we have to * implement copy on write here in case * of active snapshots. */ wtfs(dst, sblock.fs_bsize, src, fso, Nflag); } /* * The same block can't be found again in this loop. */ break; } f++; } DBG_LEAVE; return; } /* ************************************************************ updjcg ***** */ /* * Here we do all needed work for the former last cylinder group. It has to be * changed in any case, even if the filesystem ended exactly on the end of * this group, as there is some slightly inconsistent handling of the number * of cylinders in the cylinder group. We start again by reading the cylinder * group from disk. If the last block was not fully available, we first handle * the missing fragments, then we handle all new full blocks in that file * system and finally we handle the new last fragmented block in the file * system. We again have to handle the fragment statistics rotational layout * tables and cluster summary during all those operations. */ static void updjcg(int cylno, time_t utime, int fsi, int fso, int Nflag) { DBG_FUNC("updjcg") daddr_t cbase, dmax, dupper; struct csum *cs; int i,k; int j=0; DBG_ENTER; /* * Read the former last (joining) cylinder group from disk, and make * a copy. */ rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)), osblock.fs_cgsize, (char *)&aocg, fsi); DBG_PRINT0("jcg read\n"); - DBG_DUMP_CG(&sblock, "old joining cg", &aocg); + DBG_DUMP_CG(&sblock, + "old joining cg", + &aocg); memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); /* * If the cylinder group had already it's new final size almost * nothing is to be done ... except: * For some reason the value of cg_ncyl in the last cylinder group has * to be zero instead of fs_cpg. As this is now no longer the last * cylinder group we have to change that value now to fs_cpg. */ if(cgbase(&osblock, cylno+1) == osblock.fs_size) { acg.cg_ncyl=sblock.fs_cpg; wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), sblock.fs_cgsize, (char *)&acg, fso, Nflag); DBG_PRINT0("jcg written\n"); - DBG_DUMP_CG(&sblock, "new joining cg", &acg); + DBG_DUMP_CG(&sblock, + "new joining cg", + &acg); DBG_LEAVE; return; } /* * Set up some variables needed later. */ cbase = cgbase(&sblock, cylno); dmax = cbase + sblock.fs_fpg; if (dmax > sblock.fs_size) dmax = sblock.fs_size; dupper = cgdmin(&sblock, cylno) - cbase; if (cylno == 0) { dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); } /* * Set pointer to the cylinder summary for our cylinder group. */ cs = fscs + cylno; /* * Touch the cylinder group, update all fields in the cylinder group as * needed, update the free space in the superblock. */ acg.cg_time = utime; if (cylno == sblock.fs_ncg - 1) { /* * This is still the last cylinder group. */ acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; } else { acg.cg_ncyl = sblock.fs_cpg; } - DBG_PRINT4("jcg dbg: %d %u %d %u\n", cylno, sblock.fs_ncg, acg.cg_ncyl, sblock.fs_cpg); + DBG_PRINT4("jcg dbg: %d %u %d %u\n", + cylno, + sblock.fs_ncg, + acg.cg_ncyl, + sblock.fs_cpg); acg.cg_ndblk = dmax - cbase; sblock.fs_dsize += acg.cg_ndblk-aocg.cg_ndblk; if (sblock.fs_contigsumsize > 0) { acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; } /* * Now we have to update the free fragment bitmap for our new free * space. There again we have to handle the fragmentation and also * the rotational layout tables and the cluster summary. This is * also done per fragment for the first new block if the old file * system end was not on a block boundary, per fragment for the new * last block if the new file system end is not on a block boundary, * and per block for all space in between. * * Handle the first new block here if it was partially available * before. */ if(osblock.fs_size % sblock.fs_frag) { if(roundup(osblock.fs_size, sblock.fs_frag)<=sblock.fs_size) { /* * The new space is enough to fill at least this * block */ j=0; for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag)-1; i>=osblock.fs_size-cbase; i--) { setbit(cg_blksfree(&acg), i); acg.cg_cs.cs_nffree++; j++; } /* * Check if the fragment just created could join an * already existing fragment at the former end of the * file system. */ if(isblock(&sblock, cg_blksfree(&acg), ((osblock.fs_size - cgbase(&sblock, cylno))/ sblock.fs_frag))) { /* * The block is now completely available */ DBG_PRINT0("block was\n"); acg.cg_frsum[osblock.fs_size%sblock.fs_frag]--; acg.cg_cs.cs_nbfree++; acg.cg_cs.cs_nffree-=sblock.fs_frag; k=rounddown(osblock.fs_size-cbase, sblock.fs_frag); cg_blktot(&acg)[cbtocylno(&sblock, k)]++; cg_blks(&sblock, &acg, cbtocylno(&sblock, k)) [cbtorpos(&sblock, k)]++; updclst((osblock.fs_size-cbase)/sblock.fs_frag); } else { /* * Lets rejoin a possible partially growed * fragment. */ k=0; while(isset(cg_blksfree(&acg), i) && (i>=rounddown(osblock.fs_size-cbase, sblock.fs_frag))) { i--; k++; } if(k) { acg.cg_frsum[k]--; } acg.cg_frsum[k+j]++; } } else { /* * We only grow by some fragments within this last * block. */ for(i=sblock.fs_size-cbase-1; i>=osblock.fs_size-cbase; i--) { setbit(cg_blksfree(&acg), i); acg.cg_cs.cs_nffree++; j++; } /* * Lets rejoin a possible partially growed fragment. */ k=0; while(isset(cg_blksfree(&acg), i) && (i>=rounddown(osblock.fs_size-cbase, sblock.fs_frag))) { i--; k++; } if(k) { acg.cg_frsum[k]--; } acg.cg_frsum[k+j]++; } } /* * Handle all new complete blocks here. */ for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag); i+sblock.fs_frag<=dmax-cbase; /* XXX <= or only < ? */ i+=sblock.fs_frag) { j = i / sblock.fs_frag; setblock(&sblock, cg_blksfree(&acg), j); updclst(j); acg.cg_cs.cs_nbfree++; cg_blktot(&acg)[cbtocylno(&sblock, i)]++; cg_blks(&sblock, &acg, cbtocylno(&sblock, i)) [cbtorpos(&sblock, i)]++; } /* * Handle the last new block if there are stll some new fragments left. * Here we don't have to bother about the cluster summary or the even * the rotational layout table. */ if (i < (dmax - cbase)) { acg.cg_frsum[dmax - cbase - i]++; for (; i < dmax - cbase; i++) { setbit(cg_blksfree(&acg), i); acg.cg_cs.cs_nffree++; } } sblock.fs_cstotal.cs_nffree += (acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree); sblock.fs_cstotal.cs_nbfree += (acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree); /* * The following statistics are not changed here: * sblock.fs_cstotal.cs_ndir * sblock.fs_cstotal.cs_nifree * As the statistics for this cylinder group are ready, copy it to * the summary information array. */ *cs = acg.cg_cs; /* * Write the updated "joining" cylinder group back to disk. */ wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), sblock.fs_cgsize, (char *)&acg, fso, Nflag); DBG_PRINT0("jcg written\n"); - DBG_DUMP_CG(&sblock, "new joining cg", &acg); + DBG_DUMP_CG(&sblock, + "new joining cg", + &acg); DBG_LEAVE; return; } /* ********************************************************** updcsloc ***** */ /* * Here we update the location of the cylinder summary. We have two possible * ways of growing the cylinder summary. * (1) We can try to grow the summary in the current location, and relocate * possibly used blocks within the current cylinder group. * (2) Alternatively we can relocate the whole cylinder summary to the first * new completely empty cylinder group. Once the cylinder summary is no * longer in the beginning of the first cylinder group you should never * use a version of fsck which is not aware of the possibility to have * this structure in a non standard place. * Option (1) is considered to be less intrusive to the structure of the file- * system. So we try to stick to that whenever possible. If there is not enough * space in the cylinder group containing the cylinder summary we have to use * method (2). In case of active snapshots in the filesystem we probably can * completely avoid implementing copy on write if we stick to method (2) only. */ static void updcsloc(time_t utime, int fsi, int fso, int Nflag) { DBG_FUNC("updcsloc") struct csum *cs; int ocscg, ncscg; int blocks; daddr_t cbase, dupper, odupper, d, f, g; int ind; int cylno, inc; struct gfs_bpp *bp; int i, l; int lcs=0; int block; DBG_ENTER; if(howmany(sblock.fs_cssize, sblock.fs_fsize) == howmany(osblock.fs_cssize, osblock.fs_fsize)) { /* * No new fragment needed. */ DBG_LEAVE; return; } ocscg=dtog(&osblock, osblock.fs_csaddr); cs=fscs+ocscg; blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)- howmany(osblock.fs_cssize, osblock.fs_bsize); /* * Read original cylinder group from disk, and make a copy. */ rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)), osblock.fs_cgsize, (char *)&aocg, fsi); DBG_PRINT0("oscg read\n"); - DBG_DUMP_CG(&sblock, "old summary cg", &aocg); + DBG_DUMP_CG(&sblock, + "old summary cg", + &aocg); memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); /* * Touch the cylinder group, set up local variables needed later * and update the superblock. */ acg.cg_time = utime; /* * XXX In the case of having active snapshots we may need much more * blocks for the copy on write. We need each block twice, and * also up to 8*3 blocks for indirect blocks for all possible * references. */ if(/*((int)sblock.fs_time&0x3)>0||*/ cs->cs_nbfree < blocks) { /* * There is not enough space in the old cylinder group to * relocate all blocks as needed, so we relocate the whole * cylinder group summary to a new group. We try to use the * first complete new cylinder group just created. Within the * cylinder group we allign the area immediately after the * cylinder group information location in order to be as * close as possible to the original implementation of ffs. * * First we have to make sure we'll find enough space in the * new cylinder group. If not, then we currently give up. * We start with freeing everything which was used by the * fragments of the old cylinder summary in the current group. * Now we write back the group meta data, read in the needed * meta data from the new cylinder group, and start allocating * within that group. Here we can assume, the group to be * completely empty. Which makes the handling of fragments and * clusters a lot easier. */ DBG_TRC; if(sblock.fs_ncg-osblock.fs_ncg < 2) { - fprintf(stderr, "growfs: panic, not enough space\n"); - exit(2); + errx(2, "panic: not enough space"); } /* * Point "d" to the first fragment not used by the cylinder * summary. */ d=osblock.fs_csaddr+(osblock.fs_cssize/osblock.fs_fsize); /* * Set up last cluster size ("lcs") already here. Calculate * the size for the trailing cluster just behind where "d" * points to. */ if(sblock.fs_contigsumsize > 0) { for(block=howmany(d%sblock.fs_fpg, sblock.fs_frag), lcs=0; lcs 0) { setbit(cg_clustersfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); if(lcs < sblock.fs_contigsumsize) { if(lcs) { cg_clustersum(&acg) [lcs]--; } lcs++; cg_clustersum(&acg)[lcs]++; } } } /* * Point "d" to the first fragment of the block before * the last incomplete block. */ d--; } - DBG_PRINT1("d=%d\n",d); + DBG_PRINT1("d=%d\n", + d); for(d=rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr; d-=sblock.fs_frag) { DBG_TRC; - DBG_PRINT1("d=%d\n",d); + DBG_PRINT1("d=%d\n", + d); setblock(&sblock, cg_blksfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); acg.cg_cs.cs_nbfree++; sblock.fs_cstotal.cs_nbfree++; cg_blktot(&acg)[cbtocylno(&sblock, d%sblock.fs_fpg)]++; cg_blks(&sblock, &acg, cbtocylno(&sblock, d%sblock.fs_fpg))[cbtorpos(&sblock, d%sblock.fs_fpg)]++; if(sblock.fs_contigsumsize > 0) { setbit(cg_clustersfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); /* * The last cluster size is already set up. */ if(lcs < sblock.fs_contigsumsize) { if(lcs) { cg_clustersum(&acg)[lcs]--; } lcs++; cg_clustersum(&acg)[lcs]++; } } } *cs = acg.cg_cs; /* * Now write the former cylinder group containing the cylinder * summary back to disk. */ wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), sblock.fs_cgsize, (char *)&acg, fso, Nflag); DBG_PRINT0("oscg written\n"); - DBG_DUMP_CG(&sblock, "old summary cg", &acg); + DBG_DUMP_CG(&sblock, + "old summary cg", + &acg); /* * Find the beginning of the new cylinder group containing the * cylinder summary. */ sblock.fs_csaddr=cgdmin(&sblock, osblock.fs_ncg); ncscg=dtog(&sblock, sblock.fs_csaddr); cs=fscs+ncscg; /* * Read the future cylinder group containing the cylinder * summary from disk, and make a copy. */ rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), sblock.fs_cgsize, (char *)&aocg, fsi); DBG_PRINT0("nscg read\n"); - DBG_DUMP_CG(&sblock, "new summary cg", &aocg); + DBG_DUMP_CG(&sblock, + "new summary cg", + &aocg); memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2)); /* * Allocate all complete blocks used by the new cylinder * summary. */ for(d=sblock.fs_csaddr; d+sblock.fs_frag <= sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize); d+=sblock.fs_frag) { clrblock(&sblock, cg_blksfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); acg.cg_cs.cs_nbfree--; sblock.fs_cstotal.cs_nbfree--; cg_blktot(&acg)[cbtocylno(&sblock, d%sblock.fs_fpg)]--; cg_blks(&sblock, &acg, cbtocylno(&sblock, d%sblock.fs_fpg))[cbtorpos(&sblock, d%sblock.fs_fpg)]--; if(sblock.fs_contigsumsize > 0) { clrbit(cg_clustersfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); } } /* * Allocate all fragments used by the cylinder summary in the * last block. */ if(d 0) { clrbit(cg_clustersfree(&acg), (d%sblock.fs_fpg)/sblock.fs_frag); } frag_adjust(d%sblock.fs_fpg, +1); } /* * XXX Handle the cluster statistics here in the case this * cylinder group is now almost full, and the remaining * space is less then the maximum cluster size. This is * probably not needed, as you would hardly find a file * system which has only MAXCSBUFS+FS_MAXCONTIG of free * space right behind the cylinder group information in * any new cylinder group. */ /* * Update our statistics in the cylinder summary. */ *cs = acg.cg_cs; /* * Write the new cylinder group containing the cylinder summary * back to disk. */ wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)), sblock.fs_cgsize, (char *)&acg, fso, Nflag); DBG_PRINT0("nscg written\n"); - DBG_DUMP_CG(&sblock, "new summary cg", &acg); + DBG_DUMP_CG(&sblock, + "new summary cg", + &acg); DBG_LEAVE; return; } /* * We have got enough of space in the current cylinder group, so we * can relocate just a few blocks, and let the summary information * grow in place where it is right now. */ DBG_TRC; cbase = cgbase(&osblock, ocscg); /* old and new are equal */ dupper = sblock.fs_csaddr - cbase + howmany(sblock.fs_cssize, sblock.fs_fsize); odupper = osblock.fs_csaddr - cbase + howmany(osblock.fs_cssize, osblock.fs_fsize); sblock.fs_dsize -= dupper-odupper; /* * Allocate the space for the array of blocks to be relocated. */ bp=(struct gfs_bpp *)malloc(((dupper-odupper)/sblock.fs_frag+2)* sizeof(struct gfs_bpp)); + if(bp == NULL) { + errx(1, "malloc failed"); + } memset((char *)bp, 0, sizeof(struct gfs_bpp)); /* * Lock all new frags needed for the cylinder group summary. This is * done per fragment in the first and last block of the new required * area, and per block for all other blocks. * * Handle the first new block here (but only if some fragments where * already used for the cylinder summary). */ ind=0; frag_adjust(odupper, -1); for(d=odupper; ((d= dupper) { bp[ind].flags|=GFS_FL_LAST; } ind++; } } else { clrbit(cg_blksfree(&acg), d); acg.cg_cs.cs_nffree--; sblock.fs_cstotal.cs_nffree--; } /* * No cluster handling is needed here, as there was at least * one fragment in use by the cylinder summary in the old * file system. * No block-free counter handling here as this block was not * a free block. */ } frag_adjust(odupper, 1); /* * Handle all needed complete blocks here. */ for(; d+sblock.fs_frag<=dupper; d+=sblock.fs_frag) { - DBG_PRINT1("scg block check loop d=%d\n", d); + DBG_PRINT1("scg block check loop d=%d\n", + d); if(!isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) { for(f=d; f 0) { clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); for(lcs=0, l=(d/sblock.fs_frag)+1; lcs 0) { clrbit(cg_clustersfree(&acg), d/sblock.fs_frag); for(lcs=0, l=(d/sblock.fs_frag)+1; lcs%d) block relocated\n", bp[i].old, bp[i].new); + DBG_PRINT2("scg (%d->%d) block relocated\n", + bp[i].old, + bp[i].new); } /* * Now we have to update all references to any fragment which * belongs to any block relocated. We iterate now over all * cylinder groups, within those over all non zero length * inodes. */ for(cylno=0; cylno=0 ; inc--) { updrefs(cylno, (ino_t)inc, bp, fsi, fso, Nflag); } } /* * All inodes are checked, now make sure the number of * references found make sense. */ for(i=0; isblock.fs_frag)) { - fprintf(stderr, - "error: %d refs found for block %d.\n", + warnx("error: %d refs found for block %d.", bp[i].found, bp[i].old); } } } /* * The following statistics are not changed here: * sblock.fs_cstotal.cs_ndir * sblock.fs_cstotal.cs_nifree * The following statistics were already updated on the fly: * sblock.fs_cstotal.cs_nffree * sblock.fs_cstotal.cs_nbfree * As the statistics for this cylinder group are ready, copy it to * the summary information array. */ *cs = acg.cg_cs; /* * Write summary cylinder group back to disk. */ wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), sblock.fs_cgsize, (char *)&acg, fso, Nflag); DBG_PRINT0("scg written\n"); - DBG_DUMP_CG(&sblock, "new summary cg", &acg); + DBG_DUMP_CG(&sblock, + "new summary cg", + &acg); DBG_LEAVE; return; } /* ************************************************************** rdfs ***** */ /* * Here we read some block(s) from disk. */ static void rdfs(daddr_t bno, int size, char *bf, int fsi) { DBG_FUNC("rdfs") int n; DBG_ENTER; if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) { - fprintf(stderr, "seek error: %ld\n", (long)bno); - err(33, "rdfs"); + err(33, "rdfs: seek error: %ld", (long)bno); } n = read(fsi, bf, (size_t)size); if (n != size) { - fprintf(stderr, "read error: %ld\n", (long)bno); - err(34, "rdfs"); + err(34, "rdfs: read error: %ld", (long)bno); } DBG_LEAVE; return; } /* ************************************************************** wtfs ***** */ /* * Here we write some block(s) to disk. */ static void wtfs(daddr_t bno, int size, char *bf, int fso, int Nflag) { DBG_FUNC("wtfs") int n; DBG_ENTER; if (Nflag) { DBG_LEAVE; return; } if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0) { - fprintf(stderr, "seek error: %ld\n", (long)bno); - err(35, "wtfs"); + err(35, "wtfs: seek error: %ld", (long)bno); } n = write(fso, bf, (size_t)size); if (n != size) { - fprintf(stderr, "write error: %ld\n", (long)bno); - err(36, "wtfs"); + err(36, "wtfs: write error: %ld", (long)bno); } DBG_LEAVE; return; } /* ************************************************************* alloc ***** */ /* * Here we allocate a free block in the current cylinder group. It is assumed, * that acg contains the current cylinder group. As we may take a block from * somewhere in the filesystem we have to handle cluster summary here. */ static daddr_t alloc(void) { DBG_FUNC("alloc") daddr_t d, blkno; int lcs1, lcs2; int l; int csmin, csmax; int dlower, dupper, dmax; DBG_ENTER; if (acg.cg_magic != CG_MAGIC) { - fprintf(stderr, "acg: bad magic number\n"); + warnx("acg: bad magic number"); DBG_LEAVE; return (0); } if (acg.cg_cs.cs_nbfree == 0) { - fprintf(stderr, "error: cylinder group ran out of space\n"); + warnx("error: cylinder group ran out of space"); DBG_LEAVE; return (0); } /* * We start seeking for free blocks only from the space available after * the end of the new grown cylinder summary. Otherwise we allocate a * block here which we have to relocate a couple of seconds later again * again, and we are not prepared to to this anyway. */ blkno=-1; dlower=cgsblock(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); dupper=cgdmin(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx); dmax=cgbase(&sblock, acg.cg_cgx)+sblock.fs_fpg; if (dmax > sblock.fs_size) { dmax = sblock.fs_size; } dmax-=cgbase(&sblock, acg.cg_cgx); /* retransform into cg */ csmin=sblock.fs_csaddr-cgbase(&sblock, acg.cg_cgx); csmax=csmin+howmany(sblock.fs_cssize, sblock.fs_fsize); - DBG_PRINT3("seek range: dl=%d, du=%d, dm=%d\n", dlower, dupper, dmax); - DBG_PRINT2("range cont: csmin=%d, csmax=%d\n", csmin, csmax); + DBG_PRINT3("seek range: dl=%d, du=%d, dm=%d\n", + dlower, + dupper, + dmax); + DBG_PRINT2("range cont: csmin=%d, csmax=%d\n", + csmin, + csmax); for(d=0; (d=csmin && d<=csmax) { continue; } if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, d))) { blkno = fragstoblks(&sblock, d);/* Yeah found a block */ break; } } for(d=dupper; (d=csmin && d<=csmax) { continue; } if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, d))) { blkno = fragstoblks(&sblock, d);/* Yeah found a block */ break; } } if(blkno==-1) { - fprintf(stderr, - "internal error: couldn't find promised block in cg\n"); + warnx("internal error: couldn't find promised block in cg"); DBG_LEAVE; return (0); } /* * This is needed if the block was found already in the first loop. */ d=blkstofrags(&sblock, blkno); clrblock(&sblock, cg_blksfree(&acg), blkno); if (sblock.fs_contigsumsize > 0) { /* * Handle the cluster allocation bitmap. */ clrbit(cg_clustersfree(&acg), blkno); /* * We possibly have split a cluster here, so we have to do - * recalculate the sizes of the remaining cluster halfes now, + * recalculate the sizes of the remaining cluster halves now, * and use them for updating the cluster summary information. * * Lets start with the blocks before our allocated block ... */ for(lcs1=0, l=blkno-1; lcs1fs_frag) { case 8: DBG_LEAVE; return (cp[h] == 0xff); case 4: mask = 0x0f << ((h & 0x1) << 2); DBG_LEAVE; return ((cp[h >> 1] & mask) == mask); case 2: mask = 0x03 << ((h & 0x3) << 1); DBG_LEAVE; return ((cp[h >> 2] & mask) == mask); case 1: mask = 0x01 << (h & 0x7); DBG_LEAVE; return ((cp[h >> 3] & mask) == mask); default: fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag); DBG_LEAVE; return (0); } } /* ********************************************************** clrblock ***** */ /* * Here we allocate a complete block in the block map. For more details again * please see the source of newfs(8), as this function is taken over almost * unchanged. */ static void clrblock(struct fs *fs, unsigned char *cp, int h) { DBG_FUNC("clrblock") DBG_ENTER; switch ((fs)->fs_frag) { case 8: cp[h] = 0; break; case 4: cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); break; case 2: cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); break; case 1: cp[h >> 3] &= ~(0x01 << (h & 0x7)); break; default: - fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag); + warnx("clrblock bad fs_frag %d", fs->fs_frag); break; } DBG_LEAVE; return; } /* ********************************************************** setblock ***** */ /* * Here we free a complete block in the free block map. For more details again * please see the source of newfs(8), as this function is taken over almost * unchanged. */ static void setblock(struct fs *fs, unsigned char *cp, int h) { DBG_FUNC("setblock") DBG_ENTER; switch (fs->fs_frag) { case 8: cp[h] = 0xff; break; case 4: cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); break; case 2: cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); break; case 1: cp[h >> 3] |= (0x01 << (h & 0x7)); break; default: - fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag); + warnx("setblock bad fs_frag %d", fs->fs_frag); break; } DBG_LEAVE; return; } /* ************************************************************ ginode ***** */ /* * This function provides access to an individual inode. We find out in which * block the requested inode is located, read it from disk if needed, and * return the pointer into that block. We maintain a cache of one block to - * not read the same block again and again if we iterate lineary over all + * not read the same block again and again if we iterate linearly over all * inodes. */ static struct dinode * ginode(ino_t inumber, int fsi, int cg) { DBG_FUNC("ginode") ufs_daddr_t iblk; static ino_t startinum=0; /* first inode in cached block */ struct dinode *pi; DBG_ENTER; pi=(struct dinode *)ablk; inumber+=(cg * sblock.fs_ipg); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { /* * The block needed is not cached, so we have to read it from * disk now. */ iblk = ino_to_fsba(&sblock, inumber); in_src=fsbtodb(&sblock, iblk); rdfs(in_src, sblock.fs_bsize, (char *)&ablk, fsi); startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } DBG_LEAVE; return (&(pi[inumber % INOPB(&sblock)])); } /* ****************************************************** charsperline ***** */ /* * Figure out how many lines our current terminal has. For more details again * please see the source of newfs(8), as this function is taken over almost * unchanged. */ static int charsperline(void) { DBG_FUNC("charsperline") int columns; char *cp; struct winsize ws; DBG_ENTER; columns = 0; if (ioctl(0, TIOCGWINSZ, &ws) != -1) { columns = ws.ws_col; } if (columns == 0 && (cp = getenv("COLUMNS"))) { columns = atoi(cp); } if (columns == 0) { columns = 80; /* last resort */ } DBG_LEAVE; return columns; } /* ************************************************************** main ***** */ /* * growfs(8) is a utility which allows to increase the size of an existing * ufs filesystem. Currently this can only be done on unmounted file system. * It recognizes some command line options to specify the new desired size, * and it does some basic checkings. The old file system size is determined * and after some more checks like we can really access the new last block * on the disk etc. we calculate the new parameters for the superblock. After * having done this we just call growfs() which will do the work. Before * we finish the only thing left is to update the disklabel. * We still have to provide support for snapshots. Therefore we first have to * understand what data structures are always replicated in the snapshot on * creation, for all other blocks we touch during our procedure, we have to - * keep the old blocks unchanged somewere available for the snapshots. If we + * keep the old blocks unchanged somewhere available for the snapshots. If we * are lucky, then we only have to handle our blocks to be relocated in that * way. * Also we have to consider in what order we actually update the critical - * data structures of the filesystem to make sure, that in case of a desaster + * data structures of the filesystem to make sure, that in case of a disaster * fsck(8) is still able to restore any lost data. - * The forseen last step then will be to provide for growing even mounted - * file systems. There we have to extend the mount() systemcall to provide + * The foreseen last step then will be to provide for growing even mounted + * file systems. There we have to extend the mount() system call to provide * userland access to the file system locking facility. */ int main(int argc, char **argv) { DBG_FUNC("main") - char *a0, *device, *special, *cp; + char *device, *special, *cp; char ch; unsigned long size=0; size_t len; int Nflag=0; int ExpertFlag=0; struct stat st; struct disklabel *lp; struct partition *pp; int fsi,fso; char reply[5]; #ifdef FSMAXSNAP int j; #endif /* FSMAXSNAP */ DBG_ENTER; - a0=*argv; /* save argv[0] for usage() */ while((ch=getopt(argc, argv, "Ns:vy")) != -1) { switch(ch) { case 'N': Nflag=1; break; case 's': size=(size_t)atol(optarg); if(size<1) { - usage(a0); + usage(); } break; case 'v': /* for compatibility to newfs */ break; case 'y': ExpertFlag=1; break; case '?': /* FALLTHROUGH */ default: - usage(a0); + usage(); } } argc -= optind; argv += optind; if(argc != 1) { - usage(a0); + usage(); } device=*argv; /* * Now try to guess the (raw)device name. */ if (0 == strrchr(device, '/')) { /* * No path prefix was given, so try in that order: * /dev/r%s * /dev/%s * /dev/vinum/r%s * /dev/vinum/%s. * * FreeBSD now doesn't distinguish between raw and block * devices any longer, but it should still work this way. */ len=strlen(device)+strlen(_PATH_DEV)+2+strlen("vinum/"); special=(char *)malloc(len); + if(special == NULL) { + errx(1, "malloc failed"); + } snprintf(special, len, "%sr%s", _PATH_DEV, device); if (stat(special, &st) == -1) { snprintf(special, len, "%s%s", _PATH_DEV, device); if (stat(special, &st) == -1) { snprintf(special, len, "%svinum/r%s", _PATH_DEV, device); if (stat(special, &st) == -1) { /* For now this is the 'last resort' */ snprintf(special, len, "%svinum/%s", _PATH_DEV, device); } } } device = special; } /* * Try to access our devices for writing ... */ if (Nflag) { fso = -1; } else { fso = open(device, O_WRONLY); if (fso < 0) { - fprintf(stderr, "%s: %s\n", device, strerror(errno)); - exit(-1); + err(1, "%s", device); } } /* * ... and reading. */ fsi = open(device, O_RDONLY); if (fsi < 0) { - fprintf(stderr, "%s: %s\n", device, strerror(errno)); - exit(-1); + err(1, "%s", device); } /* * Try to read a label and gess the slice if not specified. This * code should guess the right thing and avaid to bother the user * user with the task of specifying the option -v on vinum volumes. */ cp=device+strlen(device)-1; lp = get_disklabel(fsi); if(lp->d_type == DTYPE_VINUM) { pp = &lp->d_partitions[0]; } else if (isdigit(*cp)) { pp = &lp->d_partitions[2]; } else if (*cp>='a' && *cp<='h') { pp = &lp->d_partitions[*cp - 'a']; } else { - fprintf(stderr, "unknown device\n"); - exit(-1); + errx(1, "unknown device"); } /* * Check if that partition looks suited for growing a file system. */ if (pp->p_size < 1) { - fprintf(stderr, "partition is unavailable\n"); - exit(-1); + errx(1, "partition is unavailable"); } if (pp->p_fstype != FS_BSDFFS) { - fprintf(stderr, "partition not 4.2BSD\n"); - exit(-1); + errx(1, "partition not 4.2BSD"); } /* * Read the current superblock, and take a backup. */ rdfs((daddr_t)(SBOFF/DEV_BSIZE), SBSIZE, (char *)&(osblock), fsi); if (osblock.fs_magic != FS_MAGIC) { - fprintf(stderr, "superblock not recognized\n"); - exit(-1); + errx(1, "superblock not recognized"); } memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2)); DBG_OPEN("/tmp/growfs.debug"); /* already here we need a superblock */ - DBG_DUMP_FS(&sblock, "old sblock"); + DBG_DUMP_FS(&sblock, + "old sblock"); /* * Determine size to grow to. Default to the full size specified in * the disk label. */ sblock.fs_size = dbtofsb(&osblock, pp->p_size); if (size != 0) { if (size > pp->p_size){ - fprintf(stderr, - "There is not enough space (%d < %ld)\n", + errx(1, "There is not enough space (%d < %ld)", pp->p_size, size); - exit(-1); } sblock.fs_size = dbtofsb(&osblock, size); } /* * Are we really growing ? */ if(osblock.fs_size >= sblock.fs_size) { - fprintf(stderr, "we are not growing (%d->%d)\n", - osblock.fs_size, sblock.fs_size); - exit(-1); + errx(1, "we are not growing (%d->%d)", osblock.fs_size, + sblock.fs_size); } #ifdef FSMAXSNAP /* * Check if we find an active snapshot. */ if(ExpertFlag == 0) { for(j=0; jp_size-1, DEV_BSIZE, (char *)&sblock, fso, Nflag); /* * Now calculate new superblock values and check for reasonable * bound for new file system size: * fs_size: is derived from label or user input * fs_dsize: should get updated in the routines creating or * updating the cylinder groups on the fly * fs_cstotal: should get updated in the routines creating or * updating the cylinder groups */ /* * Update the number of cylinders in the filesystem. */ sblock.fs_ncyl = sblock.fs_size * NSPF(&sblock) / sblock.fs_spc; if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) { sblock.fs_ncyl++; } /* * Update the number of cylinder groups in the filesystem. */ sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg; if (sblock.fs_ncyl % sblock.fs_cpg) { sblock.fs_ncg++; } if ((sblock.fs_size - (sblock.fs_ncg-1) * sblock.fs_fpg) < sblock.fs_fpg && cgdmin(&sblock, (sblock.fs_ncg-1))- cgbase(&sblock, (sblock.fs_ncg-1)) > (sblock.fs_size - (sblock.fs_ncg-1) * sblock.fs_fpg )) { /* * The space in the new last cylinder group is too small, * so revert back. */ sblock.fs_ncg--; #if 1 /* this is a bit more safe */ sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg; #else sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg; #endif sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg; printf( "Warning: %d sector(s) cannot be allocated.\n", (sblock.fs_size-(sblock.fs_ncg)*sblock.fs_fpg) * NSPF(&sblock)); sblock.fs_size = sblock.fs_ncyl * sblock.fs_spc / NSPF(&sblock); } /* * Update the space for the cylinder group summary information in the * respective cylinder group data area. */ sblock.fs_cssize = fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); if(osblock.fs_size >= sblock.fs_size) { - fprintf(stderr, "not enough new space\n"); - exit(-1); + errx(1, "not enough new space"); } DBG_PRINT0("sblock calculated\n"); /* * Ok, everything prepared, so now let's do the tricks. */ growfs(fsi, fso, Nflag); /* * Update the disk label. */ pp->p_fsize = sblock.fs_fsize; pp->p_frag = sblock.fs_frag; pp->p_cpg = sblock.fs_cpg; return_disklabel(fso, lp, Nflag); DBG_PRINT0("label rewritten\n"); close(fsi); if(fso>-1) close(fso); DBG_CLOSE; DBG_LEAVE; return 0; } /* ************************************************** return_disklabel ***** */ /* * Write the updated disklabel back to disk. */ static void return_disklabel(int fd, struct disklabel *lp, int Nflag) { DBG_FUNC("return_disklabel") u_short sum; u_short *ptr; DBG_ENTER; if(!lp) { DBG_LEAVE; return; } if(!Nflag) { lp->d_checksum=0; sum = 0; ptr=(u_short *)lp; /* * recalculate checksum */ while(ptr < (u_short *)&lp->d_partitions[lp->d_npartitions]) { sum ^= *ptr++; } lp->d_checksum=sum; if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { - fprintf(stderr, "DIOCWDINFO failed\n"); - exit(-1); + errx(1, "DIOCWDINFO failed"); } } free(lp); DBG_LEAVE; return ; } /* ***************************************************** get_disklabel ***** */ /* * Read the disklabel from disk. */ static struct disklabel * get_disklabel(int fd) { DBG_FUNC("get_disklabel") static struct disklabel *lab; DBG_ENTER; lab=(struct disklabel *)malloc(sizeof(struct disklabel)); if (!lab) { - fprintf(stderr, "malloc failed\n"); - exit(-1); + errx(1, "malloc failed"); } if (ioctl(fd, DIOCGDINFO, (char *)lab) < 0) { - fprintf(stderr, "DIOCGDINFO failed\n"); - exit(-1); + errx(1, "DIOCGDINFO failed"); } DBG_LEAVE; return (lab); } /* ************************************************************* usage ***** */ /* * Dump a line of usage. */ static void -usage(char *name) +usage(void) { DBG_FUNC("usage") - char *basename; DBG_ENTER; - basename=strrchr(name, '/'); - if(!basename) { - basename=name; - } else { - basename++; - } - fprintf(stderr, "usage: %s [-Ny] [-s size] special_file\n", basename); + fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n"); + DBG_LEAVE; - exit(-1); + exit(1); } /* *********************************************************** updclst ***** */ /* * This updates most paramters and the bitmap related to cluster. We have to * assume, that sblock, osblock, acg are set up. */ static void updclst(int block) { DBG_FUNC("updclst") static int lcs=0; DBG_ENTER; if(sblock.fs_contigsumsize < 1) { /* no clustering */ return; } /* * update cluster allocation map */ setbit(cg_clustersfree(&acg), block); /* * update cluster summary table */ if(!lcs) { /* * calculate size for the trailing cluster */ for(block--; lcsdi_mode & IFMT)==IFDIR || (ino->di_mode & IFMT)==IFREG || (ino->di_mode & IFMT)==IFLNK)) { DBG_LEAVE; return; /* only check DIR, FILE, LINK */ } if(((ino->di_mode & IFMT)==IFLNK) && (ino->di_sizedi_size) { DBG_LEAVE; return; /* skip empty file */ } if(!ino->di_blocks) { DBG_LEAVE; return; /* skip empty swiss cheesy file or old fastlink */ } - DBG_PRINT2("scg checking inode (%d in %d)\n", in, cg); + DBG_PRINT2("scg checking inode (%d in %d)\n", + in, + cg); /* * Start checking all direct blocks. */ remaining_blocks=howmany(ino->di_size, sblock.fs_bsize); for(ictr=0; ictr < MIN(NDADDR, (unsigned int)remaining_blocks); ictr++) { iptr=&(ino->di_db[ictr]); if(*iptr) { cond_bl_upd(iptr, bp, GFS_PS_INODE, fso, Nflag); } } DBG_PRINT0("~~scg direct blocks checked\n"); remaining_blocks-=NDADDR; if(remaining_blocks<0) { DBG_LEAVE; return; } if(ino->di_ib[0]) { /* * Start checking first indirect block */ cond_bl_upd(&(ino->di_ib[0]), bp, GFS_PS_INODE, fso, Nflag); i1_src=fsbtodb(&sblock, ino->di_ib[0]); rdfs(i1_src, sblock.fs_bsize, (char *)&i1blk, fsi); for(ictr=0; ictr < MIN(howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)), (unsigned int)remaining_blocks); ictr++) { iptr=&((ufs_daddr_t *)&i1blk)[ictr]; if(*iptr) { cond_bl_upd(iptr, bp, GFS_PS_IND_BLK_LVL1, fso, Nflag); } } } DBG_PRINT0("scg indirect_1 blocks checked\n"); remaining_blocks-= howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); if(remaining_blocks<0) { DBG_LEAVE; return; } if(ino->di_ib[1]) { /* * Start checking second indirect block */ cond_bl_upd(&(ino->di_ib[1]), bp, GFS_PS_INODE, fso, Nflag); i2_src=fsbtodb(&sblock, ino->di_ib[1]); rdfs(i2_src, sblock.fs_bsize, (char *)&i2blk, fsi); for(ind2ctr=0; ind2ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); ind2ctr++) { ind2ptr=&((ufs_daddr_t *)&i2blk)[ind2ctr]; if(!*ind2ptr) { continue; } cond_bl_upd(ind2ptr, bp, GFS_PS_IND_BLK_LVL2, fso, Nflag); i1_src=fsbtodb(&sblock, *ind2ptr); rdfs(i1_src, sblock.fs_bsize, (char *)&i1blk, fsi); for(ictr=0; ictrdi_ib[2]) { /* * Start checking third indirect block */ cond_bl_upd(&(ino->di_ib[2]), bp, GFS_PS_INODE, fso, Nflag); i3_src=fsbtodb(&sblock, ino->di_ib[2]); rdfs(i3_src, sblock.fs_bsize, (char *)&i3blk, fsi); for(ind3ctr=0; ind3ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); ind3ctr ++) { ind3ptr=&((ufs_daddr_t *)&i3blk)[ind3ctr]; if(!*ind3ptr) { continue; } cond_bl_upd(ind3ptr, bp, GFS_PS_IND_BLK_LVL3, fso, Nflag); i2_src=fsbtodb(&sblock, *ind3ptr); rdfs(i2_src, sblock.fs_bsize, (char *)&i2blk, fsi); for(ind2ctr=0; ind2ctr < howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)); ind2ctr ++) { ind2ptr=&((ufs_daddr_t *)&i2blk)[ind2ctr]; if(!*ind2ptr) { continue; } cond_bl_upd(ind2ptr, bp, GFS_PS_IND_BLK_LVL2, fso, Nflag); i1_src=fsbtodb(&sblock, *ind2ptr); rdfs(i1_src, sblock.fs_bsize, (char *)&i1blk, fsi); for(ictr=0; ictr < MIN(howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)), (unsigned int)remaining_blocks); ictr++) { iptr=&((ufs_daddr_t *)&i1blk)[ictr]; if(*iptr) { cond_bl_upd(iptr, bp, GFS_PS_IND_BLK_LVL1, fso, Nflag); } } } } } DBG_PRINT0("scg indirect_3 blocks checked\n"); DBG_LEAVE; return; }