root-tree.c 11.0 KB
Newer Older
C
Chris Mason 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2007 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

19
#include "ctree.h"
20
#include "transaction.h"
21 22 23
#include "disk-io.h"
#include "print-tree.h"

24
/*
C
Chris Mason 已提交
25 26 27 28
 *  search forward for a root, starting with objectid 'search_start'
 *  if a root key is found, the objectid we find is filled into 'found_objectid'
 *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing
 *  left in the tree.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 */
int btrfs_search_root(struct btrfs_root *root, u64 search_start,
		      u64 *found_objectid)
{
	struct btrfs_path *path;
	struct btrfs_key search_key;
	int ret;

	root = root->fs_info->tree_root;
	search_key.objectid = search_start;
	search_key.type = (u8)-1;
	search_key.offset = (u64)-1;

	path = btrfs_alloc_path();
	BUG_ON(!path);
again:
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
	if (ret < 0)
		goto out;
	if (ret == 0) {
		ret = 1;
		goto out;
	}
	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
		ret = btrfs_next_leaf(root, path);
		if (ret)
			goto out;
	}
	btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]);
	if (search_key.type != BTRFS_ROOT_ITEM_KEY) {
		search_key.offset++;
		btrfs_release_path(root, path);
		goto again;
	}
	ret = 0;
	*found_objectid = search_key.objectid;

out:
	btrfs_free_path(path);
	return ret;
}

C
Chris Mason 已提交
71 72 73 74 75
/*
 * lookup the root with the highest offset for a given objectid.  The key we do
 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
 * on error.
 */
76 77 78
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
			struct btrfs_root_item *item, struct btrfs_key *key)
{
79
	struct btrfs_path *path;
80
	struct btrfs_key search_key;
81 82
	struct btrfs_key found_key;
	struct extent_buffer *l;
83 84 85 86
	int ret;
	int slot;

	search_key.objectid = objectid;
87
	search_key.type = BTRFS_ROOT_ITEM_KEY;
88
	search_key.offset = (u64)-1;
89

90 91 92
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
93 94
	if (ret < 0)
		goto out;
95

96
	BUG_ON(ret == 0);
97 98 99 100
	if (path->slots[0] == 0) {
		ret = 1;
		goto out;
	}
101
	l = path->nodes[0];
102
	slot = path->slots[0] - 1;
103
	btrfs_item_key_to_cpu(l, &found_key, slot);
104 105
	if (found_key.objectid != objectid ||
	    found_key.type != BTRFS_ROOT_ITEM_KEY) {
106 107 108
		ret = 1;
		goto out;
	}
109 110 111 112 113
	if (item)
		read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
				   sizeof(*item));
	if (key)
		memcpy(key, &found_key, sizeof(found_key));
114 115
	ret = 0;
out:
116
	btrfs_free_path(path);
117 118 119
	return ret;
}

120 121 122 123 124 125 126 127 128
int btrfs_set_root_node(struct btrfs_root_item *item,
			struct extent_buffer *node)
{
	btrfs_set_root_bytenr(item, node->start);
	btrfs_set_root_level(item, btrfs_header_level(node));
	btrfs_set_root_generation(item, btrfs_header_generation(node));
	return 0;
}

C
Chris Mason 已提交
129 130 131
/*
 * copy the data in 'item' into the btree
 */
132 133 134
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
135
{
136
	struct btrfs_path *path;
137
	struct extent_buffer *l;
138 139
	int ret;
	int slot;
140
	unsigned long ptr;
141

142 143 144
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
145 146
	if (ret < 0)
		goto out;
C
Chris Mason 已提交
147 148 149

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
C
Chris Mason 已提交
150 151 152
		printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
		       (unsigned long long)key->objectid, key->type,
		       (unsigned long long)key->offset);
C
Chris Mason 已提交
153 154 155
		BUG_ON(1);
	}

156
	l = path->nodes[0];
157
	slot = path->slots[0];
158 159
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
160
	btrfs_mark_buffer_dirty(path->nodes[0]);
161
out:
162 163
	btrfs_release_path(root, path);
	btrfs_free_path(path);
164 165 166
	return ret;
}

167 168 169
int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
170 171
{
	int ret;
172
	ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
173 174 175
	return ret;
}

C
Chris Mason 已提交
176 177
/*
 * at mount time we want to find all the old transaction snapshots that were in
C
Chris Mason 已提交
178 179 180
 * the process of being deleted if we crashed.  This is any root item with an
 * offset lower than the latest root.  They need to be queued for deletion to
 * finish what was happening when we crashed.
C
Chris Mason 已提交
181
 */
182
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
183 184 185 186 187
{
	struct btrfs_root *dead_root;
	struct btrfs_item *item;
	struct btrfs_root_item *ri;
	struct btrfs_key key;
188
	struct btrfs_key found_key;
189 190 191
	struct btrfs_path *path;
	int ret;
	u32 nritems;
192
	struct extent_buffer *leaf;
193 194
	int slot;

195
	key.objectid = objectid;
196 197 198 199 200
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	key.offset = 0;
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
201 202

again:
203 204 205
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto err;
C
Chris Mason 已提交
206
	while (1) {
207 208
		leaf = path->nodes[0];
		nritems = btrfs_header_nritems(leaf);
209 210 211 212 213
		slot = path->slots[0];
		if (slot >= nritems) {
			ret = btrfs_next_leaf(root, path);
			if (ret)
				break;
214 215
			leaf = path->nodes[0];
			nritems = btrfs_header_nritems(leaf);
216 217
			slot = path->slots[0];
		}
218 219
		item = btrfs_item_nr(leaf, slot);
		btrfs_item_key_to_cpu(leaf, &key, slot);
220 221
		if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
			goto next;
222 223 224 225 226 227 228

		if (key.objectid < objectid)
			goto next;

		if (key.objectid > objectid)
			break;

229
		ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
230
		if (btrfs_disk_root_refs(leaf, ri) != 0)
231
			goto next;
232

233 234 235
		memcpy(&found_key, &key, sizeof(key));
		key.offset++;
		btrfs_release_path(root, path);
236 237 238
		dead_root =
			btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
						    &found_key);
A
Aneesh 已提交
239 240
		if (IS_ERR(dead_root)) {
			ret = PTR_ERR(dead_root);
241 242
			goto err;
		}
243

244
		ret = btrfs_add_dead_root(dead_root);
245 246
		if (ret)
			goto err;
247
		goto again;
248 249 250 251 252 253 254 255 256 257
next:
		slot++;
		path->slots[0]++;
	}
	ret = 0;
err:
	btrfs_free_path(path);
	return ret;
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
{
	struct extent_buffer *leaf;
	struct btrfs_path *path;
	struct btrfs_key key;
	int err = 0;
	int ret;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	key.objectid = BTRFS_ORPHAN_OBJECTID;
	key.type = BTRFS_ORPHAN_ITEM_KEY;
	key.offset = 0;

	while (1) {
		ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
		if (ret < 0) {
			err = ret;
			break;
		}

		leaf = path->nodes[0];
		if (path->slots[0] >= btrfs_header_nritems(leaf)) {
			ret = btrfs_next_leaf(tree_root, path);
			if (ret < 0)
				err = ret;
			if (ret != 0)
				break;
			leaf = path->nodes[0];
		}

		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
		btrfs_release_path(tree_root, path);

		if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
		    key.type != BTRFS_ORPHAN_ITEM_KEY)
			break;

		ret = btrfs_find_dead_roots(tree_root, key.offset);
		if (ret) {
			err = ret;
			break;
		}

		key.offset++;
	}

	btrfs_free_path(path);
	return err;
}

C
Chris Mason 已提交
311
/* drop the root item for 'key' from 'root' */
312 313
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
314
{
315
	struct btrfs_path *path;
316
	int ret;
C
Chris Mason 已提交
317 318
	u32 refs;
	struct btrfs_root_item *ri;
319
	struct extent_buffer *leaf;
320

321 322 323
	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
324 325
	if (ret < 0)
		goto out;
326

327
	BUG_ON(ret != 0);
328 329
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
C
Chris Mason 已提交
330

331
	refs = btrfs_disk_root_refs(leaf, ri);
332 333
	BUG_ON(refs != 0);
	ret = btrfs_del_item(trans, root, path);
334
out:
335 336
	btrfs_release_path(root, path);
	btrfs_free_path(path);
337 338
	return ret;
}
339 340 341

int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
342 343 344
		       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
		       const char *name, int name_len)

345
{
346 347 348
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
349
	struct btrfs_key key;
350 351
	unsigned long ptr;
	int err = 0;
352 353 354
	int ret;

	path = btrfs_alloc_path();
355 356
	if (!path)
		return -ENOMEM;
357 358

	key.objectid = root_id;
359
	key.type = BTRFS_ROOT_BACKREF_KEY;
360
	key.offset = ref_id;
361
again:
362
	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
	BUG_ON(ret < 0);
	if (ret == 0) {
		leaf = path->nodes[0];
		ref = btrfs_item_ptr(leaf, path->slots[0],
				     struct btrfs_root_ref);

		WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid);
		WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len);
		ptr = (unsigned long)(ref + 1);
		WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len));
		*sequence = btrfs_root_ref_sequence(leaf, ref);

		ret = btrfs_del_item(trans, tree_root, path);
		BUG_ON(ret);
	} else
		err = -ENOENT;

	if (key.type == BTRFS_ROOT_BACKREF_KEY) {
		btrfs_release_path(tree_root, path);
		key.objectid = ref_id;
		key.type = BTRFS_ROOT_REF_KEY;
		key.offset = root_id;
		goto again;
	}
387 388

	btrfs_free_path(path);
389
	return err;
390 391
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
int btrfs_find_root_ref(struct btrfs_root *tree_root,
		   struct btrfs_path *path,
		   u64 root_id, u64 ref_id)
{
	struct btrfs_key key;
	int ret;

	key.objectid = root_id;
	key.type = BTRFS_ROOT_REF_KEY;
	key.offset = ref_id;

	ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
	return ret;
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
/*
 * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
 * or BTRFS_ROOT_BACKREF_KEY.
 *
 * The dirid, sequence, name and name_len refer to the directory entry
 * that is referencing the root.
 *
 * For a forward ref, the root_id is the id of the tree referencing
 * the root and ref_id is the id of the subvol  or snapshot.
 *
 * For a back ref the root_id is the id of the subvol or snapshot and
 * ref_id is the id of the tree referencing it.
 */
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
422
		       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
423 424 425 426 427 428 429 430 431 432
		       const char *name, int name_len)
{
	struct btrfs_key key;
	int ret;
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
	unsigned long ptr;

	path = btrfs_alloc_path();
433 434
	if (!path)
		return -ENOMEM;
435 436

	key.objectid = root_id;
437
	key.type = BTRFS_ROOT_BACKREF_KEY;
438
	key.offset = ref_id;
439
again:
440 441 442 443 444 445 446 447 448 449 450 451 452
	ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
				      sizeof(*ref) + name_len);
	BUG_ON(ret);

	leaf = path->nodes[0];
	ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
	btrfs_set_root_ref_dirid(leaf, ref, dirid);
	btrfs_set_root_ref_sequence(leaf, ref, sequence);
	btrfs_set_root_ref_name_len(leaf, ref, name_len);
	ptr = (unsigned long)(ref + 1);
	write_extent_buffer(leaf, name, ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);

453 454 455 456 457 458 459 460
	if (key.type == BTRFS_ROOT_BACKREF_KEY) {
		btrfs_release_path(tree_root, path);
		key.objectid = ref_id;
		key.type = BTRFS_ROOT_REF_KEY;
		key.offset = root_id;
		goto again;
	}

461
	btrfs_free_path(path);
462
	return 0;
463
}