]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/fsck_ffs/gjournal.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sbin / fsck_ffs / gjournal.c
1 /*-
2  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Copyright (c) 1982, 1986, 1989, 1993
27  *      The Regents of the University of California.  All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  *    notice, this list of conditions and the following disclaimer.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  * 4. Neither the name of the University nor the names of its contributors
38  *    may be used to endorse or promote products derived from this software
39  *    without specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  */
53
54 #include <sys/cdefs.h>
55 __FBSDID("$FreeBSD$");
56
57 #include <sys/param.h>
58 #include <sys/disklabel.h>
59 #include <sys/mount.h>
60 #include <sys/stat.h>
61
62 #include <ufs/ufs/ufsmount.h>
63 #include <ufs/ufs/dinode.h>
64 #include <ufs/ffs/fs.h>
65
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <stdint.h>
69 #include <libufs.h>
70 #include <strings.h>
71 #include <err.h>
72 #include <assert.h>
73
74 #include "fsck.h"
75
76 struct cgchain {
77         union {
78                 struct cg cgcu_cg;
79                 char cgcu_buf[MAXBSIZE];
80         } cgc_union;
81         int     cgc_busy;
82         int     cgc_dirty;
83         LIST_ENTRY(cgchain) cgc_next;
84 };
85 #define cgc_cg  cgc_union.cgcu_cg
86
87 #define MAX_CACHED_CGS  1024
88 static unsigned ncgs = 0;
89 static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist);
90
91 static const char *devnam;
92 static struct uufsd *disk = NULL;
93 static struct fs *fs = NULL;
94 struct ufs2_dinode ufs2_zino;
95
96 static void putcgs(void);
97
98 /*
99  * Write current block of inodes.
100  */
101 static int
102 putino(struct uufsd *disk, ino_t inode)
103 {
104         caddr_t inoblock;
105         struct fs *fs;
106         ssize_t ret;
107
108         fs = &disk->d_fs;
109         inoblock = disk->d_inoblock;
110
111         assert(inoblock != NULL);
112         assert(inode >= disk->d_inomin && inode <= disk->d_inomax);
113         ret = bwrite(disk, fsbtodb(fs, ino_to_fsba(fs, inode)), inoblock,
114             fs->fs_bsize);
115
116         return (ret == -1 ? -1 : 0);
117 }
118
119 /*
120  * Return cylinder group from the cache or load it if it is not in the
121  * cache yet.
122  * Don't cache more than MAX_CACHED_CGS cylinder groups.
123  */
124 static struct cgchain *
125 getcg(int cg)
126 {
127         struct cgchain *cgc;
128
129         assert(disk != NULL && fs != NULL);
130         LIST_FOREACH(cgc, &cglist, cgc_next) {
131                 if (cgc->cgc_cg.cg_cgx == cg) {
132                         //printf("%s: Found cg=%d\n", __func__, cg);
133                         return (cgc);
134                 }
135         }
136         /*
137          * Our cache is full? Let's clean it up.
138          */
139         if (ncgs >= MAX_CACHED_CGS) {
140                 //printf("%s: Flushing CGs.\n", __func__);
141                 putcgs();
142         }
143         cgc = malloc(sizeof(*cgc));
144         if (cgc == NULL) {
145                 /*
146                  * Cannot allocate memory?
147                  * Let's put all currently loaded and not busy cylinder groups
148                  * on disk and try again.
149                  */
150                 //printf("%s: No memory, flushing CGs.\n", __func__);
151                 putcgs();
152                 cgc = malloc(sizeof(*cgc));
153                 if (cgc == NULL)
154                         err(1, "malloc(%zu)", sizeof(*cgc));
155         }
156         if (cgread1(disk, cg) == -1)
157                 err(1, "cgread1(%d)", cg);
158         bcopy(&disk->d_cg, &cgc->cgc_cg, sizeof(cgc->cgc_union));
159         cgc->cgc_busy = 0;
160         cgc->cgc_dirty = 0;
161         LIST_INSERT_HEAD(&cglist, cgc, cgc_next);
162         ncgs++;
163         //printf("%s: Read cg=%d\n", __func__, cg);
164         return (cgc);
165 }
166
167 /*
168  * Mark cylinder group as dirty - it will be written back on putcgs().
169  */
170 static void
171 dirtycg(struct cgchain *cgc)
172 {
173
174         cgc->cgc_dirty = 1;
175 }
176
177 /*
178  * Mark cylinder group as busy - it will not be freed on putcgs().
179  */
180 static void
181 busycg(struct cgchain *cgc)
182 {
183
184         cgc->cgc_busy = 1;
185 }
186
187 /*
188  * Unmark the given cylinder group as busy.
189  */
190 static void
191 unbusycg(struct cgchain *cgc)
192 {
193
194         cgc->cgc_busy = 0;
195 }
196
197 /*
198  * Write back all dirty cylinder groups.
199  * Free all non-busy cylinder groups.
200  */
201 static void
202 putcgs(void)
203 {
204         struct cgchain *cgc, *cgc2;
205
206         assert(disk != NULL && fs != NULL);
207         LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) {
208                 if (cgc->cgc_busy)
209                         continue;
210                 LIST_REMOVE(cgc, cgc_next);
211                 ncgs--;
212                 if (cgc->cgc_dirty) {
213                         bcopy(&cgc->cgc_cg, &disk->d_cg,
214                             sizeof(cgc->cgc_union));
215                         if (cgwrite1(disk, cgc->cgc_cg.cg_cgx) == -1)
216                                 err(1, "cgwrite1(%d)", cgc->cgc_cg.cg_cgx);
217                         //printf("%s: Wrote cg=%d\n", __func__,
218                         //    cgc->cgc_cg.cg_cgx);
219                 }
220                 free(cgc);
221         }
222 }
223
224 #if 0
225 /*
226  * Free all non-busy cylinder groups without storing the dirty ones.
227  */
228 static void
229 cancelcgs(void)
230 {
231         struct cgchain *cgc;
232
233         assert(disk != NULL && fs != NULL);
234         while ((cgc = LIST_FIRST(&cglist)) != NULL) {
235                 if (cgc->cgc_busy)
236                         continue;
237                 LIST_REMOVE(cgc, cgc_next);
238                 //printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx);
239                 free(cgc);
240         }
241 }
242 #endif
243
244 /*
245  * Open the given provider, load statistics.
246  */
247 static void
248 getdisk(void)
249 {
250         int i;
251
252         if (disk != NULL)
253                 return;
254         disk = malloc(sizeof(*disk));
255         if (disk == NULL)
256                 err(1, "malloc(%zu)", sizeof(*disk));
257         if (ufs_disk_fillout(disk, devnam) == -1) {
258                 err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
259                     disk->d_error);
260         }
261         fs = &disk->d_fs;
262         fs->fs_csp = malloc((size_t)fs->fs_cssize);
263         if (fs->fs_csp == NULL)
264                 err(1, "malloc(%zu)", (size_t)fs->fs_cssize);
265         bzero(fs->fs_csp, (size_t)fs->fs_cssize);
266         for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize) {
267                 if (bread(disk, fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
268                     (void *)(((char *)fs->fs_csp) + i),
269                     (size_t)(fs->fs_cssize - i < fs->fs_bsize ? fs->fs_cssize - i : fs->fs_bsize)) == -1) {
270                         err(1, "bread: %s", disk->d_error);
271                 }
272         }
273         if (fs->fs_contigsumsize > 0) {
274                 fs->fs_maxcluster = malloc(fs->fs_ncg * sizeof(int32_t));
275                 if (fs->fs_maxcluster == NULL)
276                         err(1, "malloc(%zu)", fs->fs_ncg * sizeof(int32_t));
277                 for (i = 0; i < fs->fs_ncg; i++)
278                         fs->fs_maxcluster[i] = fs->fs_contigsumsize;
279         }
280 }
281
282 /*
283  * Mark file system as clean, write the super-block back, close the disk.
284  */
285 static void
286 closedisk(void)
287 {
288
289         free(fs->fs_csp);
290         if (fs->fs_contigsumsize > 0) {
291                 free(fs->fs_maxcluster);
292                 fs->fs_maxcluster = NULL;
293         }
294         fs->fs_clean = 1;
295         if (sbwrite(disk, 0) == -1)
296                 err(1, "sbwrite(%s)", devnam);
297         if (ufs_disk_close(disk) == -1)
298                 err(1, "ufs_disk_close(%s)", devnam);
299         free(disk);
300         disk = NULL;
301         fs = NULL;
302 }
303
304 /*
305  * Write the statistics back, call closedisk().
306  */
307 static void
308 putdisk(void)
309 {
310         int i;
311
312         assert(disk != NULL && fs != NULL);
313         for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize) {
314                 if (bwrite(disk, fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
315                     (void *)(((char *)fs->fs_csp) + i),
316                     (size_t)(fs->fs_cssize - i < fs->fs_bsize ? fs->fs_cssize - i : fs->fs_bsize)) == -1) {
317                         err(1, "bwrite: %s", disk->d_error);
318                 }
319         }
320         closedisk();
321 }
322
323 #if 0
324 /*
325  * Free memory, close the disk, but don't write anything back.
326  */
327 static void
328 canceldisk(void)
329 {
330         int i;
331
332         assert(disk != NULL && fs != NULL);
333         free(fs->fs_csp);
334         if (fs->fs_contigsumsize > 0)
335                 free(fs->fs_maxcluster);
336         if (ufs_disk_close(disk) == -1)
337                 err(1, "ufs_disk_close(%s)", devnam);
338         free(disk);
339         disk = NULL;
340         fs = NULL;
341 }
342 #endif
343
344 static int
345 isblock(unsigned char *cp, ufs1_daddr_t h)
346 {
347         unsigned char mask;
348
349         switch ((int)fs->fs_frag) {
350         case 8:
351                 return (cp[h] == 0xff);
352         case 4:
353                 mask = 0x0f << ((h & 0x1) << 2);
354                 return ((cp[h >> 1] & mask) == mask);
355         case 2:
356                 mask = 0x03 << ((h & 0x3) << 1);
357                 return ((cp[h >> 2] & mask) == mask);
358         case 1:
359                 mask = 0x01 << (h & 0x7);
360                 return ((cp[h >> 3] & mask) == mask);
361         default:
362                 assert(!"isblock: invalid number of fragments");
363         }
364         return (0);
365 }
366
367 /*
368  * put a block into the map
369  */
370 static void
371 setblock(unsigned char *cp, ufs1_daddr_t h)
372 {
373
374         switch ((int)fs->fs_frag) {
375         case 8:
376                 cp[h] = 0xff;
377                 return;
378         case 4:
379                 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
380                 return;
381         case 2:
382                 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
383                 return;
384         case 1:
385                 cp[h >> 3] |= (0x01 << (h & 0x7));
386                 return;
387         default:
388                 assert(!"setblock: invalid number of fragments");
389         }
390 }
391
392 /*
393  * check if a block is free
394  */
395 static int
396 isfreeblock(u_char *cp, ufs1_daddr_t h)
397 {
398
399         switch ((int)fs->fs_frag) {
400         case 8:
401                 return (cp[h] == 0);
402         case 4:
403                 return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
404         case 2:
405                 return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
406         case 1:
407                 return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
408         default:
409                 assert(!"isfreeblock: invalid number of fragments");
410         }
411         return (0);
412 }
413
414 /*
415  * Update the frsum fields to reflect addition or deletion
416  * of some frags.
417  */
418 void
419 fragacct(int fragmap, int32_t fraglist[], int cnt)
420 {
421         int inblk;
422         int field, subfield;
423         int siz, pos;
424
425         inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
426         fragmap <<= 1;
427         for (siz = 1; siz < fs->fs_frag; siz++) {
428                 if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
429                         continue;
430                 field = around[siz];
431                 subfield = inside[siz];
432                 for (pos = siz; pos <= fs->fs_frag; pos++) {
433                         if ((fragmap & field) == subfield) {
434                                 fraglist[siz] += cnt;
435                                 pos += siz;
436                                 field <<= siz;
437                                 subfield <<= siz;
438                         }
439                         field <<= 1;
440                         subfield <<= 1;
441                 }
442         }
443 }
444
445 static void
446 clusteracct(struct cg *cgp, ufs1_daddr_t blkno)
447 {
448         int32_t *sump;
449         int32_t *lp;
450         u_char *freemapp, *mapp;
451         int i, start, end, forw, back, map, bit;
452
453         if (fs->fs_contigsumsize <= 0)
454                 return;
455         freemapp = cg_clustersfree(cgp);
456         sump = cg_clustersum(cgp);
457         /*
458          * Clear the actual block.
459          */
460         setbit(freemapp, blkno);
461         /*
462          * Find the size of the cluster going forward.
463          */
464         start = blkno + 1;
465         end = start + fs->fs_contigsumsize;
466         if (end >= cgp->cg_nclusterblks)
467                 end = cgp->cg_nclusterblks;
468         mapp = &freemapp[start / NBBY];
469         map = *mapp++;
470         bit = 1 << (start % NBBY);
471         for (i = start; i < end; i++) {
472                 if ((map & bit) == 0)
473                         break;
474                 if ((i & (NBBY - 1)) != (NBBY - 1)) {
475                         bit <<= 1;
476                 } else {
477                         map = *mapp++;
478                         bit = 1;
479                 }
480         }
481         forw = i - start;
482         /*
483          * Find the size of the cluster going backward.
484          */
485         start = blkno - 1;
486         end = start - fs->fs_contigsumsize;
487         if (end < 0)
488                 end = -1;
489         mapp = &freemapp[start / NBBY];
490         map = *mapp--;
491         bit = 1 << (start % NBBY);
492         for (i = start; i > end; i--) {
493                 if ((map & bit) == 0)
494                         break;
495                 if ((i & (NBBY - 1)) != 0) {
496                         bit >>= 1;
497                 } else {
498                         map = *mapp--;
499                         bit = 1 << (NBBY - 1);
500                 }
501         }
502         back = start - i;
503         /*
504          * Account for old cluster and the possibly new forward and
505          * back clusters.
506          */
507         i = back + forw + 1;
508         if (i > fs->fs_contigsumsize)
509                 i = fs->fs_contigsumsize;
510         sump[i]++;
511         if (back > 0)
512                 sump[back]--;
513         if (forw > 0)
514                 sump[forw]--;
515         /*
516          * Update cluster summary information.
517          */
518         lp = &sump[fs->fs_contigsumsize];
519         for (i = fs->fs_contigsumsize; i > 0; i--)
520                 if (*lp-- > 0)
521                         break;
522         fs->fs_maxcluster[cgp->cg_cgx] = i;
523 }
524
525 static void
526 blkfree(ufs2_daddr_t bno, long size)
527 {
528         struct cgchain *cgc;
529         struct cg *cgp;
530         ufs1_daddr_t fragno, cgbno;
531         int i, cg, blk, frags, bbase;
532         u_int8_t *blksfree;
533
534         cg = dtog(fs, bno);
535         cgc = getcg(cg);
536         dirtycg(cgc);
537         cgp = &cgc->cgc_cg;
538         cgbno = dtogd(fs, bno);
539         blksfree = cg_blksfree(cgp);
540         if (size == fs->fs_bsize) {
541                 fragno = fragstoblks(fs, cgbno);
542                 if (!isfreeblock(blksfree, fragno))
543                         assert(!"blkfree: freeing free block");
544                 setblock(blksfree, fragno);
545                 clusteracct(cgp, fragno);
546                 cgp->cg_cs.cs_nbfree++;
547                 fs->fs_cstotal.cs_nbfree++;
548                 fs->fs_cs(fs, cg).cs_nbfree++;
549         } else {
550                 bbase = cgbno - fragnum(fs, cgbno);
551                 /*
552                  * decrement the counts associated with the old frags
553                  */
554                 blk = blkmap(fs, blksfree, bbase);
555                 fragacct(blk, cgp->cg_frsum, -1);
556                 /*
557                  * deallocate the fragment
558                  */
559                 frags = numfrags(fs, size);
560                 for (i = 0; i < frags; i++) {
561                         if (isset(blksfree, cgbno + i))
562                                 assert(!"blkfree: freeing free frag");
563                         setbit(blksfree, cgbno + i);
564                 }
565                 cgp->cg_cs.cs_nffree += i;
566                 fs->fs_cstotal.cs_nffree += i;
567                 fs->fs_cs(fs, cg).cs_nffree += i;
568                 /*
569                  * add back in counts associated with the new frags
570                  */
571                 blk = blkmap(fs, blksfree, bbase);
572                 fragacct(blk, cgp->cg_frsum, 1);
573                 /*
574                  * if a complete block has been reassembled, account for it
575                  */
576                 fragno = fragstoblks(fs, bbase);
577                 if (isblock(blksfree, fragno)) {
578                         cgp->cg_cs.cs_nffree -= fs->fs_frag;
579                         fs->fs_cstotal.cs_nffree -= fs->fs_frag;
580                         fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
581                         clusteracct(cgp, fragno);
582                         cgp->cg_cs.cs_nbfree++;
583                         fs->fs_cstotal.cs_nbfree++;
584                         fs->fs_cs(fs, cg).cs_nbfree++;
585                 }
586         }
587 }
588
589 /*
590  * Recursively free all indirect blocks.
591  */
592 static void
593 freeindir(ufs2_daddr_t blk, int level)
594 {
595         char sblks[MAXBSIZE];
596         ufs2_daddr_t *blks;
597         int i;
598
599         if (bread(disk, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1)
600                 err(1, "bread: %s", disk->d_error);
601         blks = (ufs2_daddr_t *)&sblks;
602         for (i = 0; i < howmany(fs->fs_bsize, sizeof(ufs2_daddr_t)); i++) {
603                 if (blks[i] == 0)
604                         break;
605                 if (level == 0)
606                         blkfree(blks[i], fs->fs_bsize);
607                 else
608                         freeindir(blks[i], level - 1);
609         }
610         blkfree(blk, fs->fs_bsize);
611 }
612
613 #define dblksize(fs, dino, lbn) \
614         ((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \
615             ? (fs)->fs_bsize \
616             : fragroundup(fs, blkoff(fs, (dino)->di_size)))
617
618 /*
619  * Free all blocks associated with the given inode.
620  */
621 static void
622 clear_inode(struct ufs2_dinode *dino)
623 {
624         ufs2_daddr_t bn;
625         int extblocks, i, level;
626         off_t osize;
627         long bsize;
628
629         extblocks = 0;
630         if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0)
631                 extblocks = btodb(fragroundup(fs, dino->di_extsize));
632         /* deallocate external attributes blocks */
633         if (extblocks > 0) {
634                 osize = dino->di_extsize;
635                 dino->di_blocks -= extblocks;
636                 dino->di_extsize = 0;
637                 for (i = 0; i < NXADDR; i++) {
638                         if (dino->di_extb[i] == 0)
639                                 continue;
640                         blkfree(dino->di_extb[i], sblksize(fs, osize, i));
641                 }
642         }
643 #define SINGLE  0       /* index of single indirect block */
644 #define DOUBLE  1       /* index of double indirect block */
645 #define TRIPLE  2       /* index of triple indirect block */
646         /* deallocate indirect blocks */
647         for (level = SINGLE; level <= TRIPLE; level++) {
648                 if (dino->di_ib[level] == 0)
649                         break;
650                 freeindir(dino->di_ib[level], level);
651         }
652         /* deallocate direct blocks and fragments */
653         for (i = 0; i < NDADDR; i++) {
654                 bn = dino->di_db[i];
655                 if (bn == 0)
656                         continue;
657                 bsize = dblksize(fs, dino, i);
658                 blkfree(bn, bsize);
659         }
660 }
661
662 void
663 gjournal_check(const char *filesys)
664 {
665         struct ufs2_dinode *dino;
666         void *p;
667         struct cgchain *cgc;
668         struct cg *cgp;
669         uint8_t *inosused, *blksfree;
670         ino_t cino, ino;
671         int cg, mode;
672
673         devnam = filesys;
674         getdisk();
675         /* Are there any unreferenced inodes in this file system? */
676         if (fs->fs_unrefs == 0) {
677                 //printf("No unreferenced inodes.\n");
678                 closedisk();
679                 return;
680         }
681
682         for (cg = 0; cg < fs->fs_ncg; cg++) {
683                 /* Show progress if requested. */
684                 if (got_siginfo) {
685                         printf("%s: phase j: cyl group %d of %d (%d%%)\n",
686                             cdevname, cg, fs->fs_ncg, cg * 100 / fs->fs_ncg);
687                         got_siginfo = 0;
688                 }
689                 if (got_sigalarm) {
690                         setproctitle("%s pj %d%%", cdevname,
691                              cg * 100 / fs->fs_ncg);
692                         got_sigalarm = 0;
693                 }
694                 cgc = getcg(cg);
695                 cgp = &cgc->cgc_cg;
696                 /* Are there any unreferenced inodes in this cylinder group? */
697                 if (cgp->cg_unrefs == 0)
698                         continue;
699                 //printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs);
700                 /*
701                  * We are going to modify this cylinder group, so we want it to
702                  * be written back.
703                  */
704                 dirtycg(cgc);
705                 /* We don't want it to be freed in the meantime. */
706                 busycg(cgc);
707                 inosused = cg_inosused(cgp);
708                 blksfree = cg_blksfree(cgp);
709                 /*
710                  * Now go through the list of all inodes in this cylinder group
711                  * to find unreferenced ones.
712                  */
713                 for (cino = 0; cino < fs->fs_ipg; cino++) {
714                         ino = fs->fs_ipg * cg + cino;
715                         /* Unallocated? Skip it. */
716                         if (isclr(inosused, cino))
717                                 continue;
718                         if (getino(disk, &p, ino, &mode) == -1)
719                                 err(1, "getino(cg=%d ino=%d)", cg, ino);
720                         dino = p;
721                         /* Not a regular file nor directory? Skip it. */
722                         if (!S_ISREG(dino->di_mode) && !S_ISDIR(dino->di_mode))
723                                 continue;
724                         /* Has reference(s)? Skip it. */
725                         if (dino->di_nlink > 0)
726                                 continue;
727                         //printf("Clearing inode=%d (size=%jd)\n", ino, (intmax_t)dino->di_size);
728                         /* Free inode's blocks. */
729                         clear_inode(dino);
730                         /* Deallocate it. */
731                         clrbit(inosused, cino);
732                         /* Update position of last used inode. */
733                         if (ino < cgp->cg_irotor)
734                                 cgp->cg_irotor = ino;
735                         /* Update statistics. */
736                         cgp->cg_cs.cs_nifree++;
737                         fs->fs_cs(fs, cg).cs_nifree++;
738                         fs->fs_cstotal.cs_nifree++;
739                         cgp->cg_unrefs--;
740                         fs->fs_unrefs--;
741                         /* If this is directory, update related statistics. */
742                         if (S_ISDIR(dino->di_mode)) {
743                                 cgp->cg_cs.cs_ndir--;
744                                 fs->fs_cs(fs, cg).cs_ndir--;
745                                 fs->fs_cstotal.cs_ndir--;
746                         }
747                         /* Zero-fill the inode. */
748                         *dino = ufs2_zino;
749                         /* Write the inode back. */
750                         if (putino(disk, ino) == -1)
751                                 err(1, "putino(cg=%d ino=%d)", cg, ino);
752                         if (cgp->cg_unrefs == 0) {
753                                 //printf("No more unreferenced inodes in cg=%d.\n", cg);
754                                 break;
755                         }
756                 }
757                 /*
758                  * We don't need this cylinder group anymore, so feel free to
759                  * free it if needed.
760                  */
761                 unbusycg(cgc);
762                 /*
763                  * If there are no more unreferenced inodes, there is no need to
764                  * check other cylinder groups.
765                  */
766                 if (fs->fs_unrefs == 0) {
767                         //printf("No more unreferenced inodes (cg=%d/%d).\n", cg,
768                         //    fs->fs_ncg);
769                         break;
770                 }
771         }
772         /* Write back modified cylinder groups. */
773         putcgs();
774         /* Write back updated statistics and super-block. */
775         putdisk();
776 }