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
	btrfs_free_path(path);
163 164 165
	return ret;
}

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

C
Chris Mason 已提交
175 176
/*
 * at mount time we want to find all the old transaction snapshots that were in
C
Chris Mason 已提交
177 178 179
 * 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 已提交
180
 */
181
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
182 183 184 185 186
{
	struct btrfs_root *dead_root;
	struct btrfs_item *item;
	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 218
		item = btrfs_item_nr(leaf, slot);
		btrfs_item_key_to_cpu(leaf, &key, slot);
219 220
		if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
			goto next;
221 222 223 224 225 226 227

		if (key.objectid < objectid)
			goto next;

		if (key.objectid > objectid)
			break;

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

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

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

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

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

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

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

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

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

	path = btrfs_alloc_path();
353 354
	if (!path)
		return -ENOMEM;
355 356

	key.objectid = root_id;
357
	key.type = BTRFS_ROOT_BACKREF_KEY;
358
	key.offset = ref_id;
359
again:
360
	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	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;
	}
385 386

	btrfs_free_path(path);
387
	return err;
388 389
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
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;
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
/*
 * 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,
420
		       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
421 422 423 424 425 426 427 428 429 430
		       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();
431 432
	if (!path)
		return -ENOMEM;
433 434

	key.objectid = root_id;
435
	key.type = BTRFS_ROOT_BACKREF_KEY;
436
	key.offset = ref_id;
437
again:
438 439 440 441 442 443 444 445 446 447 448 449 450
	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);

451 452 453 454 455 456 457 458
	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;
	}

459
	btrfs_free_path(path);
460
	return 0;
461
}