mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	bcachefs: Fixes for snapshot_tree.master_subvol
Ensure that snapshot_tree.master_subvol is cleared when we delete the master subvolume in a tree of snapshots, and allow for snapshot trees that don't have a master subvolume in fsck. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
		
							parent
							
								
									b5e4cd0871
								
							
						
					
					
						commit
						4bd06f07bc
					
				
					 2 changed files with 47 additions and 15 deletions
				
			
		| 
						 | 
					@ -495,6 +495,9 @@ static int check_snapshot_tree(struct btree_trans *trans,
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!st.v->master_subvol)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = bch2_subvolume_get(trans, le32_to_cpu(st.v->master_subvol), false, &subvol);
 | 
						ret = bch2_subvolume_get(trans, le32_to_cpu(st.v->master_subvol), false, &subvol);
 | 
				
			||||||
	if (ret && !bch2_err_matches(ret, ENOENT))
 | 
						if (ret && !bch2_err_matches(ret, ENOENT))
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
| 
						 | 
					@ -538,6 +541,7 @@ static int check_snapshot_tree(struct btree_trans *trans,
 | 
				
			||||||
		u->v.master_subvol = cpu_to_le32(subvol_id);
 | 
							u->v.master_subvol = cpu_to_le32(subvol_id);
 | 
				
			||||||
		st = snapshot_tree_i_to_s_c(u);
 | 
							st = snapshot_tree_i_to_s_c(u);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
err:
 | 
					err:
 | 
				
			||||||
fsck_err:
 | 
					fsck_err:
 | 
				
			||||||
	bch2_trans_iter_exit(trans, &snapshot_iter);
 | 
						bch2_trans_iter_exit(trans, &snapshot_iter);
 | 
				
			||||||
| 
						 | 
					@ -1037,13 +1041,11 @@ int bch2_check_key_has_snapshot(struct btree_trans *trans,
 | 
				
			||||||
int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
 | 
					int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btree_iter iter;
 | 
						struct btree_iter iter;
 | 
				
			||||||
	struct bkey_i_snapshot *s;
 | 
						struct bkey_i_snapshot *s =
 | 
				
			||||||
	int ret = 0;
 | 
							bch2_bkey_get_mut_typed(trans, &iter,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	s = bch2_bkey_get_mut_typed(trans, &iter,
 | 
					 | 
				
			||||||
				    BTREE_ID_snapshots, POS(0, id),
 | 
									    BTREE_ID_snapshots, POS(0, id),
 | 
				
			||||||
				    0, snapshot);
 | 
									    0, snapshot);
 | 
				
			||||||
	ret = PTR_ERR_OR_ZERO(s);
 | 
						int ret = PTR_ERR_OR_ZERO(s);
 | 
				
			||||||
	if (unlikely(ret)) {
 | 
						if (unlikely(ret)) {
 | 
				
			||||||
		bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT),
 | 
							bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT),
 | 
				
			||||||
					trans->c, "missing snapshot %u", id);
 | 
										trans->c, "missing snapshot %u", id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -409,26 +409,56 @@ static int bch2_subvolumes_reparent(struct btree_trans *trans, u32 subvolid_to_d
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
 | 
					static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btree_iter iter;
 | 
						struct btree_iter subvol_iter = {}, snapshot_iter = {}, snapshot_tree_iter = {};
 | 
				
			||||||
	struct bkey_s_c_subvolume subvol;
 | 
					 | 
				
			||||||
	u32 snapid;
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	subvol = bch2_bkey_get_iter_typed(trans, &iter,
 | 
						struct bkey_s_c_subvolume subvol =
 | 
				
			||||||
 | 
							bch2_bkey_get_iter_typed(trans, &subvol_iter,
 | 
				
			||||||
				BTREE_ID_subvolumes, POS(0, subvolid),
 | 
									BTREE_ID_subvolumes, POS(0, subvolid),
 | 
				
			||||||
				BTREE_ITER_cached|BTREE_ITER_intent,
 | 
									BTREE_ITER_cached|BTREE_ITER_intent,
 | 
				
			||||||
				subvolume);
 | 
									subvolume);
 | 
				
			||||||
	ret = bkey_err(subvol);
 | 
						int ret = bkey_err(subvol);
 | 
				
			||||||
	bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
 | 
						bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
 | 
				
			||||||
				"missing subvolume %u", subvolid);
 | 
									"missing subvolume %u", subvolid);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snapid = le32_to_cpu(subvol.v->snapshot);
 | 
						u32 snapid = le32_to_cpu(subvol.v->snapshot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret =   bch2_btree_delete_at(trans, &iter, 0) ?:
 | 
						struct bkey_s_c_snapshot snapshot =
 | 
				
			||||||
 | 
							bch2_bkey_get_iter_typed(trans, &snapshot_iter,
 | 
				
			||||||
 | 
									BTREE_ID_snapshots, POS(0, snapid),
 | 
				
			||||||
 | 
									0, snapshot);
 | 
				
			||||||
 | 
						ret = bkey_err(subvol);
 | 
				
			||||||
 | 
						bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
 | 
				
			||||||
 | 
									"missing snapshot %u", snapid);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u32 treeid = le32_to_cpu(snapshot.v->tree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct bkey_s_c_snapshot_tree snapshot_tree =
 | 
				
			||||||
 | 
							bch2_bkey_get_iter_typed(trans, &snapshot_tree_iter,
 | 
				
			||||||
 | 
									BTREE_ID_snapshot_trees, POS(0, treeid),
 | 
				
			||||||
 | 
									0, snapshot_tree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (le32_to_cpu(snapshot_tree.v->master_subvol) == subvolid) {
 | 
				
			||||||
 | 
							struct bkey_i_snapshot_tree *snapshot_tree_mut =
 | 
				
			||||||
 | 
								bch2_bkey_make_mut_typed(trans, &snapshot_tree_iter,
 | 
				
			||||||
 | 
											 &snapshot_tree.s_c,
 | 
				
			||||||
 | 
											 0, snapshot_tree);
 | 
				
			||||||
 | 
							ret = PTR_ERR_OR_ZERO(snapshot_tree_mut);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snapshot_tree_mut->v.master_subvol = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret =   bch2_btree_delete_at(trans, &subvol_iter, 0) ?:
 | 
				
			||||||
		bch2_snapshot_node_set_deleted(trans, snapid);
 | 
							bch2_snapshot_node_set_deleted(trans, snapid);
 | 
				
			||||||
	bch2_trans_iter_exit(trans, &iter);
 | 
					err:
 | 
				
			||||||
 | 
						bch2_trans_iter_exit(trans, &snapshot_tree_iter);
 | 
				
			||||||
 | 
						bch2_trans_iter_exit(trans, &snapshot_iter);
 | 
				
			||||||
 | 
						bch2_trans_iter_exit(trans, &subvol_iter);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue