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