Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : #include <inttypes.h>
4 : #include <stdlib.h>
5 : #include <stdint.h>
6 : #include <string.h>
7 : #include <unistd.h>
8 : #include <libintl.h>
9 : #define _(String) gettext(String)
10 :
11 : #include <logging.h>
12 : #include "libgfs2.h"
13 : #include "fsck.h"
14 : #include "inode_hash.h"
15 : #include "link.h"
16 : #include "util.h"
17 :
18 : struct bmap nlink1map = { 0 }; /* map of dinodes with nlink == 1 */
19 : struct bmap clink1map = { 0 }; /* map of dinodes w/counted links == 1 */
20 :
21 970 : int link1_set(struct bmap *bmap, uint64_t bblock, int mark)
22 : {
23 : static unsigned char *byte;
24 : static uint64_t b;
25 :
26 970 : if (!bmap)
27 0 : return 0;
28 970 : if (bblock > bmap->size)
29 1 : return -1;
30 :
31 969 : byte = bmap->map + BLOCKMAP_SIZE1(bblock);
32 969 : b = BLOCKMAP_BYTE_OFFSET1(bblock);
33 969 : *byte &= ~(BLOCKMAP_MASK1 << b);
34 969 : *byte |= (mark & BLOCKMAP_MASK1) << b;
35 969 : return 0;
36 : }
37 :
38 712 : int set_di_nlink(struct fsck_cx *cx, struct lgfs2_inode *ip)
39 : {
40 : struct inode_info *ii;
41 : struct dir_info *di;
42 :
43 712 : if (is_dir(ip)) {
44 228 : di = dirtree_find(cx, ip->i_num.in_addr);
45 228 : if (di == NULL) {
46 0 : log_err(_("Error: directory %"PRIu64" (0x%"PRIx64") is not "
47 : "in the dir_tree (set).\n"),
48 : ip->i_num.in_addr, ip->i_num.in_addr);
49 0 : return -1;
50 : }
51 228 : di->di_nlink = ip->i_nlink;
52 228 : return 0;
53 : }
54 484 : if (ip->i_nlink == 1) {
55 484 : link1_set(&nlink1map, ip->i_num.in_addr, 1);
56 484 : return 0;
57 : }
58 : /*log_debug( _("Setting link count to %u for %" PRIu64
59 : " (0x%" PRIx64 ")\n"), count, inode_no, inode_no);*/
60 : /* If the list has entries, look for one that matches inode_no */
61 0 : ii = inodetree_find(cx, ip->i_num.in_addr);
62 0 : if (!ii) {
63 0 : struct lgfs2_inum no = ip->i_num;
64 0 : ii = inodetree_insert(cx, no);
65 : }
66 0 : if (ii)
67 0 : ii->di_nlink = ip->i_nlink;
68 : else
69 0 : return -1;
70 0 : return 0;
71 : }
72 :
73 : /* I'm making whyincr a macro rather than function so that the debug output
74 : * matches older versions. */
75 : #define whyincr(no_addr, why, referenced_from, counted_links) \
76 : log_debug(_("Dir (0x%"PRIx64") incremented counted links to %u " \
77 : "for (0x%"PRIx64") via %s\n"), \
78 : referenced_from, counted_links, no_addr, why);
79 :
80 1054 : int incr_link_count(struct fsck_cx *cx, struct lgfs2_inum no, struct lgfs2_inode *ip, const char *why)
81 : {
82 1054 : struct inode_info *ii = NULL;
83 1054 : uint64_t referenced_from = ip ? ip->i_num.in_addr : 0;
84 : struct dir_info *di;
85 : struct lgfs2_inode *link_ip;
86 :
87 1054 : di = dirtree_find(cx, no.in_addr);
88 1054 : if (di) {
89 570 : if (di->dinode.in_formal_ino != no.in_formal_ino)
90 0 : return INCR_LINK_INO_MISMATCH;
91 :
92 570 : di->counted_links++;
93 570 : whyincr(no.in_addr, why, referenced_from, di->counted_links);
94 570 : return INCR_LINK_GOOD;
95 : }
96 484 : ii = inodetree_find(cx, no.in_addr);
97 : /* If the list has entries, look for one that matches inode_no */
98 484 : if (ii) {
99 0 : if (ii->num.in_formal_ino != no.in_formal_ino)
100 0 : return INCR_LINK_INO_MISMATCH;
101 :
102 0 : ii->counted_links++;
103 0 : whyincr(no.in_addr, why, referenced_from, ii->counted_links);
104 0 : return INCR_LINK_GOOD;
105 : }
106 484 : if (link1_type(&clink1map, no.in_addr) != 1) {
107 484 : link1_set(&clink1map, no.in_addr, 1);
108 484 : whyincr(no.in_addr, why, referenced_from, 1);
109 484 : return INCR_LINK_GOOD;
110 : }
111 :
112 0 : link_ip = fsck_load_inode(ip->i_sbd, no.in_addr);
113 : /* Check formal ino against dinode before adding to inode tree. */
114 0 : if (no.in_formal_ino != link_ip->i_num.in_formal_ino) {
115 0 : fsck_inode_put(&link_ip);
116 0 : return INCR_LINK_INO_MISMATCH; /* inode mismatch */
117 : }
118 : /* Move it from the link1 maps to a real inode tree entry */
119 0 : link1_set(&nlink1map, no.in_addr, 0);
120 0 : link1_set(&clink1map, no.in_addr, 0);
121 :
122 : /* If no match was found, it must be a hard link. In theory, it can't
123 : be a duplicate because those were resolved in pass1b. Add a new
124 : inodetree entry and set its counted links to 2 */
125 0 : ii = inodetree_insert(cx, no);
126 0 : if (!ii) {
127 0 : log_debug(_("Ref: 0x%"PRIx64" Error incrementing link for 0x%"PRIx64"\n"),
128 : referenced_from, no.in_addr);
129 0 : fsck_inode_put(&link_ip);
130 0 : return INCR_LINK_BAD;
131 : }
132 0 : ii->num.in_addr = link_ip->i_num.in_addr;
133 0 : ii->num.in_formal_ino = link_ip->i_num.in_formal_ino;
134 0 : fsck_inode_put(&link_ip);
135 0 : ii->di_nlink = 1; /* Must be 1 or it wouldn't have gotten into the
136 : nlink1map */
137 0 : ii->counted_links = 2;
138 0 : whyincr(no.in_addr, why, referenced_from, ii->counted_links);
139 : /* We transitioned a dentry link count from 1 to 2, and we know it's
140 : not a directory. But the new reference has the correct formal
141 : inode number, so the first reference is suspect: we need to
142 : check it in case it's a bad reference, and not just a hard link. */
143 0 : return INCR_LINK_CHECK_ORIG;
144 : }
145 :
146 : #define whydecr(no_addr, why, referenced_from, counted_links) \
147 : log_debug(_("Dir (0x%"PRIx64") decremented counted links to %u " \
148 : "for (0x%"PRIx64") via %s\n"), \
149 : referenced_from, counted_links, no_addr, why);
150 :
151 0 : int decr_link_count(struct fsck_cx *cx, uint64_t inode_no, uint64_t referenced_from, const char *why)
152 : {
153 0 : struct inode_info *ii = NULL;
154 : struct dir_info *di;
155 :
156 0 : di = dirtree_find(cx, inode_no);
157 0 : if (di) {
158 0 : if (!di->counted_links) {
159 0 : log_debug(_("Dir 0x%"PRIx64"'s link to 0x%"PRIx64" via %s is zero!\n"),
160 : referenced_from, inode_no, why);
161 0 : return 0;
162 : }
163 0 : di->counted_links--;
164 0 : whydecr(inode_no, why, referenced_from, di->counted_links);
165 0 : return 0;
166 : }
167 :
168 0 : ii = inodetree_find(cx, inode_no);
169 : /* If the list has entries, look for one that matches
170 : * inode_no */
171 0 : if (ii) {
172 0 : if (!ii->counted_links) {
173 0 : log_debug(_("Dir 0x%"PRIx64"'s link to 0x%"PRIx64" via %s is zero!\n"),
174 : referenced_from, inode_no, why);
175 0 : return 0;
176 : }
177 0 : ii->counted_links--;
178 0 : whydecr(inode_no, why, referenced_from, ii->counted_links);
179 0 : return 0;
180 : }
181 0 : if (link1_type(&clink1map, inode_no) == 1) { /* 1 -> 0 */
182 0 : link1_set(&clink1map, inode_no, 0);
183 0 : whydecr(inode_no, why, referenced_from, 0);
184 0 : return 0;
185 : }
186 :
187 0 : log_debug(_("No match found when decrementing link for (0x%"PRIx64")!\n"), inode_no);
188 0 : return -1;
189 :
190 : }
191 :
192 :
|