Changeset View
Changeset View
Standalone View
Standalone View
sbin/fsck_ffs/setup.c
| Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
| #include <limits.h> | #include <limits.h> | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <libufs.h> | #include <libufs.h> | ||||
| #include "fsck.h" | #include "fsck.h" | ||||
| struct inoinfo **inphead, **inpsort; /* info about all inodes */ | struct inoinfo **inphead, **inpsort; /* info about all inodes */ | ||||
| struct inode snaplist[FSMAXSNAP + 1]; /* list of active snapshots */ | |||||
| int snapcnt; /* number of active snapshots */ | |||||
| char *copybuf; /* buffer to copy snapshot blocks */ | |||||
| static int sbhashfailed; | static int sbhashfailed; | ||||
| #define POWEROF2(num) (((num) & ((num) - 1)) == 0) | #define POWEROF2(num) (((num) & ((num) - 1)) == 0) | ||||
| static int calcsb(char *dev, int devfd, struct fs *fs); | static int calcsb(char *dev, int devfd, struct fs *fs); | ||||
| static void saverecovery(int readfd, int writefd); | static void saverecovery(int readfd, int writefd); | ||||
| static int chkrecovery(int devfd); | static int chkrecovery(int devfd); | ||||
| static int getlbnblkno(struct inodesc *); | |||||
| static int checksnapinfo(struct inode *); | |||||
| /* | /* | ||||
| * Read in a superblock finding an alternate if necessary. | * Read in a superblock finding an alternate if necessary. | ||||
| * Return 1 if successful, 0 if unsuccessful, -1 if file system | * Return 1 if successful, 0 if unsuccessful, -1 if file system | ||||
| * is already clean (ckclean and preen mode only). | * is already clean (ckclean and preen mode only). | ||||
| */ | */ | ||||
| int | int | ||||
| setup(char *dev) | setup(char *dev) | ||||
| { | { | ||||
| long bmapsize; | long i, bmapsize; | ||||
| struct inode ip; | |||||
| /* | /* | ||||
| * We are expected to have an open file descriptor and a superblock. | * We are expected to have an open file descriptor and a superblock. | ||||
| */ | */ | ||||
| if (fsreadfd < 0 || havesb == 0) { | if (fsreadfd < 0 || havesb == 0) { | ||||
| if (debug) | if (debug) | ||||
| printf("setup: bad fsreadfd or missing superblock\n"); | printf("setup: bad fsreadfd or missing superblock\n"); | ||||
| return (0); | return (0); | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if (inpsort == NULL || inphead == NULL) { | ||||
| printf("cannot alloc %ju bytes for inphead\n", | printf("cannot alloc %ju bytes for inphead\n", | ||||
| (uintmax_t)numdirs * sizeof(struct inoinfo *)); | (uintmax_t)numdirs * sizeof(struct inoinfo *)); | ||||
| goto badsb; | goto badsb; | ||||
| } | } | ||||
| if (sblock.fs_flags & FS_DOSOFTDEP) | if (sblock.fs_flags & FS_DOSOFTDEP) | ||||
| usedsoftdep = 1; | usedsoftdep = 1; | ||||
| else | else | ||||
| usedsoftdep = 0; | usedsoftdep = 0; | ||||
| /* | |||||
| * Collect any snapshot inodes so that we can allow them to | |||||
| * claim any blocks that we free. The code for doing this is | |||||
| * imported here and into inode.c from sys/ufs/ffs/ffs_snapshot.c. | |||||
| */ | |||||
| for (snapcnt = 0; snapcnt < FSMAXSNAP; snapcnt++) { | |||||
| if (sblock.fs_snapinum[snapcnt] == 0) | |||||
| break; | |||||
| ginode(sblock.fs_snapinum[snapcnt], &ip); | |||||
| if ((DIP(ip.i_dp, di_mode) & IFMT) == IFREG && | |||||
| (DIP(ip.i_dp, di_flags) & SF_SNAPSHOT) != 0 && | |||||
| checksnapinfo(&ip)) { | |||||
| if (debug) | |||||
| printf("Load snapshot %jd\n", | |||||
| (intmax_t)sblock.fs_snapinum[snapcnt]); | |||||
| snaplist[snapcnt] = ip; | |||||
| continue; | |||||
| } | |||||
| printf("Removing non-snapshot inode %ju from snapshot list\n", | |||||
| (uintmax_t)sblock.fs_snapinum[snapcnt]); | |||||
| irelse(&ip); | |||||
| for (i = snapcnt + 1; i < FSMAXSNAP; i++) { | |||||
| if (sblock.fs_snapinum[i] == 0) | |||||
| break; | |||||
| sblock.fs_snapinum[i - 1] = sblock.fs_snapinum[i]; | |||||
| } | |||||
| sblock.fs_snapinum[i - 1] = 0; | |||||
| snapcnt--; | |||||
| sbdirty(); | |||||
| } | |||||
| if (snapcnt > 0 && copybuf == NULL) { | |||||
| copybuf = Malloc(sblock.fs_bsize); | |||||
| if (copybuf == NULL) | |||||
| errx(EEXIT, "cannot allocate space for snapshot " | |||||
| "copy buffer"); | |||||
| } | |||||
| return (1); | return (1); | ||||
| badsb: | badsb: | ||||
| ckfini(0); | ckfini(0); | ||||
| return (0); | return (0); | ||||
| } | |||||
| /* | |||||
| * Check for valid snapshot information. | |||||
| * | |||||
| * Each snapshot has a list of blocks that have been copied. This list | |||||
| * is consulted before checking the snapshot inode. Its purpose is to | |||||
| * speed checking of commonly checked blocks and to avoid recursive | |||||
| * checks of the snapshot inode. In particular, the list must contain | |||||
| * the superblock, the superblock summary information, and all the | |||||
| * cylinder group blocks. The list may contain other commonly checked | |||||
| * pointers such as those of the blocks that contain the snapshot inodes. | |||||
| * The list is sorted into block order to allow binary search lookup. | |||||
| * | |||||
| * The twelve direct direct block pointers of the snapshot are always | |||||
| * copied, so we test for them first before checking the list itself | |||||
| * (i.e., they are not in the list). | |||||
| * | |||||
| * The checksnapinfo() routine needs to ensure that the list contains at | |||||
| * least the super block, its summary information, and the cylinder groups. | |||||
| * Here we check the list first for the superblock, zero or more cylinder | |||||
| * groups up to the location of the superblock summary information, the | |||||
| * summary group information, and any remaining cylinder group maps that | |||||
| * follow it. We skip over any other entries in the list. | |||||
| */ | |||||
| #define CHKBLKINLIST(chkblk) \ | |||||
| /* All UFS_NDADDR blocks are copied */ \ | |||||
| if ((chkblk) >= UFS_NDADDR) { \ | |||||
| /* Skip over blocks that are not of interest */ \ | |||||
kib: Could this be a function? You would need to pass several parameters, including manually… | |||||
Done Inline ActionsI started with this as a function and found that it was even less clear than the macro. It ends up looking a lot like the macro except that it is more convoluted. One of its parameters is daddr_t **blkp so every use of blkp has an extra level of indirection. At least in the macro it is clear when you are incrementing the pointer versus using the pointer. mckusick: I started with this as a function and found that it was even less clear than the macro. It ends… | |||||
| while (*blkp < (chkblk) && blkp < lastblkp) \ | |||||
| blkp++; \ | |||||
| /* Fail if end of list and not all blocks found */ \ | |||||
| if (blkp >= lastblkp) { \ | |||||
| pwarn("UFS%d snapshot inode %jd failed: " \ | |||||
| "improper block list length (%jd)\n", \ | |||||
| sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ | |||||
| (intmax_t)snapip->i_number, \ | |||||
| (intmax_t)(lastblkp - &snapblklist[0])); \ | |||||
| status = 0; \ | |||||
| } \ | |||||
| /* Fail if block we seek is missing */ \ | |||||
| else if (*blkp++ != (chkblk)) { \ | |||||
| pwarn("UFS%d snapshot inode %jd failed: " \ | |||||
| "block list (%jd) != %s (%jd)\n", \ | |||||
| sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \ | |||||
| (intmax_t)snapip->i_number, \ | |||||
| (intmax_t)blkp[-1], #chkblk, \ | |||||
| (intmax_t)chkblk); \ | |||||
| status = 0; \ | |||||
| } \ | |||||
| } | |||||
| static int | |||||
| checksnapinfo(struct inode *snapip) | |||||
| { | |||||
| struct fs *fs; | |||||
Not Done Inline ActionsCould you, please, add more comments to the code. It is not completely clear to me what is checked there. In fact, the line 239 if (*blkp++ != (chkblk)) looks like we just check that the superblock/summary/cgs lists fit into the snapshot file size. Am I missing something? kib: Could you, please, add more comments to the code.
It is not completely clear to me what is… | |||||
Done Inline ActionsHopefully the added comments make it clearer what is being checked. mckusick: Hopefully the added comments make it clearer what is being checked. | |||||
| struct bufarea *bp; | |||||
| struct inodesc idesc; | |||||
| daddr_t *snapblklist, *blkp, *lastblkp, csblkno; | |||||
| int cg, loc, len, status; | |||||
| ufs_lbn_t lbn; | |||||
| size_t size; | |||||
| fs = &sblock; | |||||
| memset(&idesc, 0, sizeof(struct inodesc)); | |||||
| idesc.id_type = ADDR; | |||||
| idesc.id_func = getlbnblkno; | |||||
| idesc.id_number = snapip->i_number; | |||||
| lbn = howmany(fs->fs_size, fs->fs_frag); | |||||
| idesc.id_parent = lbn; /* sought after blkno */ | |||||
| if ((ckinode(snapip->i_dp, &idesc) & FOUND) == 0) | |||||
| return (0); | |||||
| size = fragroundup(fs, | |||||
| DIP(snapip->i_dp, di_size) - lblktosize(fs, lbn)); | |||||
| bp = getdatablk(idesc.id_parent, size, BT_DATA); | |||||
| snapblklist = (daddr_t *)bp->b_un.b_buf; | |||||
| /* | |||||
| * snapblklist[0] is the size of the list | |||||
| * snapblklist[1] is the first element of the list | |||||
| * | |||||
| * We need to be careful to bound the size of the list and verify | |||||
| * that we have not run off the end of it if it or its size has | |||||
| * been corrupted. | |||||
| */ | |||||
| blkp = &snapblklist[1]; | |||||
| lastblkp = &snapblklist[MAX(0, | |||||
| MIN(snapblklist[0] + 1, size / sizeof(daddr_t)))]; | |||||
| status = 1; | |||||
| /* Check that the superblock is listed. */ | |||||
| CHKBLKINLIST(lblkno(fs, fs->fs_sblockloc)); | |||||
| if (status == 0) | |||||
| goto out; | |||||
| /* | |||||
| * Calculate where the summary information is located. | |||||
| * Usually it is in the first cylinder group, but growfs | |||||
| * may move it to the first cylinder group that it adds. | |||||
| * | |||||
| * Check all cylinder groups up to the summary information. | |||||
| */ | |||||
| csblkno = fragstoblks(fs, fs->fs_csaddr); | |||||
| for (cg = 0; cg < fs->fs_ncg; cg++) { | |||||
| if (fragstoblks(fs, cgtod(fs, cg)) > csblkno) | |||||
| break; | |||||
| CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); | |||||
| if (status == 0) | |||||
| goto out; | |||||
| } | |||||
| /* Check the summary information block(s). */ | |||||
| len = howmany(fs->fs_cssize, fs->fs_bsize); | |||||
| for (loc = 0; loc < len; loc++) { | |||||
| CHKBLKINLIST(csblkno + loc); | |||||
| if (status == 0) | |||||
| goto out; | |||||
| } | |||||
| /* Check the remaining cylinder groups. */ | |||||
| for (; cg < fs->fs_ncg; cg++) { | |||||
| CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg))); | |||||
| if (status == 0) | |||||
| goto out; | |||||
| } | |||||
| out: | |||||
| brelse(bp); | |||||
| return (status); | |||||
| } | |||||
| /* | |||||
| * Return the block number associated with a specified inode lbn. | |||||
| * Requested lbn is in id_parent. If found, block is returned in | |||||
| * id_parent. | |||||
| */ | |||||
| static int | |||||
| getlbnblkno(struct inodesc *idesc) | |||||
| { | |||||
| if (idesc->id_lbn < idesc->id_parent) | |||||
| return (KEEPON); | |||||
| idesc->id_parent = idesc->id_blkno; | |||||
| return (STOP | FOUND); | |||||
| } | } | ||||
| /* | /* | ||||
| * Open a device or file to be checked by fsck. | * Open a device or file to be checked by fsck. | ||||
| */ | */ | ||||
| int | int | ||||
| openfilesys(char *dev) | openfilesys(char *dev) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 256 Lines • Show Last 20 Lines | |||||
Could this be a function? You would need to pass several parameters, including manually constructed string fragment for pwarn, and a return value to pass control to fail label outside, but IMO it is much cleaner than such unwieldy macro.