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