root-tree.c 11.2 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
	path = btrfs_alloc_path();
T
Tsutomu Itoh 已提交
91 92
	if (!path)
		return -ENOMEM;
93
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
94 95
	if (ret < 0)
		goto out;
96

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

121 122 123 124 125 126 127 128 129
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 已提交
130 131 132
/*
 * copy the data in 'item' into the btree
 */
133 134 135
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
136
{
137
	struct btrfs_path *path;
138
	struct extent_buffer *l;
139 140
	int ret;
	int slot;
141
	unsigned long ptr;
142

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

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
C
Chris Mason 已提交
151 152 153
		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 已提交
154 155 156
		BUG_ON(1);
	}

157
	l = path->nodes[0];
158
	slot = path->slots[0];
159 160
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
161
	btrfs_mark_buffer_dirty(path->nodes[0]);
162
out:
163
	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
{
	struct btrfs_root *dead_root;
	struct btrfs_root_item *ri;
	struct btrfs_key key;
187
	struct btrfs_key found_key;
188 189 190
	struct btrfs_path *path;
	int ret;
	u32 nritems;
191
	struct extent_buffer *leaf;
192 193
	int slot;

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

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

		if (key.objectid < objectid)
			goto next;

		if (key.objectid > objectid)
			break;

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

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

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

256 257 258 259 260
int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
{
	struct extent_buffer *leaf;
	struct btrfs_path *path;
	struct btrfs_key key;
261 262
	struct btrfs_key root_key;
	struct btrfs_root *root;
263 264 265 266 267 268 269 270 271 272 273
	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;

274 275 276
	root_key.type = BTRFS_ROOT_ITEM_KEY;
	root_key.offset = (u64)-1;

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
	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;

301 302 303 304 305 306 307 308 309 310
		root_key.objectid = key.offset;
		key.offset++;

		root = btrfs_read_fs_root_no_name(tree_root->fs_info,
						  &root_key);
		if (!IS_ERR(root))
			continue;

		ret = PTR_ERR(root);
		if (ret != -ENOENT) {
311 312 313 314
			err = ret;
			break;
		}

315 316 317 318 319
		ret = btrfs_find_dead_roots(tree_root, root_key.objectid);
		if (ret) {
			err = ret;
			break;
		}
320 321 322 323 324 325
	}

	btrfs_free_path(path);
	return err;
}

C
Chris Mason 已提交
326
/* drop the root item for 'key' from 'root' */
327 328
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
329
{
330
	struct btrfs_path *path;
331
	int ret;
C
Chris Mason 已提交
332
	struct btrfs_root_item *ri;
333
	struct extent_buffer *leaf;
334

335
	path = btrfs_alloc_path();
T
Tsutomu Itoh 已提交
336 337
	if (!path)
		return -ENOMEM;
338
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
339 340
	if (ret < 0)
		goto out;
341

342
	BUG_ON(ret != 0);
343 344
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);
C
Chris Mason 已提交
345

346
	ret = btrfs_del_item(trans, root, path);
347
out:
348
	btrfs_free_path(path);
349 350
	return ret;
}
351 352 353

int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
354 355 356
		       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
		       const char *name, int name_len)

357
{
358 359 360
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
361
	struct btrfs_key key;
362 363
	unsigned long ptr;
	int err = 0;
364 365 366
	int ret;

	path = btrfs_alloc_path();
367 368
	if (!path)
		return -ENOMEM;
369 370

	key.objectid = root_id;
371
	key.type = BTRFS_ROOT_BACKREF_KEY;
372
	key.offset = ref_id;
373
again:
374
	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
	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;
	}
399 400

	btrfs_free_path(path);
401
	return err;
402 403
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
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;
}

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
/*
 * 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,
434
		       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
435 436 437 438 439 440 441 442 443 444
		       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();
445 446
	if (!path)
		return -ENOMEM;
447 448

	key.objectid = root_id;
449
	key.type = BTRFS_ROOT_BACKREF_KEY;
450
	key.offset = ref_id;
451
again:
452 453 454 455 456 457 458 459 460 461 462 463 464
	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);

465 466 467 468 469 470 471 472
	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;
	}

473
	btrfs_free_path(path);
474
	return 0;
475
}