brintos

brintos / linux-shallow public Read only

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