|
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