Linux Audio

Check our new training course

Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) STRATO AG 2013.  All rights reserved.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  4 */
  5
  6#include <linux/uuid.h>
  7#include <asm/unaligned.h>
  8#include "ctree.h"
  9#include "transaction.h"
 10#include "disk-io.h"
 11#include "print-tree.h"
 12
 13
 14static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key)
 15{
 16	key->type = type;
 17	key->objectid = get_unaligned_le64(uuid);
 18	key->offset = get_unaligned_le64(uuid + sizeof(u64));
 19}
 20
 21/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
 22static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
 23				  u8 type, u64 subid)
 24{
 25	int ret;
 26	struct btrfs_path *path = NULL;
 27	struct extent_buffer *eb;
 28	int slot;
 29	u32 item_size;
 30	unsigned long offset;
 31	struct btrfs_key key;
 32
 33	if (WARN_ON_ONCE(!uuid_root)) {
 34		ret = -ENOENT;
 35		goto out;
 36	}
 37
 38	path = btrfs_alloc_path();
 39	if (!path) {
 40		ret = -ENOMEM;
 41		goto out;
 42	}
 43
 44	btrfs_uuid_to_key(uuid, type, &key);
 45	ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
 46	if (ret < 0) {
 47		goto out;
 48	} else if (ret > 0) {
 49		ret = -ENOENT;
 50		goto out;
 51	}
 52
 53	eb = path->nodes[0];
 54	slot = path->slots[0];
 55	item_size = btrfs_item_size_nr(eb, slot);
 56	offset = btrfs_item_ptr_offset(eb, slot);
 57	ret = -ENOENT;
 58
 59	if (!IS_ALIGNED(item_size, sizeof(u64))) {
 60		btrfs_warn(uuid_root->fs_info,
 61			   "uuid item with illegal size %lu!",
 62			   (unsigned long)item_size);
 63		goto out;
 64	}
 65	while (item_size) {
 66		__le64 data;
 67
 68		read_extent_buffer(eb, &data, offset, sizeof(data));
 69		if (le64_to_cpu(data) == subid) {
 70			ret = 0;
 71			break;
 72		}
 73		offset += sizeof(data);
 74		item_size -= sizeof(data);
 75	}
 76
 77out:
 78	btrfs_free_path(path);
 79	return ret;
 80}
 81
 82int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
 
 83			u64 subid_cpu)
 84{
 85	struct btrfs_fs_info *fs_info = trans->fs_info;
 86	struct btrfs_root *uuid_root = fs_info->uuid_root;
 87	int ret;
 88	struct btrfs_path *path = NULL;
 89	struct btrfs_key key;
 90	struct extent_buffer *eb;
 91	int slot;
 92	unsigned long offset;
 93	__le64 subid_le;
 94
 95	ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
 96	if (ret != -ENOENT)
 97		return ret;
 98
 99	if (WARN_ON_ONCE(!uuid_root)) {
100		ret = -EINVAL;
101		goto out;
102	}
103
104	btrfs_uuid_to_key(uuid, type, &key);
105
106	path = btrfs_alloc_path();
107	if (!path) {
108		ret = -ENOMEM;
109		goto out;
110	}
111
112	ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
113				      sizeof(subid_le));
114	if (ret >= 0) {
115		/* Add an item for the type for the first time */
116		eb = path->nodes[0];
117		slot = path->slots[0];
118		offset = btrfs_item_ptr_offset(eb, slot);
119	} else if (ret == -EEXIST) {
120		/*
121		 * An item with that type already exists.
122		 * Extend the item and store the new subid at the end.
123		 */
124		btrfs_extend_item(path, sizeof(subid_le));
125		eb = path->nodes[0];
126		slot = path->slots[0];
127		offset = btrfs_item_ptr_offset(eb, slot);
128		offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
129	} else {
130		btrfs_warn(fs_info,
131			   "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!",
132			   ret, (unsigned long long)key.objectid,
133			   (unsigned long long)key.offset, type);
134		goto out;
135	}
136
137	ret = 0;
138	subid_le = cpu_to_le64(subid_cpu);
139	write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
140	btrfs_mark_buffer_dirty(eb);
141
142out:
143	btrfs_free_path(path);
144	return ret;
145}
146
147int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type,
 
148			u64 subid)
149{
150	struct btrfs_fs_info *fs_info = trans->fs_info;
151	struct btrfs_root *uuid_root = fs_info->uuid_root;
152	int ret;
153	struct btrfs_path *path = NULL;
154	struct btrfs_key key;
155	struct extent_buffer *eb;
156	int slot;
157	unsigned long offset;
158	u32 item_size;
159	unsigned long move_dst;
160	unsigned long move_src;
161	unsigned long move_len;
162
163	if (WARN_ON_ONCE(!uuid_root)) {
164		ret = -EINVAL;
165		goto out;
166	}
167
168	btrfs_uuid_to_key(uuid, type, &key);
169
170	path = btrfs_alloc_path();
171	if (!path) {
172		ret = -ENOMEM;
173		goto out;
174	}
175
176	ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
177	if (ret < 0) {
178		btrfs_warn(fs_info, "error %d while searching for uuid item!",
179			   ret);
180		goto out;
181	}
182	if (ret > 0) {
183		ret = -ENOENT;
184		goto out;
185	}
186
187	eb = path->nodes[0];
188	slot = path->slots[0];
189	offset = btrfs_item_ptr_offset(eb, slot);
190	item_size = btrfs_item_size_nr(eb, slot);
191	if (!IS_ALIGNED(item_size, sizeof(u64))) {
192		btrfs_warn(fs_info, "uuid item with illegal size %lu!",
193			   (unsigned long)item_size);
194		ret = -ENOENT;
195		goto out;
196	}
197	while (item_size) {
198		__le64 read_subid;
199
200		read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
201		if (le64_to_cpu(read_subid) == subid)
202			break;
203		offset += sizeof(read_subid);
204		item_size -= sizeof(read_subid);
205	}
206
207	if (!item_size) {
208		ret = -ENOENT;
209		goto out;
210	}
211
212	item_size = btrfs_item_size_nr(eb, slot);
213	if (item_size == sizeof(subid)) {
214		ret = btrfs_del_item(trans, uuid_root, path);
215		goto out;
216	}
217
218	move_dst = offset;
219	move_src = offset + sizeof(subid);
220	move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
221	memmove_extent_buffer(eb, move_dst, move_src, move_len);
222	btrfs_truncate_item(path, item_size - sizeof(subid), 1);
223
224out:
225	btrfs_free_path(path);
226	return ret;
227}
228
229static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
230			       u64 subid)
231{
232	struct btrfs_trans_handle *trans;
233	int ret;
234
235	/* 1 - for the uuid item */
236	trans = btrfs_start_transaction(uuid_root, 1);
237	if (IS_ERR(trans)) {
238		ret = PTR_ERR(trans);
239		goto out;
240	}
241
242	ret = btrfs_uuid_tree_remove(trans, uuid, type, subid);
243	btrfs_end_transaction(trans);
244
245out:
246	return ret;
247}
248
249int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
250			    int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
251					      u64))
252{
253	struct btrfs_root *root = fs_info->uuid_root;
254	struct btrfs_key key;
255	struct btrfs_path *path;
256	int ret = 0;
257	struct extent_buffer *leaf;
258	int slot;
259	u32 item_size;
260	unsigned long offset;
261
262	path = btrfs_alloc_path();
263	if (!path) {
264		ret = -ENOMEM;
265		goto out;
266	}
267
268	key.objectid = 0;
269	key.type = 0;
270	key.offset = 0;
271
272again_search_slot:
273	ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
274	if (ret) {
275		if (ret > 0)
276			ret = 0;
277		goto out;
278	}
279
280	while (1) {
281		cond_resched();
282		leaf = path->nodes[0];
283		slot = path->slots[0];
284		btrfs_item_key_to_cpu(leaf, &key, slot);
285
286		if (key.type != BTRFS_UUID_KEY_SUBVOL &&
287		    key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
288			goto skip;
289
290		offset = btrfs_item_ptr_offset(leaf, slot);
291		item_size = btrfs_item_size_nr(leaf, slot);
292		if (!IS_ALIGNED(item_size, sizeof(u64))) {
293			btrfs_warn(fs_info,
294				   "uuid item with illegal size %lu!",
295				   (unsigned long)item_size);
296			goto skip;
297		}
298		while (item_size) {
299			u8 uuid[BTRFS_UUID_SIZE];
300			__le64 subid_le;
301			u64 subid_cpu;
302
303			put_unaligned_le64(key.objectid, uuid);
304			put_unaligned_le64(key.offset, uuid + sizeof(u64));
305			read_extent_buffer(leaf, &subid_le, offset,
306					   sizeof(subid_le));
307			subid_cpu = le64_to_cpu(subid_le);
308			ret = check_func(fs_info, uuid, key.type, subid_cpu);
309			if (ret < 0)
310				goto out;
311			if (ret > 0) {
312				btrfs_release_path(path);
313				ret = btrfs_uuid_iter_rem(root, uuid, key.type,
314							  subid_cpu);
315				if (ret == 0) {
316					/*
317					 * this might look inefficient, but the
318					 * justification is that it is an
319					 * exception that check_func returns 1,
320					 * and that in the regular case only one
321					 * entry per UUID exists.
322					 */
323					goto again_search_slot;
324				}
325				if (ret < 0 && ret != -ENOENT)
326					goto out;
327			}
328			item_size -= sizeof(subid_le);
329			offset += sizeof(subid_le);
330		}
331
332skip:
333		ret = btrfs_next_item(root, path);
334		if (ret == 0)
335			continue;
336		else if (ret > 0)
337			ret = 0;
338		break;
339	}
340
341out:
342	btrfs_free_path(path);
343	return ret;
 
 
344}
v4.6
 
  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	ret = btrfs_search_forward(root, &key, path, 0);
283	if (ret) {
284		if (ret > 0)
285			ret = 0;
286		goto out;
287	}
288
289	while (1) {
290		cond_resched();
291		leaf = path->nodes[0];
292		slot = path->slots[0];
293		btrfs_item_key_to_cpu(leaf, &key, slot);
294
295		if (key.type != BTRFS_UUID_KEY_SUBVOL &&
296		    key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
297			goto skip;
298
299		offset = btrfs_item_ptr_offset(leaf, slot);
300		item_size = btrfs_item_size_nr(leaf, slot);
301		if (!IS_ALIGNED(item_size, sizeof(u64))) {
302			btrfs_warn(fs_info, "uuid item with illegal size %lu!",
303				(unsigned long)item_size);
 
304			goto skip;
305		}
306		while (item_size) {
307			u8 uuid[BTRFS_UUID_SIZE];
308			__le64 subid_le;
309			u64 subid_cpu;
310
311			put_unaligned_le64(key.objectid, uuid);
312			put_unaligned_le64(key.offset, uuid + sizeof(u64));
313			read_extent_buffer(leaf, &subid_le, offset,
314					   sizeof(subid_le));
315			subid_cpu = le64_to_cpu(subid_le);
316			ret = check_func(fs_info, uuid, key.type, subid_cpu);
317			if (ret < 0)
318				goto out;
319			if (ret > 0) {
320				btrfs_release_path(path);
321				ret = btrfs_uuid_iter_rem(root, uuid, key.type,
322							  subid_cpu);
323				if (ret == 0) {
324					/*
325					 * this might look inefficient, but the
326					 * justification is that it is an
327					 * exception that check_func returns 1,
328					 * and that in the regular case only one
329					 * entry per UUID exists.
330					 */
331					goto again_search_slot;
332				}
333				if (ret < 0 && ret != -ENOENT)
334					goto out;
335			}
336			item_size -= sizeof(subid_le);
337			offset += sizeof(subid_le);
338		}
339
340skip:
341		ret = btrfs_next_item(root, path);
342		if (ret == 0)
343			continue;
344		else if (ret > 0)
345			ret = 0;
346		break;
347	}
348
349out:
350	btrfs_free_path(path);
351	if (ret)
352		btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
353	return 0;
354}