Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) STRATO AG 2013.  All rights reserved.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  4 */
  5
  6#include <linux/kthread.h>
  7#include <linux/uuid.h>
  8#include <linux/unaligned.h>
  9#include "messages.h"
 10#include "ctree.h"
 11#include "transaction.h"
 12#include "disk-io.h"
 13#include "fs.h"
 14#include "accessors.h"
 15#include "uuid-tree.h"
 16#include "ioctl.h"
 17
 18static void btrfs_uuid_to_key(const u8 *uuid, u8 type, struct btrfs_key *key)
 19{
 20	key->type = type;
 21	key->objectid = get_unaligned_le64(uuid);
 22	key->offset = get_unaligned_le64(uuid + sizeof(u64));
 23}
 24
 25/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
 26static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, const u8 *uuid,
 27				  u8 type, u64 subid)
 28{
 29	int ret;
 30	struct btrfs_path *path = NULL;
 31	struct extent_buffer *eb;
 32	int slot;
 33	u32 item_size;
 34	unsigned long offset;
 35	struct btrfs_key key;
 36
 37	if (WARN_ON_ONCE(!uuid_root)) {
 38		ret = -ENOENT;
 39		goto out;
 40	}
 41
 42	path = btrfs_alloc_path();
 43	if (!path) {
 44		ret = -ENOMEM;
 45		goto out;
 46	}
 47
 48	btrfs_uuid_to_key(uuid, type, &key);
 49	ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
 50	if (ret < 0) {
 51		goto out;
 52	} else if (ret > 0) {
 53		ret = -ENOENT;
 54		goto out;
 55	}
 56
 57	eb = path->nodes[0];
 58	slot = path->slots[0];
 59	item_size = btrfs_item_size(eb, slot);
 60	offset = btrfs_item_ptr_offset(eb, slot);
 61	ret = -ENOENT;
 62
 63	if (!IS_ALIGNED(item_size, sizeof(u64))) {
 64		btrfs_warn(uuid_root->fs_info,
 65			   "uuid item with illegal size %lu!",
 66			   (unsigned long)item_size);
 67		goto out;
 68	}
 69	while (item_size) {
 70		__le64 data;
 71
 72		read_extent_buffer(eb, &data, offset, sizeof(data));
 73		if (le64_to_cpu(data) == subid) {
 74			ret = 0;
 75			break;
 76		}
 77		offset += sizeof(data);
 78		item_size -= sizeof(data);
 79	}
 80
 81out:
 82	btrfs_free_path(path);
 83	return ret;
 84}
 85
 86int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 type,
 
 87			u64 subid_cpu)
 88{
 89	struct btrfs_fs_info *fs_info = trans->fs_info;
 90	struct btrfs_root *uuid_root = fs_info->uuid_root;
 91	int ret;
 92	struct btrfs_path *path = NULL;
 93	struct btrfs_key key;
 94	struct extent_buffer *eb;
 95	int slot;
 96	unsigned long offset;
 97	__le64 subid_le;
 98
 99	ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
100	if (ret != -ENOENT)
101		return ret;
102
103	if (WARN_ON_ONCE(!uuid_root)) {
104		ret = -EINVAL;
105		goto out;
106	}
107
108	btrfs_uuid_to_key(uuid, type, &key);
109
110	path = btrfs_alloc_path();
111	if (!path) {
112		ret = -ENOMEM;
113		goto out;
114	}
115
116	ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
117				      sizeof(subid_le));
118	if (ret == 0) {
119		/* Add an item for the type for the first time */
120		eb = path->nodes[0];
121		slot = path->slots[0];
122		offset = btrfs_item_ptr_offset(eb, slot);
123	} else if (ret == -EEXIST) {
124		/*
125		 * An item with that type already exists.
126		 * Extend the item and store the new subid at the end.
127		 */
128		btrfs_extend_item(trans, path, sizeof(subid_le));
129		eb = path->nodes[0];
130		slot = path->slots[0];
131		offset = btrfs_item_ptr_offset(eb, slot);
132		offset += btrfs_item_size(eb, slot) - sizeof(subid_le);
133	} else {
134		btrfs_warn(fs_info,
135			   "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!",
136			   ret, key.objectid, key.offset, type);
 
137		goto out;
138	}
139
140	ret = 0;
141	subid_le = cpu_to_le64(subid_cpu);
142	write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
143	btrfs_mark_buffer_dirty(trans, eb);
144
145out:
146	btrfs_free_path(path);
147	return ret;
148}
149
150int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 type,
 
151			u64 subid)
152{
153	struct btrfs_fs_info *fs_info = trans->fs_info;
154	struct btrfs_root *uuid_root = fs_info->uuid_root;
155	int ret;
156	struct btrfs_path *path = NULL;
157	struct btrfs_key key;
158	struct extent_buffer *eb;
159	int slot;
160	unsigned long offset;
161	u32 item_size;
162	unsigned long move_dst;
163	unsigned long move_src;
164	unsigned long move_len;
165
166	if (WARN_ON_ONCE(!uuid_root)) {
167		ret = -EINVAL;
168		goto out;
169	}
170
171	btrfs_uuid_to_key(uuid, type, &key);
172
173	path = btrfs_alloc_path();
174	if (!path) {
175		ret = -ENOMEM;
176		goto out;
177	}
178
179	ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
180	if (ret < 0) {
181		btrfs_warn(fs_info, "error %d while searching for uuid item!",
182			   ret);
183		goto out;
184	}
185	if (ret > 0) {
186		ret = -ENOENT;
187		goto out;
188	}
189
190	eb = path->nodes[0];
191	slot = path->slots[0];
192	offset = btrfs_item_ptr_offset(eb, slot);
193	item_size = btrfs_item_size(eb, slot);
194	if (!IS_ALIGNED(item_size, sizeof(u64))) {
195		btrfs_warn(fs_info, "uuid item with illegal size %lu!",
196			   (unsigned long)item_size);
197		ret = -ENOENT;
198		goto out;
199	}
200	while (item_size) {
201		__le64 read_subid;
202
203		read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
204		if (le64_to_cpu(read_subid) == subid)
205			break;
206		offset += sizeof(read_subid);
207		item_size -= sizeof(read_subid);
208	}
209
210	if (!item_size) {
211		ret = -ENOENT;
212		goto out;
213	}
214
215	item_size = btrfs_item_size(eb, slot);
216	if (item_size == sizeof(subid)) {
217		ret = btrfs_del_item(trans, uuid_root, path);
218		goto out;
219	}
220
221	move_dst = offset;
222	move_src = offset + sizeof(subid);
223	move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
224	memmove_extent_buffer(eb, move_dst, move_src, move_len);
225	btrfs_truncate_item(trans, path, item_size - sizeof(subid), 1);
226
227out:
228	btrfs_free_path(path);
229	return ret;
230}
231
232static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
233			       u64 subid)
234{
235	struct btrfs_trans_handle *trans;
236	int ret;
237
238	/* 1 - for the uuid item */
239	trans = btrfs_start_transaction(uuid_root, 1);
240	if (IS_ERR(trans)) {
241		ret = PTR_ERR(trans);
242		goto out;
243	}
244
245	ret = btrfs_uuid_tree_remove(trans, uuid, type, subid);
246	btrfs_end_transaction(trans);
247
248out:
249	return ret;
250}
251
252/*
253 * Check if there's an matching subvolume for given UUID
254 *
255 * Return:
256 * 0	check succeeded, the entry is not outdated
257 * > 0	if the check failed, the caller should remove the entry
258 * < 0	if an error occurred
259 */
260static int btrfs_check_uuid_tree_entry(struct btrfs_fs_info *fs_info,
261				       const u8 *uuid, u8 type, u64 subvolid)
262{
263	int ret = 0;
264	struct btrfs_root *subvol_root;
265
266	if (type != BTRFS_UUID_KEY_SUBVOL &&
267	    type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
268		goto out;
269
270	subvol_root = btrfs_get_fs_root(fs_info, subvolid, true);
271	if (IS_ERR(subvol_root)) {
272		ret = PTR_ERR(subvol_root);
273		if (ret == -ENOENT)
274			ret = 1;
275		goto out;
276	}
277
278	switch (type) {
279	case BTRFS_UUID_KEY_SUBVOL:
280		if (memcmp(uuid, subvol_root->root_item.uuid, BTRFS_UUID_SIZE))
281			ret = 1;
282		break;
283	case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
284		if (memcmp(uuid, subvol_root->root_item.received_uuid,
285			   BTRFS_UUID_SIZE))
286			ret = 1;
287		break;
288	}
289	btrfs_put_root(subvol_root);
290out:
291	return ret;
292}
293
294int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info)
 
 
295{
296	struct btrfs_root *root = fs_info->uuid_root;
297	struct btrfs_key key;
298	struct btrfs_path *path;
299	int ret = 0;
300	struct extent_buffer *leaf;
301	int slot;
302	u32 item_size;
303	unsigned long offset;
304
305	path = btrfs_alloc_path();
306	if (!path) {
307		ret = -ENOMEM;
308		goto out;
309	}
310
311	key.objectid = 0;
312	key.type = 0;
313	key.offset = 0;
314
315again_search_slot:
316	ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
 
317	if (ret) {
318		if (ret > 0)
319			ret = 0;
320		goto out;
321	}
322
323	while (1) {
324		if (btrfs_fs_closing(fs_info)) {
325			ret = -EINTR;
326			goto out;
327		}
328		cond_resched();
329		leaf = path->nodes[0];
330		slot = path->slots[0];
331		btrfs_item_key_to_cpu(leaf, &key, slot);
332
333		if (key.type != BTRFS_UUID_KEY_SUBVOL &&
334		    key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
335			goto skip;
336
337		offset = btrfs_item_ptr_offset(leaf, slot);
338		item_size = btrfs_item_size(leaf, slot);
339		if (!IS_ALIGNED(item_size, sizeof(u64))) {
340			btrfs_warn(fs_info,
341				   "uuid item with illegal size %lu!",
342				   (unsigned long)item_size);
343			goto skip;
344		}
345		while (item_size) {
346			u8 uuid[BTRFS_UUID_SIZE];
347			__le64 subid_le;
348			u64 subid_cpu;
349
350			put_unaligned_le64(key.objectid, uuid);
351			put_unaligned_le64(key.offset, uuid + sizeof(u64));
352			read_extent_buffer(leaf, &subid_le, offset,
353					   sizeof(subid_le));
354			subid_cpu = le64_to_cpu(subid_le);
355			ret = btrfs_check_uuid_tree_entry(fs_info, uuid,
356							  key.type, subid_cpu);
357			if (ret < 0)
358				goto out;
359			if (ret > 0) {
360				btrfs_release_path(path);
361				ret = btrfs_uuid_iter_rem(root, uuid, key.type,
362							  subid_cpu);
363				if (ret == 0) {
364					/*
365					 * this might look inefficient, but the
366					 * justification is that it is an
367					 * exception that check_func returns 1,
368					 * and that in the regular case only one
369					 * entry per UUID exists.
370					 */
371					goto again_search_slot;
372				}
373				if (ret < 0 && ret != -ENOENT)
374					goto out;
375				key.offset++;
376				goto again_search_slot;
377			}
378			item_size -= sizeof(subid_le);
379			offset += sizeof(subid_le);
380		}
381
382skip:
383		ret = btrfs_next_item(root, path);
384		if (ret == 0)
385			continue;
386		else if (ret > 0)
387			ret = 0;
388		break;
389	}
390
391out:
392	btrfs_free_path(path);
393	return ret;
394}
395
396int btrfs_uuid_scan_kthread(void *data)
397{
398	struct btrfs_fs_info *fs_info = data;
399	struct btrfs_root *root = fs_info->tree_root;
400	struct btrfs_key key;
401	struct btrfs_path *path = NULL;
402	int ret = 0;
403	struct extent_buffer *eb;
404	int slot;
405	struct btrfs_root_item root_item;
406	u32 item_size;
407	struct btrfs_trans_handle *trans = NULL;
408	bool closing = false;
409
410	path = btrfs_alloc_path();
411	if (!path) {
412		ret = -ENOMEM;
413		goto out;
414	}
415
416	key.objectid = 0;
417	key.type = BTRFS_ROOT_ITEM_KEY;
418	key.offset = 0;
419
420	while (1) {
421		if (btrfs_fs_closing(fs_info)) {
422			closing = true;
423			break;
424		}
425		ret = btrfs_search_forward(root, &key, path,
426				BTRFS_OLDEST_GENERATION);
427		if (ret) {
428			if (ret > 0)
429				ret = 0;
430			break;
431		}
432
433		if (key.type != BTRFS_ROOT_ITEM_KEY ||
434		    (key.objectid < BTRFS_FIRST_FREE_OBJECTID &&
435		     key.objectid != BTRFS_FS_TREE_OBJECTID) ||
436		    key.objectid > BTRFS_LAST_FREE_OBJECTID)
437			goto skip;
438
439		eb = path->nodes[0];
440		slot = path->slots[0];
441		item_size = btrfs_item_size(eb, slot);
442		if (item_size < sizeof(root_item))
443			goto skip;
444
445		read_extent_buffer(eb, &root_item,
446				   btrfs_item_ptr_offset(eb, slot),
447				   (int)sizeof(root_item));
448		if (btrfs_root_refs(&root_item) == 0)
449			goto skip;
450
451		if (!btrfs_is_empty_uuid(root_item.uuid) ||
452		    !btrfs_is_empty_uuid(root_item.received_uuid)) {
453			if (trans)
454				goto update_tree;
455
456			btrfs_release_path(path);
457			/*
458			 * 1 - subvol uuid item
459			 * 1 - received_subvol uuid item
460			 */
461			trans = btrfs_start_transaction(fs_info->uuid_root, 2);
462			if (IS_ERR(trans)) {
463				ret = PTR_ERR(trans);
464				break;
465			}
466			continue;
467		} else {
468			goto skip;
469		}
470update_tree:
471		btrfs_release_path(path);
472		if (!btrfs_is_empty_uuid(root_item.uuid)) {
473			ret = btrfs_uuid_tree_add(trans, root_item.uuid,
474						  BTRFS_UUID_KEY_SUBVOL,
475						  key.objectid);
476			if (ret < 0) {
477				btrfs_warn(fs_info, "uuid_tree_add failed %d",
478					ret);
479				break;
480			}
481		}
482
483		if (!btrfs_is_empty_uuid(root_item.received_uuid)) {
484			ret = btrfs_uuid_tree_add(trans,
485						  root_item.received_uuid,
486						 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
487						  key.objectid);
488			if (ret < 0) {
489				btrfs_warn(fs_info, "uuid_tree_add failed %d",
490					ret);
491				break;
492			}
493		}
494
495skip:
496		btrfs_release_path(path);
497		if (trans) {
498			ret = btrfs_end_transaction(trans);
499			trans = NULL;
500			if (ret)
501				break;
502		}
503
504		if (key.offset < (u64)-1) {
505			key.offset++;
506		} else if (key.type < BTRFS_ROOT_ITEM_KEY) {
507			key.offset = 0;
508			key.type = BTRFS_ROOT_ITEM_KEY;
509		} else if (key.objectid < (u64)-1) {
510			key.offset = 0;
511			key.type = BTRFS_ROOT_ITEM_KEY;
512			key.objectid++;
513		} else {
514			break;
515		}
516		cond_resched();
517	}
518
519out:
520	btrfs_free_path(path);
521	if (trans && !IS_ERR(trans))
522		btrfs_end_transaction(trans);
523	if (ret)
524		btrfs_warn(fs_info, "btrfs_uuid_scan_kthread failed %d", ret);
525	else if (!closing)
526		set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags);
527	up(&fs_info->uuid_tree_rescan_sem);
528	return 0;
529}
530
531int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
532{
533	struct btrfs_trans_handle *trans;
534	struct btrfs_root *tree_root = fs_info->tree_root;
535	struct btrfs_root *uuid_root;
536	struct task_struct *task;
537	int ret;
538
539	/*
540	 * 1 - root node
541	 * 1 - root item
542	 */
543	trans = btrfs_start_transaction(tree_root, 2);
544	if (IS_ERR(trans))
545		return PTR_ERR(trans);
546
547	uuid_root = btrfs_create_tree(trans, BTRFS_UUID_TREE_OBJECTID);
548	if (IS_ERR(uuid_root)) {
549		ret = PTR_ERR(uuid_root);
550		btrfs_abort_transaction(trans, ret);
551		btrfs_end_transaction(trans);
552		return ret;
553	}
554
555	fs_info->uuid_root = uuid_root;
556
557	ret = btrfs_commit_transaction(trans);
558	if (ret)
559		return ret;
560
561	down(&fs_info->uuid_tree_rescan_sem);
562	task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid");
563	if (IS_ERR(task)) {
564		/* fs_info->update_uuid_tree_gen remains 0 in all error case */
565		btrfs_warn(fs_info, "failed to start uuid_scan task");
566		up(&fs_info->uuid_tree_rescan_sem);
567		return PTR_ERR(task);
568	}
569
570	return 0;
571}
v3.15
 
  1/*
  2 * Copyright (C) STRATO AG 2013.  All rights reserved.
  3 *
  4 * This program is free software; you can redistribute it and/or
  5 * modify it under the terms of the GNU General Public
  6 * License v2 as published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11 * General Public License for more details.
 12 *
 13 * You should have received a copy of the GNU General Public
 14 * License along with this program; if not, write to the
 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 16 * Boston, MA 021110-1307, USA.
 17 */
 
 
 18#include <linux/uuid.h>
 19#include <asm/unaligned.h>
 
 20#include "ctree.h"
 21#include "transaction.h"
 22#include "disk-io.h"
 23#include "print-tree.h"
 24
 
 
 25
 26static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key)
 27{
 28	key->type = type;
 29	key->objectid = get_unaligned_le64(uuid);
 30	key->offset = get_unaligned_le64(uuid + sizeof(u64));
 31}
 32
 33/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
 34static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
 35				  u8 type, u64 subid)
 36{
 37	int ret;
 38	struct btrfs_path *path = NULL;
 39	struct extent_buffer *eb;
 40	int slot;
 41	u32 item_size;
 42	unsigned long offset;
 43	struct btrfs_key key;
 44
 45	if (WARN_ON_ONCE(!uuid_root)) {
 46		ret = -ENOENT;
 47		goto out;
 48	}
 49
 50	path = btrfs_alloc_path();
 51	if (!path) {
 52		ret = -ENOMEM;
 53		goto out;
 54	}
 55
 56	btrfs_uuid_to_key(uuid, type, &key);
 57	ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
 58	if (ret < 0) {
 59		goto out;
 60	} else if (ret > 0) {
 61		ret = -ENOENT;
 62		goto out;
 63	}
 64
 65	eb = path->nodes[0];
 66	slot = path->slots[0];
 67	item_size = btrfs_item_size_nr(eb, slot);
 68	offset = btrfs_item_ptr_offset(eb, slot);
 69	ret = -ENOENT;
 70
 71	if (!IS_ALIGNED(item_size, sizeof(u64))) {
 72		btrfs_warn(uuid_root->fs_info, "uuid item with illegal size %lu!",
 73			(unsigned long)item_size);
 
 74		goto out;
 75	}
 76	while (item_size) {
 77		__le64 data;
 78
 79		read_extent_buffer(eb, &data, offset, sizeof(data));
 80		if (le64_to_cpu(data) == subid) {
 81			ret = 0;
 82			break;
 83		}
 84		offset += sizeof(data);
 85		item_size -= sizeof(data);
 86	}
 87
 88out:
 89	btrfs_free_path(path);
 90	return ret;
 91}
 92
 93int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
 94			struct btrfs_root *uuid_root, u8 *uuid, u8 type,
 95			u64 subid_cpu)
 96{
 
 
 97	int ret;
 98	struct btrfs_path *path = NULL;
 99	struct btrfs_key key;
100	struct extent_buffer *eb;
101	int slot;
102	unsigned long offset;
103	__le64 subid_le;
104
105	ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
106	if (ret != -ENOENT)
107		return ret;
108
109	if (WARN_ON_ONCE(!uuid_root)) {
110		ret = -EINVAL;
111		goto out;
112	}
113
114	btrfs_uuid_to_key(uuid, type, &key);
115
116	path = btrfs_alloc_path();
117	if (!path) {
118		ret = -ENOMEM;
119		goto out;
120	}
121
122	ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
123				      sizeof(subid_le));
124	if (ret >= 0) {
125		/* Add an item for the type for the first time */
126		eb = path->nodes[0];
127		slot = path->slots[0];
128		offset = btrfs_item_ptr_offset(eb, slot);
129	} else if (ret == -EEXIST) {
130		/*
131		 * An item with that type already exists.
132		 * Extend the item and store the new subid at the end.
133		 */
134		btrfs_extend_item(uuid_root, path, sizeof(subid_le));
135		eb = path->nodes[0];
136		slot = path->slots[0];
137		offset = btrfs_item_ptr_offset(eb, slot);
138		offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
139	} else if (ret < 0) {
140		btrfs_warn(uuid_root->fs_info, "insert uuid item failed %d "
141			"(0x%016llx, 0x%016llx) type %u!",
142			ret, (unsigned long long)key.objectid,
143			(unsigned long long)key.offset, type);
144		goto out;
145	}
146
147	ret = 0;
148	subid_le = cpu_to_le64(subid_cpu);
149	write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
150	btrfs_mark_buffer_dirty(eb);
151
152out:
153	btrfs_free_path(path);
154	return ret;
155}
156
157int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
158			struct btrfs_root *uuid_root, u8 *uuid, u8 type,
159			u64 subid)
160{
 
 
161	int ret;
162	struct btrfs_path *path = NULL;
163	struct btrfs_key key;
164	struct extent_buffer *eb;
165	int slot;
166	unsigned long offset;
167	u32 item_size;
168	unsigned long move_dst;
169	unsigned long move_src;
170	unsigned long move_len;
171
172	if (WARN_ON_ONCE(!uuid_root)) {
173		ret = -EINVAL;
174		goto out;
175	}
176
177	btrfs_uuid_to_key(uuid, type, &key);
178
179	path = btrfs_alloc_path();
180	if (!path) {
181		ret = -ENOMEM;
182		goto out;
183	}
184
185	ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
186	if (ret < 0) {
187		btrfs_warn(uuid_root->fs_info, "error %d while searching for uuid item!",
188			ret);
189		goto out;
190	}
191	if (ret > 0) {
192		ret = -ENOENT;
193		goto out;
194	}
195
196	eb = path->nodes[0];
197	slot = path->slots[0];
198	offset = btrfs_item_ptr_offset(eb, slot);
199	item_size = btrfs_item_size_nr(eb, slot);
200	if (!IS_ALIGNED(item_size, sizeof(u64))) {
201		btrfs_warn(uuid_root->fs_info, "uuid item with illegal size %lu!",
202			(unsigned long)item_size);
203		ret = -ENOENT;
204		goto out;
205	}
206	while (item_size) {
207		__le64 read_subid;
208
209		read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
210		if (le64_to_cpu(read_subid) == subid)
211			break;
212		offset += sizeof(read_subid);
213		item_size -= sizeof(read_subid);
214	}
215
216	if (!item_size) {
217		ret = -ENOENT;
218		goto out;
219	}
220
221	item_size = btrfs_item_size_nr(eb, slot);
222	if (item_size == sizeof(subid)) {
223		ret = btrfs_del_item(trans, uuid_root, path);
224		goto out;
225	}
226
227	move_dst = offset;
228	move_src = offset + sizeof(subid);
229	move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
230	memmove_extent_buffer(eb, move_dst, move_src, move_len);
231	btrfs_truncate_item(uuid_root, path, item_size - sizeof(subid), 1);
232
233out:
234	btrfs_free_path(path);
235	return ret;
236}
237
238static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
239			       u64 subid)
240{
241	struct btrfs_trans_handle *trans;
242	int ret;
243
244	/* 1 - for the uuid item */
245	trans = btrfs_start_transaction(uuid_root, 1);
246	if (IS_ERR(trans)) {
247		ret = PTR_ERR(trans);
248		goto out;
249	}
250
251	ret = btrfs_uuid_tree_rem(trans, uuid_root, uuid, type, subid);
252	btrfs_end_transaction(trans, uuid_root);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
 
 
 
 
 
 
 
 
 
 
 
254out:
255	return ret;
256}
257
258int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
259			    int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
260					      u64))
261{
262	struct btrfs_root *root = fs_info->uuid_root;
263	struct btrfs_key key;
264	struct btrfs_path *path;
265	int ret = 0;
266	struct extent_buffer *leaf;
267	int slot;
268	u32 item_size;
269	unsigned long offset;
270
271	path = btrfs_alloc_path();
272	if (!path) {
273		ret = -ENOMEM;
274		goto out;
275	}
276
277	key.objectid = 0;
278	key.type = 0;
279	key.offset = 0;
280
281again_search_slot:
282	path->keep_locks = 1;
283	ret = btrfs_search_forward(root, &key, path, 0);
284	if (ret) {
285		if (ret > 0)
286			ret = 0;
287		goto out;
288	}
289
290	while (1) {
 
 
 
 
291		cond_resched();
292		leaf = path->nodes[0];
293		slot = path->slots[0];
294		btrfs_item_key_to_cpu(leaf, &key, slot);
295
296		if (key.type != BTRFS_UUID_KEY_SUBVOL &&
297		    key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
298			goto skip;
299
300		offset = btrfs_item_ptr_offset(leaf, slot);
301		item_size = btrfs_item_size_nr(leaf, slot);
302		if (!IS_ALIGNED(item_size, sizeof(u64))) {
303			btrfs_warn(fs_info, "uuid item with illegal size %lu!",
304				(unsigned long)item_size);
 
305			goto skip;
306		}
307		while (item_size) {
308			u8 uuid[BTRFS_UUID_SIZE];
309			__le64 subid_le;
310			u64 subid_cpu;
311
312			put_unaligned_le64(key.objectid, uuid);
313			put_unaligned_le64(key.offset, uuid + sizeof(u64));
314			read_extent_buffer(leaf, &subid_le, offset,
315					   sizeof(subid_le));
316			subid_cpu = le64_to_cpu(subid_le);
317			ret = check_func(fs_info, uuid, key.type, subid_cpu);
 
318			if (ret < 0)
319				goto out;
320			if (ret > 0) {
321				btrfs_release_path(path);
322				ret = btrfs_uuid_iter_rem(root, uuid, key.type,
323							  subid_cpu);
324				if (ret == 0) {
325					/*
326					 * this might look inefficient, but the
327					 * justification is that it is an
328					 * exception that check_func returns 1,
329					 * and that in the regular case only one
330					 * entry per UUID exists.
331					 */
332					goto again_search_slot;
333				}
334				if (ret < 0 && ret != -ENOENT)
335					goto out;
 
 
336			}
337			item_size -= sizeof(subid_le);
338			offset += sizeof(subid_le);
339		}
340
341skip:
342		ret = btrfs_next_item(root, path);
343		if (ret == 0)
344			continue;
345		else if (ret > 0)
346			ret = 0;
347		break;
348	}
349
350out:
351	btrfs_free_path(path);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352	if (ret)
353		btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354	return 0;
355}