1 /*        $NetBSD: inode.c,v 1.2 2022/04/08 10:17:53 andvar Exp $     */
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: inode.c,v 1.2 2022/04/08 10:17:53 andvar Exp $");
35 #endif /* not lint */
36 
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <string.h>
40 
41 #include "v7fs.h"
42 #include "v7fs_impl.h"
43 #include "v7fs_inode.h"
44 #include "v7fs_superblock.h"
45 #include "fsck_v7fs.h"
46 
47 struct ilistcheck_arg {
48           int total;
49           int alloc;
50 };
51 
52 int
freeinode_check(struct v7fs_self * fs)53 freeinode_check(struct v7fs_self *fs)
54 {
55           struct v7fs_superblock *sb = &fs->superblock;
56           v7fs_ino_t *f = sb->freeinode;
57           int16_t n = sb->nfreeinode;
58           int16_t i, j;
59           int bogus = false;
60 
61           /* Check # of cached free inode. */
62           if (n > V7FS_MAX_FREEINODE || n < 0) {
63                     pwarn("*** corrupt nfreeinode %d (0-%d)***", n,
64                         V7FS_MAX_FREEINODE);
65 
66                     if (reply("PURGE?")) {
67                               sb->nfreeinode = 0;
68                               sb->modified = 1;
69                               v7fs_superblock_writeback(fs);
70                               return FSCK_EXIT_UNRESOLVED;
71                     }
72                     return FSCK_EXIT_CHECK_FAILED;
73           }
74 
75           /* Check dup. */
76           for (i = 0; i < n; i++)
77                     for (j = 0; j < i; j++)
78                               if (f[i] == f[j]) {
79                                         pwarn("*** freeinode DUP %d %d", i, j);
80                                         bogus = true;
81                               }
82           if (bogus) {
83                     if (reply("PURGE?")) {
84                               memset(sb->freeinode, 0, sizeof(*sb->freeinode));
85                               sb->nfreeinode = 0;
86                               sb->modified = 1;
87                               v7fs_superblock_writeback(fs);
88                               return FSCK_EXIT_UNRESOLVED;
89                     } else {
90                               return FSCK_EXIT_CHECK_FAILED;
91                     }
92           }
93 
94           return FSCK_EXIT_OK;
95 }
96 
97 /* Counting freeinode and find partially allocated inode. */
98 static int
v7fs_inode_check(struct v7fs_self * fs,struct v7fs_inode * p,v7fs_ino_t ino)99 v7fs_inode_check(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t ino)
100 {
101           int error = 0;
102 
103           if (v7fs_inode_allocated(p) && !p->nlink) {
104                     pwarn("*** partially allocated inode #%d", ino);
105                     v7fs_inode_dump(p);
106                     if (reply_trivial("REMOVE?")) {
107                               memset(p, 0, sizeof(*p));
108                               v7fs_inode_deallocate(fs, ino);
109                     } else {
110                               error = FSCK_EXIT_CHECK_FAILED;
111                     }
112           }
113 
114           return error;
115 }
116 
117 static int
ilistcheck_subr(struct v7fs_self * fs,void * ctx,struct v7fs_inode * p,v7fs_ino_t ino)118 ilistcheck_subr(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p,
119     v7fs_ino_t ino)
120 {
121           struct ilistcheck_arg *arg = (struct ilistcheck_arg *)ctx;
122           int error = 0;
123 
124           if (ino != 1)
125                     error = v7fs_inode_check(fs, p, ino);
126 
127           arg->total++;
128           if (v7fs_inode_allocated(p))
129                     arg->alloc++;
130 
131           return error;
132 }
133 
134 int
ilist_check(struct v7fs_self * fs)135 ilist_check(struct v7fs_self *fs)
136 {
137           struct v7fs_superblock *sb = &fs->superblock;
138           struct ilistcheck_arg arg = { .total = 0, .alloc = 0 };
139           int error = 0;
140 
141           if ((error = v7fs_ilist_foreach(fs, ilistcheck_subr, &arg)))
142                     return error;
143           int nfree = arg.total - arg.alloc;
144 
145           if (nfree != sb->total_freeinode) {
146                     pwarn("*** corrupt total freeinode. %d(sb) != %d(cnt)\n",
147                         sb->total_freeinode, nfree);
148                     if (reply_trivial("CORRECT?")) {
149                               sb->total_freeinode = nfree;
150                               sb->modified = true;
151                               v7fs_superblock_writeback(fs);
152                               v7fs_superblock_dump(fs);
153                     } else {
154                               error = FSCK_EXIT_CHECK_FAILED;
155                     }
156           }
157 
158           pwarn("\ninode usage: %d/%d (%d)\n", arg.alloc, arg.total, nfree);
159           return error;
160 }
161