Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcachefs: bch2_check_subvolume_structure()

Now that we've got bch_subvolume.fs_path_parent, it's easy to write
subvolume

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+135 -27
+133 -27
fs/bcachefs/fsck.c
··· 342 342 return ret; 343 343 } 344 344 345 + static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume s) 346 + { 347 + struct bch_fs *c = trans->c; 348 + 349 + struct bch_inode_unpacked inode; 350 + int ret = bch2_inode_find_by_inum_trans(trans, 351 + (subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) }, 352 + &inode); 353 + if (ret) 354 + return ret; 355 + 356 + ret = remove_backpointer(trans, &inode); 357 + bch_err_msg(c, ret, "removing dirent"); 358 + if (ret) 359 + return ret; 360 + 361 + ret = reattach_inode(trans, &inode, le32_to_cpu(s.v->snapshot)); 362 + bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum); 363 + return ret; 364 + } 365 + 345 366 struct snapshots_seen_entry { 346 367 u32 id; 347 368 u32 equiv; ··· 2129 2108 return ret; 2130 2109 } 2131 2110 2111 + typedef DARRAY(u32) darray_u32; 2112 + 2113 + static bool darray_u32_has(darray_u32 *d, u32 v) 2114 + { 2115 + darray_for_each(*d, i) 2116 + if (*i == v) 2117 + return true; 2118 + return false; 2119 + } 2120 + 2121 + /* 2122 + * We've checked that inode backpointers point to valid dirents; here, it's 2123 + * sufficient to check that the subvolume root has a dirent: 2124 + */ 2125 + static int subvol_has_dirent(struct btree_trans *trans, struct bkey_s_c_subvolume s) 2126 + { 2127 + struct bch_inode_unpacked inode; 2128 + int ret = bch2_inode_find_by_inum_trans(trans, 2129 + (subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) }, 2130 + &inode); 2131 + if (ret) 2132 + return ret; 2133 + 2134 + return inode.bi_dir != 0; 2135 + } 2136 + 2137 + static int check_subvol_path(struct btree_trans *trans, struct btree_iter *iter, struct bkey_s_c k) 2138 + { 2139 + struct bch_fs *c = trans->c; 2140 + struct btree_iter parent_iter = {}; 2141 + darray_u32 subvol_path = {}; 2142 + struct printbuf buf = PRINTBUF; 2143 + int ret = 0; 2144 + 2145 + if (k.k->type != KEY_TYPE_subvolume) 2146 + return 0; 2147 + 2148 + while (k.k->p.offset != BCACHEFS_ROOT_SUBVOL) { 2149 + ret = darray_push(&subvol_path, k.k->p.offset); 2150 + if (ret) 2151 + goto err; 2152 + 2153 + struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k); 2154 + 2155 + ret = subvol_has_dirent(trans, s); 2156 + if (ret < 0) 2157 + break; 2158 + 2159 + if (fsck_err_on(!ret, 2160 + c, subvol_unreachable, 2161 + "unreachable subvolume %s", 2162 + (bch2_bkey_val_to_text(&buf, c, s.s_c), 2163 + buf.buf))) { 2164 + ret = reattach_subvol(trans, s); 2165 + break; 2166 + } 2167 + 2168 + u32 parent = le32_to_cpu(s.v->fs_path_parent); 2169 + 2170 + if (darray_u32_has(&subvol_path, parent)) { 2171 + if (fsck_err(c, subvol_loop, "subvolume loop")) 2172 + ret = reattach_subvol(trans, s); 2173 + break; 2174 + } 2175 + 2176 + bch2_trans_iter_exit(trans, &parent_iter); 2177 + bch2_trans_iter_init(trans, &parent_iter, 2178 + BTREE_ID_subvolumes, POS(0, parent), 0); 2179 + k = bch2_btree_iter_peek_slot(&parent_iter); 2180 + ret = bkey_err(k); 2181 + if (ret) 2182 + goto err; 2183 + 2184 + if (fsck_err_on(k.k->type != KEY_TYPE_subvolume, 2185 + c, subvol_unreachable, 2186 + "unreachable subvolume %s", 2187 + (bch2_bkey_val_to_text(&buf, c, s.s_c), 2188 + buf.buf))) { 2189 + ret = reattach_subvol(trans, s); 2190 + break; 2191 + } 2192 + } 2193 + fsck_err: 2194 + err: 2195 + printbuf_exit(&buf); 2196 + darray_exit(&subvol_path); 2197 + bch2_trans_iter_exit(trans, &parent_iter); 2198 + return ret; 2199 + } 2200 + 2201 + int bch2_check_subvolume_structure(struct bch_fs *c) 2202 + { 2203 + int ret = bch2_trans_run(c, 2204 + for_each_btree_key_commit(trans, iter, 2205 + BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k, 2206 + NULL, NULL, BCH_TRANS_COMMIT_no_enospc, 2207 + check_subvol_path(trans, &iter, k))); 2208 + bch_err_fn(c, ret); 2209 + return ret; 2210 + } 2211 + 2132 2212 struct pathbuf_entry { 2133 2213 u64 inum; 2134 2214 u32 snapshot; ··· 2244 2122 i->snapshot == snapshot) 2245 2123 return true; 2246 2124 return false; 2247 - } 2248 - 2249 - static int path_down(struct bch_fs *c, pathbuf *p, 2250 - u64 inum, u32 snapshot) 2251 - { 2252 - int ret = darray_push(p, ((struct pathbuf_entry) { 2253 - .inum = inum, 2254 - .snapshot = snapshot, 2255 - })); 2256 - 2257 - if (ret) 2258 - bch_err(c, "fsck: error allocating memory for pathbuf, size %zu", 2259 - p->size); 2260 - return ret; 2261 2125 } 2262 2126 2263 2127 /* ··· 2296 2188 if (!S_ISDIR(inode.bi_mode)) 2297 2189 break; 2298 2190 2299 - ret = path_down(c, p, inode.bi_inum, snapshot); 2300 - if (ret) { 2301 - bch_err(c, "memory allocation failure"); 2191 + ret = darray_push(p, ((struct pathbuf_entry) { 2192 + .inum = inode.bi_inum, 2193 + .snapshot = snapshot, 2194 + })); 2195 + if (ret) 2302 2196 return ret; 2303 - } 2304 2197 2305 2198 snapshot = parent_snapshot; 2306 2199 ··· 2328 2219 pr_err("%llu:%u", i->inum, i->snapshot); 2329 2220 pr_err("%llu:%u", inode.bi_inum, snapshot); 2330 2221 2331 - if (!fsck_err(c, dir_loop, "directory structure loop")) 2332 - return 0; 2333 - 2334 - ret = remove_backpointer(trans, &inode); 2335 - if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart)) 2222 + if (fsck_err(c, dir_loop, "directory structure loop")) { 2223 + ret = remove_backpointer(trans, &inode); 2336 2224 bch_err_msg(c, ret, "removing dirent"); 2337 - if (ret) 2338 - break; 2225 + if (ret) 2226 + break; 2339 2227 2340 - ret = reattach_inode(trans, &inode, snapshot); 2341 - if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart)) 2228 + ret = reattach_inode(trans, &inode, snapshot); 2342 2229 bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum); 2230 + } 2343 2231 break; 2344 2232 } 2345 2233 }
+1
fs/bcachefs/fsck.h
··· 8 8 int bch2_check_dirents(struct bch_fs *); 9 9 int bch2_check_xattrs(struct bch_fs *); 10 10 int bch2_check_root(struct bch_fs *); 11 + int bch2_check_subvolume_structure(struct bch_fs *); 11 12 int bch2_check_directory_structure(struct bch_fs *); 12 13 int bch2_check_nlinks(struct bch_fs *); 13 14 int bch2_fix_reflink_p(struct bch_fs *);
+1
fs/bcachefs/recovery_types.h
··· 44 44 x(check_dirents, 27, PASS_FSCK) \ 45 45 x(check_xattrs, 28, PASS_FSCK) \ 46 46 x(check_root, 29, PASS_ONLINE|PASS_FSCK) \ 47 + x(check_subvolume_structure, 36, PASS_ONLINE|PASS_FSCK) \ 47 48 x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \ 48 49 x(check_nlinks, 31, PASS_FSCK) \ 49 50 x(delete_dead_inodes, 32, PASS_FSCK|PASS_UNCLEAN) \