xref: /openbmc/linux/fs/btrfs/props.c (revision e6e8c82b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
4  */
5 
6 #include <linux/hashtable.h>
7 #include "props.h"
8 #include "btrfs_inode.h"
9 #include "transaction.h"
10 #include "ctree.h"
11 #include "xattr.h"
12 #include "compression.h"
13 
14 #define BTRFS_PROP_HANDLERS_HT_BITS 8
15 static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
16 
17 struct prop_handler {
18 	struct hlist_node node;
19 	const char *xattr_name;
20 	int (*validate)(const char *value, size_t len);
21 	int (*apply)(struct inode *inode, const char *value, size_t len);
22 	const char *(*extract)(struct inode *inode);
23 	int inheritable;
24 };
25 
26 static int prop_compression_validate(const char *value, size_t len);
27 static int prop_compression_apply(struct inode *inode,
28 				  const char *value,
29 				  size_t len);
30 static const char *prop_compression_extract(struct inode *inode);
31 
32 static struct prop_handler prop_handlers[] = {
33 	{
34 		.xattr_name = XATTR_BTRFS_PREFIX "compression",
35 		.validate = prop_compression_validate,
36 		.apply = prop_compression_apply,
37 		.extract = prop_compression_extract,
38 		.inheritable = 1
39 	},
40 };
41 
42 void __init btrfs_props_init(void)
43 {
44 	int i;
45 
46 	hash_init(prop_handlers_ht);
47 
48 	for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
49 		struct prop_handler *p = &prop_handlers[i];
50 		u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
51 
52 		hash_add(prop_handlers_ht, &p->node, h);
53 	}
54 }
55 
56 static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
57 {
58 	struct hlist_head *h;
59 
60 	h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
61 	if (hlist_empty(h))
62 		return NULL;
63 
64 	return h;
65 }
66 
67 static const struct prop_handler *
68 find_prop_handler(const char *name,
69 		  const struct hlist_head *handlers)
70 {
71 	struct prop_handler *h;
72 
73 	if (!handlers) {
74 		u64 hash = btrfs_name_hash(name, strlen(name));
75 
76 		handlers = find_prop_handlers_by_hash(hash);
77 		if (!handlers)
78 			return NULL;
79 	}
80 
81 	hlist_for_each_entry(h, handlers, node)
82 		if (!strcmp(h->xattr_name, name))
83 			return h;
84 
85 	return NULL;
86 }
87 
88 static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
89 			    struct inode *inode,
90 			    const char *name,
91 			    const char *value,
92 			    size_t value_len,
93 			    int flags)
94 {
95 	const struct prop_handler *handler;
96 	int ret;
97 
98 	if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
99 		return -EINVAL;
100 
101 	handler = find_prop_handler(name, NULL);
102 	if (!handler)
103 		return -EINVAL;
104 
105 	if (value_len == 0) {
106 		ret = btrfs_setxattr(trans, inode, handler->xattr_name,
107 				       NULL, 0, flags);
108 		if (ret)
109 			return ret;
110 
111 		ret = handler->apply(inode, NULL, 0);
112 		ASSERT(ret == 0);
113 
114 		return ret;
115 	}
116 
117 	ret = handler->validate(value, value_len);
118 	if (ret)
119 		return ret;
120 	ret = btrfs_setxattr(trans, inode, handler->xattr_name,
121 			       value, value_len, flags);
122 	if (ret)
123 		return ret;
124 	ret = handler->apply(inode, value, value_len);
125 	if (ret) {
126 		btrfs_setxattr(trans, inode, handler->xattr_name,
127 				 NULL, 0, flags);
128 		return ret;
129 	}
130 
131 	set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
132 
133 	return 0;
134 }
135 
136 int btrfs_set_prop(struct inode *inode,
137 		   const char *name,
138 		   const char *value,
139 		   size_t value_len,
140 		   int flags)
141 {
142 	return __btrfs_set_prop(NULL, inode, name, value, value_len, flags);
143 }
144 
145 static int iterate_object_props(struct btrfs_root *root,
146 				struct btrfs_path *path,
147 				u64 objectid,
148 				void (*iterator)(void *,
149 						 const struct prop_handler *,
150 						 const char *,
151 						 size_t),
152 				void *ctx)
153 {
154 	int ret;
155 	char *name_buf = NULL;
156 	char *value_buf = NULL;
157 	int name_buf_len = 0;
158 	int value_buf_len = 0;
159 
160 	while (1) {
161 		struct btrfs_key key;
162 		struct btrfs_dir_item *di;
163 		struct extent_buffer *leaf;
164 		u32 total_len, cur, this_len;
165 		int slot;
166 		const struct hlist_head *handlers;
167 
168 		slot = path->slots[0];
169 		leaf = path->nodes[0];
170 
171 		if (slot >= btrfs_header_nritems(leaf)) {
172 			ret = btrfs_next_leaf(root, path);
173 			if (ret < 0)
174 				goto out;
175 			else if (ret > 0)
176 				break;
177 			continue;
178 		}
179 
180 		btrfs_item_key_to_cpu(leaf, &key, slot);
181 		if (key.objectid != objectid)
182 			break;
183 		if (key.type != BTRFS_XATTR_ITEM_KEY)
184 			break;
185 
186 		handlers = find_prop_handlers_by_hash(key.offset);
187 		if (!handlers)
188 			goto next_slot;
189 
190 		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
191 		cur = 0;
192 		total_len = btrfs_item_size_nr(leaf, slot);
193 
194 		while (cur < total_len) {
195 			u32 name_len = btrfs_dir_name_len(leaf, di);
196 			u32 data_len = btrfs_dir_data_len(leaf, di);
197 			unsigned long name_ptr, data_ptr;
198 			const struct prop_handler *handler;
199 
200 			this_len = sizeof(*di) + name_len + data_len;
201 			name_ptr = (unsigned long)(di + 1);
202 			data_ptr = name_ptr + name_len;
203 
204 			if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
205 			    memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
206 						 name_ptr,
207 						 XATTR_BTRFS_PREFIX_LEN))
208 				goto next_dir_item;
209 
210 			if (name_len >= name_buf_len) {
211 				kfree(name_buf);
212 				name_buf_len = name_len + 1;
213 				name_buf = kmalloc(name_buf_len, GFP_NOFS);
214 				if (!name_buf) {
215 					ret = -ENOMEM;
216 					goto out;
217 				}
218 			}
219 			read_extent_buffer(leaf, name_buf, name_ptr, name_len);
220 			name_buf[name_len] = '\0';
221 
222 			handler = find_prop_handler(name_buf, handlers);
223 			if (!handler)
224 				goto next_dir_item;
225 
226 			if (data_len > value_buf_len) {
227 				kfree(value_buf);
228 				value_buf_len = data_len;
229 				value_buf = kmalloc(data_len, GFP_NOFS);
230 				if (!value_buf) {
231 					ret = -ENOMEM;
232 					goto out;
233 				}
234 			}
235 			read_extent_buffer(leaf, value_buf, data_ptr, data_len);
236 
237 			iterator(ctx, handler, value_buf, data_len);
238 next_dir_item:
239 			cur += this_len;
240 			di = (struct btrfs_dir_item *)((char *) di + this_len);
241 		}
242 
243 next_slot:
244 		path->slots[0]++;
245 	}
246 
247 	ret = 0;
248 out:
249 	btrfs_release_path(path);
250 	kfree(name_buf);
251 	kfree(value_buf);
252 
253 	return ret;
254 }
255 
256 static void inode_prop_iterator(void *ctx,
257 				const struct prop_handler *handler,
258 				const char *value,
259 				size_t len)
260 {
261 	struct inode *inode = ctx;
262 	struct btrfs_root *root = BTRFS_I(inode)->root;
263 	int ret;
264 
265 	ret = handler->apply(inode, value, len);
266 	if (unlikely(ret))
267 		btrfs_warn(root->fs_info,
268 			   "error applying prop %s to ino %llu (root %llu): %d",
269 			   handler->xattr_name, btrfs_ino(BTRFS_I(inode)),
270 			   root->root_key.objectid, ret);
271 	else
272 		set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
273 }
274 
275 int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
276 {
277 	struct btrfs_root *root = BTRFS_I(inode)->root;
278 	u64 ino = btrfs_ino(BTRFS_I(inode));
279 	int ret;
280 
281 	ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
282 
283 	return ret;
284 }
285 
286 static int inherit_props(struct btrfs_trans_handle *trans,
287 			 struct inode *inode,
288 			 struct inode *parent)
289 {
290 	struct btrfs_root *root = BTRFS_I(inode)->root;
291 	struct btrfs_fs_info *fs_info = root->fs_info;
292 	int ret;
293 	int i;
294 
295 	if (!test_bit(BTRFS_INODE_HAS_PROPS,
296 		      &BTRFS_I(parent)->runtime_flags))
297 		return 0;
298 
299 	for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
300 		const struct prop_handler *h = &prop_handlers[i];
301 		const char *value;
302 		u64 num_bytes;
303 
304 		if (!h->inheritable)
305 			continue;
306 
307 		value = h->extract(parent);
308 		if (!value)
309 			continue;
310 
311 		num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
312 		ret = btrfs_block_rsv_add(root, trans->block_rsv,
313 					  num_bytes, BTRFS_RESERVE_NO_FLUSH);
314 		if (ret)
315 			goto out;
316 		ret = __btrfs_set_prop(trans, inode, h->xattr_name,
317 				       value, strlen(value), 0);
318 		btrfs_block_rsv_release(fs_info, trans->block_rsv, num_bytes);
319 		if (ret)
320 			goto out;
321 	}
322 	ret = 0;
323 out:
324 	return ret;
325 }
326 
327 int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
328 			      struct inode *inode,
329 			      struct inode *dir)
330 {
331 	if (!dir)
332 		return 0;
333 
334 	return inherit_props(trans, inode, dir);
335 }
336 
337 int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
338 			       struct btrfs_root *root,
339 			       struct btrfs_root *parent_root)
340 {
341 	struct super_block *sb = root->fs_info->sb;
342 	struct btrfs_key key;
343 	struct inode *parent_inode, *child_inode;
344 	int ret;
345 
346 	key.objectid = BTRFS_FIRST_FREE_OBJECTID;
347 	key.type = BTRFS_INODE_ITEM_KEY;
348 	key.offset = 0;
349 
350 	parent_inode = btrfs_iget(sb, &key, parent_root, NULL);
351 	if (IS_ERR(parent_inode))
352 		return PTR_ERR(parent_inode);
353 
354 	child_inode = btrfs_iget(sb, &key, root, NULL);
355 	if (IS_ERR(child_inode)) {
356 		iput(parent_inode);
357 		return PTR_ERR(child_inode);
358 	}
359 
360 	ret = inherit_props(trans, child_inode, parent_inode);
361 	iput(child_inode);
362 	iput(parent_inode);
363 
364 	return ret;
365 }
366 
367 static int prop_compression_validate(const char *value, size_t len)
368 {
369 	if (!strncmp("lzo", value, len))
370 		return 0;
371 	else if (!strncmp("zlib", value, len))
372 		return 0;
373 	else if (!strncmp("zstd", value, len))
374 		return 0;
375 
376 	return -EINVAL;
377 }
378 
379 static int prop_compression_apply(struct inode *inode,
380 				  const char *value,
381 				  size_t len)
382 {
383 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
384 	int type;
385 
386 	if (len == 0) {
387 		BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
388 		BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
389 		BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
390 
391 		return 0;
392 	}
393 
394 	if (!strncmp("lzo", value, 3)) {
395 		type = BTRFS_COMPRESS_LZO;
396 		btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
397 	} else if (!strncmp("zlib", value, 4)) {
398 		type = BTRFS_COMPRESS_ZLIB;
399 	} else if (!strncmp("zstd", value, len)) {
400 		type = BTRFS_COMPRESS_ZSTD;
401 		btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
402 	} else {
403 		return -EINVAL;
404 	}
405 
406 	BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
407 	BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
408 	BTRFS_I(inode)->prop_compress = type;
409 
410 	return 0;
411 }
412 
413 static const char *prop_compression_extract(struct inode *inode)
414 {
415 	switch (BTRFS_I(inode)->prop_compress) {
416 	case BTRFS_COMPRESS_ZLIB:
417 	case BTRFS_COMPRESS_LZO:
418 	case BTRFS_COMPRESS_ZSTD:
419 		return btrfs_compress_type2str(BTRFS_I(inode)->prop_compress);
420 	default:
421 		break;
422 	}
423 
424 	return NULL;
425 }
426 
427 
428