|
23 | 23 | #include <linux/bsearch.h> |
24 | 24 | #include <linux/dcache.h> /* struct qstr */ |
25 | 25 |
|
26 | | -static bool inode_points_to_dirent(struct bch_inode_unpacked *inode, |
27 | | - struct bkey_s_c_dirent d) |
28 | | -{ |
29 | | - return inode->bi_dir == d.k->p.inode && |
30 | | - inode->bi_dir_offset == d.k->p.offset; |
31 | | -} |
32 | | - |
33 | 26 | static int dirent_points_to_inode_nowarn(struct bkey_s_c_dirent d, |
34 | 27 | struct bch_inode_unpacked *inode) |
35 | 28 | { |
@@ -116,29 +109,6 @@ static int subvol_lookup(struct btree_trans *trans, u32 subvol, |
116 | 109 | return ret; |
117 | 110 | } |
118 | 111 |
|
119 | | -static int lookup_first_inode(struct btree_trans *trans, u64 inode_nr, |
120 | | - struct bch_inode_unpacked *inode) |
121 | | -{ |
122 | | - struct btree_iter iter; |
123 | | - struct bkey_s_c k; |
124 | | - int ret; |
125 | | - |
126 | | - for_each_btree_key_norestart(trans, iter, BTREE_ID_inodes, POS(0, inode_nr), |
127 | | - BTREE_ITER_all_snapshots, k, ret) { |
128 | | - if (k.k->p.offset != inode_nr) |
129 | | - break; |
130 | | - if (!bkey_is_inode(k.k)) |
131 | | - continue; |
132 | | - ret = bch2_inode_unpack(k, inode); |
133 | | - goto found; |
134 | | - } |
135 | | - ret = -BCH_ERR_ENOENT_inode; |
136 | | -found: |
137 | | - bch_err_msg(trans->c, ret, "fetching inode %llu", inode_nr); |
138 | | - bch2_trans_iter_exit(trans, &iter); |
139 | | - return ret; |
140 | | -} |
141 | | - |
142 | 112 | static int lookup_inode(struct btree_trans *trans, u64 inode_nr, u32 snapshot, |
143 | 113 | struct bch_inode_unpacked *inode) |
144 | 114 | { |
@@ -179,32 +149,6 @@ static int lookup_dirent_in_snapshot(struct btree_trans *trans, |
179 | 149 | return 0; |
180 | 150 | } |
181 | 151 |
|
182 | | -static int __remove_dirent(struct btree_trans *trans, struct bpos pos) |
183 | | -{ |
184 | | - struct bch_fs *c = trans->c; |
185 | | - struct btree_iter iter; |
186 | | - struct bch_inode_unpacked dir_inode; |
187 | | - struct bch_hash_info dir_hash_info; |
188 | | - int ret; |
189 | | - |
190 | | - ret = lookup_first_inode(trans, pos.inode, &dir_inode); |
191 | | - if (ret) |
192 | | - goto err; |
193 | | - |
194 | | - dir_hash_info = bch2_hash_info_init(c, &dir_inode); |
195 | | - |
196 | | - bch2_trans_iter_init(trans, &iter, BTREE_ID_dirents, pos, BTREE_ITER_intent); |
197 | | - |
198 | | - ret = bch2_btree_iter_traverse(&iter) ?: |
199 | | - bch2_hash_delete_at(trans, bch2_dirent_hash_desc, |
200 | | - &dir_hash_info, &iter, |
201 | | - BTREE_UPDATE_internal_snapshot_node); |
202 | | - bch2_trans_iter_exit(trans, &iter); |
203 | | -err: |
204 | | - bch_err_fn(c, ret); |
205 | | - return ret; |
206 | | -} |
207 | | - |
208 | 152 | /* |
209 | 153 | * Find any subvolume associated with a tree of snapshots |
210 | 154 | * We can't rely on master_subvol - it might have been deleted. |
@@ -548,7 +492,7 @@ static int remove_backpointer(struct btree_trans *trans, |
548 | 492 | SPOS(inode->bi_dir, inode->bi_dir_offset, inode->bi_snapshot)); |
549 | 493 | int ret = bkey_err(d) ?: |
550 | 494 | dirent_points_to_inode(c, d, inode) ?: |
551 | | - __remove_dirent(trans, d.k->p); |
| 495 | + bch2_fsck_remove_dirent(trans, d.k->p); |
552 | 496 | bch2_trans_iter_exit(trans, &iter); |
553 | 497 | return ret; |
554 | 498 | } |
@@ -1985,169 +1929,6 @@ static int check_subdir_dirents_count(struct btree_trans *trans, struct inode_wa |
1985 | 1929 | trans_was_restarted(trans, restart_count); |
1986 | 1930 | } |
1987 | 1931 |
|
1988 | | -noinline_for_stack |
1989 | | -static int check_dirent_inode_dirent(struct btree_trans *trans, |
1990 | | - struct btree_iter *iter, |
1991 | | - struct bkey_s_c_dirent d, |
1992 | | - struct bch_inode_unpacked *target) |
1993 | | -{ |
1994 | | - struct bch_fs *c = trans->c; |
1995 | | - struct printbuf buf = PRINTBUF; |
1996 | | - struct btree_iter bp_iter = { NULL }; |
1997 | | - int ret = 0; |
1998 | | - |
1999 | | - if (inode_points_to_dirent(target, d)) |
2000 | | - return 0; |
2001 | | - |
2002 | | - if (!target->bi_dir && |
2003 | | - !target->bi_dir_offset) { |
2004 | | - fsck_err_on(S_ISDIR(target->bi_mode), |
2005 | | - trans, inode_dir_missing_backpointer, |
2006 | | - "directory with missing backpointer\n%s", |
2007 | | - (printbuf_reset(&buf), |
2008 | | - bch2_bkey_val_to_text(&buf, c, d.s_c), |
2009 | | - prt_printf(&buf, "\n"), |
2010 | | - bch2_inode_unpacked_to_text(&buf, target), |
2011 | | - buf.buf)); |
2012 | | - |
2013 | | - fsck_err_on(target->bi_flags & BCH_INODE_unlinked, |
2014 | | - trans, inode_unlinked_but_has_dirent, |
2015 | | - "inode unlinked but has dirent\n%s", |
2016 | | - (printbuf_reset(&buf), |
2017 | | - bch2_bkey_val_to_text(&buf, c, d.s_c), |
2018 | | - prt_printf(&buf, "\n"), |
2019 | | - bch2_inode_unpacked_to_text(&buf, target), |
2020 | | - buf.buf)); |
2021 | | - |
2022 | | - target->bi_flags &= ~BCH_INODE_unlinked; |
2023 | | - target->bi_dir = d.k->p.inode; |
2024 | | - target->bi_dir_offset = d.k->p.offset; |
2025 | | - return __bch2_fsck_write_inode(trans, target); |
2026 | | - } |
2027 | | - |
2028 | | - if (bch2_inode_should_have_single_bp(target) && |
2029 | | - !fsck_err(trans, inode_wrong_backpointer, |
2030 | | - "dirent points to inode that does not point back:\n %s", |
2031 | | - (bch2_bkey_val_to_text(&buf, c, d.s_c), |
2032 | | - prt_printf(&buf, "\n "), |
2033 | | - bch2_inode_unpacked_to_text(&buf, target), |
2034 | | - buf.buf))) |
2035 | | - goto err; |
2036 | | - |
2037 | | - struct bkey_s_c_dirent bp_dirent = dirent_get_by_pos(trans, &bp_iter, |
2038 | | - SPOS(target->bi_dir, target->bi_dir_offset, target->bi_snapshot)); |
2039 | | - ret = bkey_err(bp_dirent); |
2040 | | - if (ret && !bch2_err_matches(ret, ENOENT)) |
2041 | | - goto err; |
2042 | | - |
2043 | | - bool backpointer_exists = !ret; |
2044 | | - ret = 0; |
2045 | | - |
2046 | | - if (fsck_err_on(!backpointer_exists, |
2047 | | - trans, inode_wrong_backpointer, |
2048 | | - "inode %llu:%u has wrong backpointer:\n" |
2049 | | - "got %llu:%llu\n" |
2050 | | - "should be %llu:%llu", |
2051 | | - target->bi_inum, target->bi_snapshot, |
2052 | | - target->bi_dir, |
2053 | | - target->bi_dir_offset, |
2054 | | - d.k->p.inode, |
2055 | | - d.k->p.offset)) { |
2056 | | - target->bi_dir = d.k->p.inode; |
2057 | | - target->bi_dir_offset = d.k->p.offset; |
2058 | | - ret = __bch2_fsck_write_inode(trans, target); |
2059 | | - goto out; |
2060 | | - } |
2061 | | - |
2062 | | - bch2_bkey_val_to_text(&buf, c, d.s_c); |
2063 | | - prt_newline(&buf); |
2064 | | - if (backpointer_exists) |
2065 | | - bch2_bkey_val_to_text(&buf, c, bp_dirent.s_c); |
2066 | | - |
2067 | | - if (fsck_err_on(backpointer_exists && |
2068 | | - (S_ISDIR(target->bi_mode) || |
2069 | | - target->bi_subvol), |
2070 | | - trans, inode_dir_multiple_links, |
2071 | | - "%s %llu:%u with multiple links\n%s", |
2072 | | - S_ISDIR(target->bi_mode) ? "directory" : "subvolume", |
2073 | | - target->bi_inum, target->bi_snapshot, buf.buf)) { |
2074 | | - ret = __remove_dirent(trans, d.k->p); |
2075 | | - goto out; |
2076 | | - } |
2077 | | - |
2078 | | - /* |
2079 | | - * hardlinked file with nlink 0: |
2080 | | - * We're just adjusting nlink here so check_nlinks() will pick |
2081 | | - * it up, it ignores inodes with nlink 0 |
2082 | | - */ |
2083 | | - if (fsck_err_on(backpointer_exists && !target->bi_nlink, |
2084 | | - trans, inode_multiple_links_but_nlink_0, |
2085 | | - "inode %llu:%u type %s has multiple links but i_nlink 0\n%s", |
2086 | | - target->bi_inum, target->bi_snapshot, bch2_d_types[d.v->d_type], buf.buf)) { |
2087 | | - target->bi_nlink++; |
2088 | | - target->bi_flags &= ~BCH_INODE_unlinked; |
2089 | | - ret = __bch2_fsck_write_inode(trans, target); |
2090 | | - if (ret) |
2091 | | - goto err; |
2092 | | - } |
2093 | | -out: |
2094 | | -err: |
2095 | | -fsck_err: |
2096 | | - bch2_trans_iter_exit(trans, &bp_iter); |
2097 | | - printbuf_exit(&buf); |
2098 | | - bch_err_fn(c, ret); |
2099 | | - return ret; |
2100 | | -} |
2101 | | - |
2102 | | -noinline_for_stack |
2103 | | -static int check_dirent_target(struct btree_trans *trans, |
2104 | | - struct btree_iter *iter, |
2105 | | - struct bkey_s_c_dirent d, |
2106 | | - struct bch_inode_unpacked *target) |
2107 | | -{ |
2108 | | - struct bch_fs *c = trans->c; |
2109 | | - struct bkey_i_dirent *n; |
2110 | | - struct printbuf buf = PRINTBUF; |
2111 | | - int ret = 0; |
2112 | | - |
2113 | | - ret = check_dirent_inode_dirent(trans, iter, d, target); |
2114 | | - if (ret) |
2115 | | - goto err; |
2116 | | - |
2117 | | - if (fsck_err_on(d.v->d_type != inode_d_type(target), |
2118 | | - trans, dirent_d_type_wrong, |
2119 | | - "incorrect d_type: got %s, should be %s:\n%s", |
2120 | | - bch2_d_type_str(d.v->d_type), |
2121 | | - bch2_d_type_str(inode_d_type(target)), |
2122 | | - (printbuf_reset(&buf), |
2123 | | - bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf))) { |
2124 | | - n = bch2_trans_kmalloc(trans, bkey_bytes(d.k)); |
2125 | | - ret = PTR_ERR_OR_ZERO(n); |
2126 | | - if (ret) |
2127 | | - goto err; |
2128 | | - |
2129 | | - bkey_reassemble(&n->k_i, d.s_c); |
2130 | | - n->v.d_type = inode_d_type(target); |
2131 | | - if (n->v.d_type == DT_SUBVOL) { |
2132 | | - n->v.d_parent_subvol = cpu_to_le32(target->bi_parent_subvol); |
2133 | | - n->v.d_child_subvol = cpu_to_le32(target->bi_subvol); |
2134 | | - } else { |
2135 | | - n->v.d_inum = cpu_to_le64(target->bi_inum); |
2136 | | - } |
2137 | | - |
2138 | | - ret = bch2_trans_update(trans, iter, &n->k_i, 0); |
2139 | | - if (ret) |
2140 | | - goto err; |
2141 | | - |
2142 | | - d = dirent_i_to_s_c(n); |
2143 | | - } |
2144 | | -err: |
2145 | | -fsck_err: |
2146 | | - printbuf_exit(&buf); |
2147 | | - bch_err_fn(c, ret); |
2148 | | - return ret; |
2149 | | -} |
2150 | | - |
2151 | 1932 | /* find a subvolume that's a descendent of @snapshot: */ |
2152 | 1933 | static int find_snapshot_subvol(struct btree_trans *trans, u32 snapshot, u32 *subvolid) |
2153 | 1934 | { |
@@ -2247,7 +2028,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter * |
2247 | 2028 | if (fsck_err(trans, dirent_to_missing_subvol, |
2248 | 2029 | "dirent points to missing subvolume\n%s", |
2249 | 2030 | (bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf))) |
2250 | | - return __remove_dirent(trans, d.k->p); |
| 2031 | + return bch2_fsck_remove_dirent(trans, d.k->p); |
2251 | 2032 | ret = 0; |
2252 | 2033 | goto out; |
2253 | 2034 | } |
@@ -2291,7 +2072,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter * |
2291 | 2072 | goto err; |
2292 | 2073 | } |
2293 | 2074 |
|
2294 | | - ret = check_dirent_target(trans, iter, d, &subvol_root); |
| 2075 | + ret = bch2_check_dirent_target(trans, iter, d, &subvol_root); |
2295 | 2076 | if (ret) |
2296 | 2077 | goto err; |
2297 | 2078 | out: |
@@ -2378,13 +2159,13 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, |
2378 | 2159 | (printbuf_reset(&buf), |
2379 | 2160 | bch2_bkey_val_to_text(&buf, c, k), |
2380 | 2161 | buf.buf))) { |
2381 | | - ret = __remove_dirent(trans, d.k->p); |
| 2162 | + ret = bch2_fsck_remove_dirent(trans, d.k->p); |
2382 | 2163 | if (ret) |
2383 | 2164 | goto err; |
2384 | 2165 | } |
2385 | 2166 |
|
2386 | 2167 | darray_for_each(target->inodes, i) { |
2387 | | - ret = check_dirent_target(trans, iter, d, &i->inode); |
| 2168 | + ret = bch2_check_dirent_target(trans, iter, d, &i->inode); |
2388 | 2169 | if (ret) |
2389 | 2170 | goto err; |
2390 | 2171 | } |
|
0 commit comments