cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

props.c (11340B)


      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
     15static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
     16
     17struct prop_handler {
     18	struct hlist_node node;
     19	const char *xattr_name;
     20	int (*validate)(const struct btrfs_inode *inode, const char *value,
     21			size_t len);
     22	int (*apply)(struct inode *inode, const char *value, size_t len);
     23	const char *(*extract)(struct inode *inode);
     24	bool (*ignore)(const struct btrfs_inode *inode);
     25	int inheritable;
     26};
     27
     28static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
     29{
     30	struct hlist_head *h;
     31
     32	h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
     33	if (hlist_empty(h))
     34		return NULL;
     35
     36	return h;
     37}
     38
     39static const struct prop_handler *
     40find_prop_handler(const char *name,
     41		  const struct hlist_head *handlers)
     42{
     43	struct prop_handler *h;
     44
     45	if (!handlers) {
     46		u64 hash = btrfs_name_hash(name, strlen(name));
     47
     48		handlers = find_prop_handlers_by_hash(hash);
     49		if (!handlers)
     50			return NULL;
     51	}
     52
     53	hlist_for_each_entry(h, handlers, node)
     54		if (!strcmp(h->xattr_name, name))
     55			return h;
     56
     57	return NULL;
     58}
     59
     60int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name,
     61			const char *value, size_t value_len)
     62{
     63	const struct prop_handler *handler;
     64
     65	if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
     66		return -EINVAL;
     67
     68	handler = find_prop_handler(name, NULL);
     69	if (!handler)
     70		return -EINVAL;
     71
     72	if (value_len == 0)
     73		return 0;
     74
     75	return handler->validate(inode, value, value_len);
     76}
     77
     78/*
     79 * Check if a property should be ignored (not set) for an inode.
     80 *
     81 * @inode:     The target inode.
     82 * @name:      The property's name.
     83 *
     84 * The caller must be sure the given property name is valid, for example by
     85 * having previously called btrfs_validate_prop().
     86 *
     87 * Returns:    true if the property should be ignored for the given inode
     88 *             false if the property must not be ignored for the given inode
     89 */
     90bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name)
     91{
     92	const struct prop_handler *handler;
     93
     94	handler = find_prop_handler(name, NULL);
     95	ASSERT(handler != NULL);
     96
     97	return handler->ignore(inode);
     98}
     99
    100int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
    101		   const char *name, const char *value, size_t value_len,
    102		   int flags)
    103{
    104	const struct prop_handler *handler;
    105	int ret;
    106
    107	handler = find_prop_handler(name, NULL);
    108	if (!handler)
    109		return -EINVAL;
    110
    111	if (value_len == 0) {
    112		ret = btrfs_setxattr(trans, inode, handler->xattr_name,
    113				     NULL, 0, flags);
    114		if (ret)
    115			return ret;
    116
    117		ret = handler->apply(inode, NULL, 0);
    118		ASSERT(ret == 0);
    119
    120		return ret;
    121	}
    122
    123	ret = btrfs_setxattr(trans, inode, handler->xattr_name, value,
    124			     value_len, flags);
    125	if (ret)
    126		return ret;
    127	ret = handler->apply(inode, value, value_len);
    128	if (ret) {
    129		btrfs_setxattr(trans, inode, handler->xattr_name, NULL,
    130			       0, flags);
    131		return ret;
    132	}
    133
    134	set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
    135
    136	return 0;
    137}
    138
    139static int iterate_object_props(struct btrfs_root *root,
    140				struct btrfs_path *path,
    141				u64 objectid,
    142				void (*iterator)(void *,
    143						 const struct prop_handler *,
    144						 const char *,
    145						 size_t),
    146				void *ctx)
    147{
    148	int ret;
    149	char *name_buf = NULL;
    150	char *value_buf = NULL;
    151	int name_buf_len = 0;
    152	int value_buf_len = 0;
    153
    154	while (1) {
    155		struct btrfs_key key;
    156		struct btrfs_dir_item *di;
    157		struct extent_buffer *leaf;
    158		u32 total_len, cur, this_len;
    159		int slot;
    160		const struct hlist_head *handlers;
    161
    162		slot = path->slots[0];
    163		leaf = path->nodes[0];
    164
    165		if (slot >= btrfs_header_nritems(leaf)) {
    166			ret = btrfs_next_leaf(root, path);
    167			if (ret < 0)
    168				goto out;
    169			else if (ret > 0)
    170				break;
    171			continue;
    172		}
    173
    174		btrfs_item_key_to_cpu(leaf, &key, slot);
    175		if (key.objectid != objectid)
    176			break;
    177		if (key.type != BTRFS_XATTR_ITEM_KEY)
    178			break;
    179
    180		handlers = find_prop_handlers_by_hash(key.offset);
    181		if (!handlers)
    182			goto next_slot;
    183
    184		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
    185		cur = 0;
    186		total_len = btrfs_item_size(leaf, slot);
    187
    188		while (cur < total_len) {
    189			u32 name_len = btrfs_dir_name_len(leaf, di);
    190			u32 data_len = btrfs_dir_data_len(leaf, di);
    191			unsigned long name_ptr, data_ptr;
    192			const struct prop_handler *handler;
    193
    194			this_len = sizeof(*di) + name_len + data_len;
    195			name_ptr = (unsigned long)(di + 1);
    196			data_ptr = name_ptr + name_len;
    197
    198			if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
    199			    memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
    200						 name_ptr,
    201						 XATTR_BTRFS_PREFIX_LEN))
    202				goto next_dir_item;
    203
    204			if (name_len >= name_buf_len) {
    205				kfree(name_buf);
    206				name_buf_len = name_len + 1;
    207				name_buf = kmalloc(name_buf_len, GFP_NOFS);
    208				if (!name_buf) {
    209					ret = -ENOMEM;
    210					goto out;
    211				}
    212			}
    213			read_extent_buffer(leaf, name_buf, name_ptr, name_len);
    214			name_buf[name_len] = '\0';
    215
    216			handler = find_prop_handler(name_buf, handlers);
    217			if (!handler)
    218				goto next_dir_item;
    219
    220			if (data_len > value_buf_len) {
    221				kfree(value_buf);
    222				value_buf_len = data_len;
    223				value_buf = kmalloc(data_len, GFP_NOFS);
    224				if (!value_buf) {
    225					ret = -ENOMEM;
    226					goto out;
    227				}
    228			}
    229			read_extent_buffer(leaf, value_buf, data_ptr, data_len);
    230
    231			iterator(ctx, handler, value_buf, data_len);
    232next_dir_item:
    233			cur += this_len;
    234			di = (struct btrfs_dir_item *)((char *) di + this_len);
    235		}
    236
    237next_slot:
    238		path->slots[0]++;
    239	}
    240
    241	ret = 0;
    242out:
    243	btrfs_release_path(path);
    244	kfree(name_buf);
    245	kfree(value_buf);
    246
    247	return ret;
    248}
    249
    250static void inode_prop_iterator(void *ctx,
    251				const struct prop_handler *handler,
    252				const char *value,
    253				size_t len)
    254{
    255	struct inode *inode = ctx;
    256	struct btrfs_root *root = BTRFS_I(inode)->root;
    257	int ret;
    258
    259	ret = handler->apply(inode, value, len);
    260	if (unlikely(ret))
    261		btrfs_warn(root->fs_info,
    262			   "error applying prop %s to ino %llu (root %llu): %d",
    263			   handler->xattr_name, btrfs_ino(BTRFS_I(inode)),
    264			   root->root_key.objectid, ret);
    265	else
    266		set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
    267}
    268
    269int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
    270{
    271	struct btrfs_root *root = BTRFS_I(inode)->root;
    272	u64 ino = btrfs_ino(BTRFS_I(inode));
    273	int ret;
    274
    275	ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
    276
    277	return ret;
    278}
    279
    280static int prop_compression_validate(const struct btrfs_inode *inode,
    281				     const char *value, size_t len)
    282{
    283	if (!btrfs_inode_can_compress(inode))
    284		return -EINVAL;
    285
    286	if (!value)
    287		return 0;
    288
    289	if (btrfs_compress_is_valid_type(value, len))
    290		return 0;
    291
    292	if ((len == 2 && strncmp("no", value, 2) == 0) ||
    293	    (len == 4 && strncmp("none", value, 4) == 0))
    294		return 0;
    295
    296	return -EINVAL;
    297}
    298
    299static int prop_compression_apply(struct inode *inode, const char *value,
    300				  size_t len)
    301{
    302	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
    303	int type;
    304
    305	/* Reset to defaults */
    306	if (len == 0) {
    307		BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
    308		BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
    309		BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
    310		return 0;
    311	}
    312
    313	/* Set NOCOMPRESS flag */
    314	if ((len == 2 && strncmp("no", value, 2) == 0) ||
    315	    (len == 4 && strncmp("none", value, 4) == 0)) {
    316		BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
    317		BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
    318		BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
    319
    320		return 0;
    321	}
    322
    323	if (!strncmp("lzo", value, 3)) {
    324		type = BTRFS_COMPRESS_LZO;
    325		btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
    326	} else if (!strncmp("zlib", value, 4)) {
    327		type = BTRFS_COMPRESS_ZLIB;
    328	} else if (!strncmp("zstd", value, 4)) {
    329		type = BTRFS_COMPRESS_ZSTD;
    330		btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
    331	} else {
    332		return -EINVAL;
    333	}
    334
    335	BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
    336	BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
    337	BTRFS_I(inode)->prop_compress = type;
    338
    339	return 0;
    340}
    341
    342static bool prop_compression_ignore(const struct btrfs_inode *inode)
    343{
    344	/*
    345	 * Compression only has effect for regular files, and for directories
    346	 * we set it just to propagate it to new files created inside them.
    347	 * Everything else (symlinks, devices, sockets, fifos) is pointless as
    348	 * it will do nothing, so don't waste metadata space on a compression
    349	 * xattr for anything that is neither a file nor a directory.
    350	 */
    351	if (!S_ISREG(inode->vfs_inode.i_mode) &&
    352	    !S_ISDIR(inode->vfs_inode.i_mode))
    353		return true;
    354
    355	return false;
    356}
    357
    358static const char *prop_compression_extract(struct inode *inode)
    359{
    360	switch (BTRFS_I(inode)->prop_compress) {
    361	case BTRFS_COMPRESS_ZLIB:
    362	case BTRFS_COMPRESS_LZO:
    363	case BTRFS_COMPRESS_ZSTD:
    364		return btrfs_compress_type2str(BTRFS_I(inode)->prop_compress);
    365	default:
    366		break;
    367	}
    368
    369	return NULL;
    370}
    371
    372static struct prop_handler prop_handlers[] = {
    373	{
    374		.xattr_name = XATTR_BTRFS_PREFIX "compression",
    375		.validate = prop_compression_validate,
    376		.apply = prop_compression_apply,
    377		.extract = prop_compression_extract,
    378		.ignore = prop_compression_ignore,
    379		.inheritable = 1
    380	},
    381};
    382
    383int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
    384			      struct inode *inode, struct inode *parent)
    385{
    386	struct btrfs_root *root = BTRFS_I(inode)->root;
    387	struct btrfs_fs_info *fs_info = root->fs_info;
    388	int ret;
    389	int i;
    390	bool need_reserve = false;
    391
    392	if (!test_bit(BTRFS_INODE_HAS_PROPS,
    393		      &BTRFS_I(parent)->runtime_flags))
    394		return 0;
    395
    396	for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
    397		const struct prop_handler *h = &prop_handlers[i];
    398		const char *value;
    399		u64 num_bytes = 0;
    400
    401		if (!h->inheritable)
    402			continue;
    403
    404		if (h->ignore(BTRFS_I(inode)))
    405			continue;
    406
    407		value = h->extract(parent);
    408		if (!value)
    409			continue;
    410
    411		/*
    412		 * This is not strictly necessary as the property should be
    413		 * valid, but in case it isn't, don't propagate it further.
    414		 */
    415		ret = h->validate(BTRFS_I(inode), value, strlen(value));
    416		if (ret)
    417			continue;
    418
    419		/*
    420		 * Currently callers should be reserving 1 item for properties,
    421		 * since we only have 1 property that we currently support.  If
    422		 * we add more in the future we need to try and reserve more
    423		 * space for them.  But we should also revisit how we do space
    424		 * reservations if we do add more properties in the future.
    425		 */
    426		if (need_reserve) {
    427			num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
    428			ret = btrfs_block_rsv_add(fs_info, trans->block_rsv,
    429						  num_bytes,
    430						  BTRFS_RESERVE_NO_FLUSH);
    431			if (ret)
    432				return ret;
    433		}
    434
    435		ret = btrfs_setxattr(trans, inode, h->xattr_name, value,
    436				     strlen(value), 0);
    437		if (!ret) {
    438			ret = h->apply(inode, value, strlen(value));
    439			if (ret)
    440				btrfs_setxattr(trans, inode, h->xattr_name,
    441					       NULL, 0, 0);
    442			else
    443				set_bit(BTRFS_INODE_HAS_PROPS,
    444					&BTRFS_I(inode)->runtime_flags);
    445		}
    446
    447		if (need_reserve) {
    448			btrfs_block_rsv_release(fs_info, trans->block_rsv,
    449					num_bytes, NULL);
    450			if (ret)
    451				return ret;
    452		}
    453		need_reserve = true;
    454	}
    455
    456	return 0;
    457}
    458
    459void __init btrfs_props_init(void)
    460{
    461	int i;
    462
    463	for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
    464		struct prop_handler *p = &prop_handlers[i];
    465		u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
    466
    467		hash_add(prop_handlers_ht, &p->node, h);
    468	}
    469}
    470