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