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        if ((len == 2 && strncmp("no", value, 2) == 0) ||
 264            (len == 4 && strncmp("none", value, 4) == 0))
 265                return 0;
 266
 267        return -EINVAL;
 268}
 269
 270static int prop_compression_apply(struct inode *inode, const char *value,
 271                                  size_t len)
 272{
 273        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 274        int type;
 275
 276        /* Reset to defaults */
 277        if (len == 0) {
 278                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
 279                BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
 280                BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
 281                return 0;
 282        }
 283
 284        /* Set NOCOMPRESS flag */
 285        if ((len == 2 && strncmp("no", value, 2) == 0) ||
 286            (len == 4 && strncmp("none", value, 4) == 0)) {
 287                BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
 288                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
 289                BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
 290
 291                return 0;
 292        }
 293
 294        if (!strncmp("lzo", value, 3)) {
 295                type = BTRFS_COMPRESS_LZO;
 296                btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
 297        } else if (!strncmp("zlib", value, 4)) {
 298                type = BTRFS_COMPRESS_ZLIB;
 299        } else if (!strncmp("zstd", value, 4)) {
 300                type = BTRFS_COMPRESS_ZSTD;
 301                btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
 302        } else {
 303                return -EINVAL;
 304        }
 305
 306        BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
 307        BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
 308        BTRFS_I(inode)->prop_compress = type;
 309
 310        return 0;
 311}
 312
 313static const char *prop_compression_extract(struct inode *inode)
 314{
 315        switch (BTRFS_I(inode)->prop_compress) {
 316        case BTRFS_COMPRESS_ZLIB:
 317        case BTRFS_COMPRESS_LZO:
 318        case BTRFS_COMPRESS_ZSTD:
 319                return btrfs_compress_type2str(BTRFS_I(inode)->prop_compress);
 320        default:
 321                break;
 322        }
 323
 324        return NULL;
 325}
 326
 327static struct prop_handler prop_handlers[] = {
 328        {
 329                .xattr_name = XATTR_BTRFS_PREFIX "compression",
 330                .validate = prop_compression_validate,
 331                .apply = prop_compression_apply,
 332                .extract = prop_compression_extract,
 333                .inheritable = 1
 334        },
 335};
 336
 337static int inherit_props(struct btrfs_trans_handle *trans,
 338                         struct inode *inode,
 339                         struct inode *parent)
 340{
 341        struct btrfs_root *root = BTRFS_I(inode)->root;
 342        struct btrfs_fs_info *fs_info = root->fs_info;
 343        int ret;
 344        int i;
 345        bool need_reserve = false;
 346
 347        if (!test_bit(BTRFS_INODE_HAS_PROPS,
 348                      &BTRFS_I(parent)->runtime_flags))
 349                return 0;
 350
 351        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
 352                const struct prop_handler *h = &prop_handlers[i];
 353                const char *value;
 354                u64 num_bytes = 0;
 355
 356                if (!h->inheritable)
 357                        continue;
 358
 359                value = h->extract(parent);
 360                if (!value)
 361                        continue;
 362
 363                /*
 364                 * This is not strictly necessary as the property should be
 365                 * valid, but in case it isn't, don't propagate it further.
 366                 */
 367                ret = h->validate(value, strlen(value));
 368                if (ret)
 369                        continue;
 370
 371                /*
 372                 * Currently callers should be reserving 1 item for properties,
 373                 * since we only have 1 property that we currently support.  If
 374                 * we add more in the future we need to try and reserve more
 375                 * space for them.  But we should also revisit how we do space
 376                 * reservations if we do add more properties in the future.
 377                 */
 378                if (need_reserve) {
 379                        num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
 380                        ret = btrfs_block_rsv_add(root, trans->block_rsv,
 381                                        num_bytes, BTRFS_RESERVE_NO_FLUSH);
 382                        if (ret)
 383                                return ret;
 384                }
 385
 386                ret = btrfs_setxattr(trans, inode, h->xattr_name, value,
 387                                     strlen(value), 0);
 388                if (!ret) {
 389                        ret = h->apply(inode, value, strlen(value));
 390                        if (ret)
 391                                btrfs_setxattr(trans, inode, h->xattr_name,
 392                                               NULL, 0, 0);
 393                        else
 394                                set_bit(BTRFS_INODE_HAS_PROPS,
 395                                        &BTRFS_I(inode)->runtime_flags);
 396                }
 397
 398                if (need_reserve) {
 399                        btrfs_block_rsv_release(fs_info, trans->block_rsv,
 400                                        num_bytes, NULL);
 401                        if (ret)
 402                                return ret;
 403                }
 404                need_reserve = true;
 405        }
 406
 407        return 0;
 408}
 409
 410int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
 411                              struct inode *inode,
 412                              struct inode *dir)
 413{
 414        if (!dir)
 415                return 0;
 416
 417        return inherit_props(trans, inode, dir);
 418}
 419
 420int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
 421                               struct btrfs_root *root,
 422                               struct btrfs_root *parent_root)
 423{
 424        struct super_block *sb = root->fs_info->sb;
 425        struct inode *parent_inode, *child_inode;
 426        int ret;
 427
 428        parent_inode = btrfs_iget(sb, BTRFS_FIRST_FREE_OBJECTID, parent_root);
 429        if (IS_ERR(parent_inode))
 430                return PTR_ERR(parent_inode);
 431
 432        child_inode = btrfs_iget(sb, BTRFS_FIRST_FREE_OBJECTID, root);
 433        if (IS_ERR(child_inode)) {
 434                iput(parent_inode);
 435                return PTR_ERR(child_inode);
 436        }
 437
 438        ret = inherit_props(trans, child_inode, parent_inode);
 439        iput(child_inode);
 440        iput(parent_inode);
 441
 442        return ret;
 443}
 444
 445void __init btrfs_props_init(void)
 446{
 447        int i;
 448
 449        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
 450                struct prop_handler *p = &prop_handlers[i];
 451                u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
 452
 453                hash_add(prop_handlers_ht, &p->node, h);
 454        }
 455}
 456
 457