linux/fs/btrfs/props.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public
   6 * License v2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11 * General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public
  14 * License along with this program; if not, write to the
  15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16 * Boston, MA 021110-1307, USA.
  17 */
  18
  19#include <linux/hashtable.h>
  20#include "props.h"
  21#include "btrfs_inode.h"
  22#include "hash.h"
  23#include "transaction.h"
  24#include "xattr.h"
  25#include "compression.h"
  26
  27#define BTRFS_PROP_HANDLERS_HT_BITS 8
  28static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
  29
  30struct prop_handler {
  31        struct hlist_node node;
  32        const char *xattr_name;
  33        int (*validate)(const char *value, size_t len);
  34        int (*apply)(struct inode *inode, const char *value, size_t len);
  35        const char *(*extract)(struct inode *inode);
  36        int inheritable;
  37};
  38
  39static int prop_compression_validate(const char *value, size_t len);
  40static int prop_compression_apply(struct inode *inode,
  41                                  const char *value,
  42                                  size_t len);
  43static const char *prop_compression_extract(struct inode *inode);
  44
  45static struct prop_handler prop_handlers[] = {
  46        {
  47                .xattr_name = XATTR_BTRFS_PREFIX "compression",
  48                .validate = prop_compression_validate,
  49                .apply = prop_compression_apply,
  50                .extract = prop_compression_extract,
  51                .inheritable = 1
  52        },
  53};
  54
  55void __init btrfs_props_init(void)
  56{
  57        int i;
  58
  59        hash_init(prop_handlers_ht);
  60
  61        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
  62                struct prop_handler *p = &prop_handlers[i];
  63                u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
  64
  65                hash_add(prop_handlers_ht, &p->node, h);
  66        }
  67}
  68
  69static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
  70{
  71        struct hlist_head *h;
  72
  73        h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
  74        if (hlist_empty(h))
  75                return NULL;
  76
  77        return h;
  78}
  79
  80static const struct prop_handler *
  81find_prop_handler(const char *name,
  82                  const struct hlist_head *handlers)
  83{
  84        struct prop_handler *h;
  85
  86        if (!handlers) {
  87                u64 hash = btrfs_name_hash(name, strlen(name));
  88
  89                handlers = find_prop_handlers_by_hash(hash);
  90                if (!handlers)
  91                        return NULL;
  92        }
  93
  94        hlist_for_each_entry(h, handlers, node)
  95                if (!strcmp(h->xattr_name, name))
  96                        return h;
  97
  98        return NULL;
  99}
 100
 101static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
 102                            struct inode *inode,
 103                            const char *name,
 104                            const char *value,
 105                            size_t value_len,
 106                            int flags)
 107{
 108        const struct prop_handler *handler;
 109        int ret;
 110
 111        if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
 112                return -EINVAL;
 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, handler->xattr_name,
 120                                       NULL, 0, flags);
 121                if (ret)
 122                        return ret;
 123
 124                ret = handler->apply(inode, NULL, 0);
 125                ASSERT(ret == 0);
 126
 127                return ret;
 128        }
 129
 130        ret = handler->validate(value, value_len);
 131        if (ret)
 132                return ret;
 133        ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
 134                               value, value_len, flags);
 135        if (ret)
 136                return ret;
 137        ret = handler->apply(inode, value, value_len);
 138        if (ret) {
 139                __btrfs_setxattr(trans, inode, handler->xattr_name,
 140                                 NULL, 0, flags);
 141                return ret;
 142        }
 143
 144        set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 145
 146        return 0;
 147}
 148
 149int btrfs_set_prop(struct inode *inode,
 150                   const char *name,
 151                   const char *value,
 152                   size_t value_len,
 153                   int flags)
 154{
 155        return __btrfs_set_prop(NULL, inode, name, value, value_len, flags);
 156}
 157
 158static int iterate_object_props(struct btrfs_root *root,
 159                                struct btrfs_path *path,
 160                                u64 objectid,
 161                                void (*iterator)(void *,
 162                                                 const struct prop_handler *,
 163                                                 const char *,
 164                                                 size_t),
 165                                void *ctx)
 166{
 167        struct btrfs_fs_info *fs_info = root->fs_info;
 168        int ret;
 169        char *name_buf = NULL;
 170        char *value_buf = NULL;
 171        int name_buf_len = 0;
 172        int value_buf_len = 0;
 173
 174        while (1) {
 175                struct btrfs_key key;
 176                struct btrfs_dir_item *di;
 177                struct extent_buffer *leaf;
 178                u32 total_len, cur, this_len;
 179                int slot;
 180                const struct hlist_head *handlers;
 181
 182                slot = path->slots[0];
 183                leaf = path->nodes[0];
 184
 185                if (slot >= btrfs_header_nritems(leaf)) {
 186                        ret = btrfs_next_leaf(root, path);
 187                        if (ret < 0)
 188                                goto out;
 189                        else if (ret > 0)
 190                                break;
 191                        continue;
 192                }
 193
 194                btrfs_item_key_to_cpu(leaf, &key, slot);
 195                if (key.objectid != objectid)
 196                        break;
 197                if (key.type != BTRFS_XATTR_ITEM_KEY)
 198                        break;
 199
 200                handlers = find_prop_handlers_by_hash(key.offset);
 201                if (!handlers)
 202                        goto next_slot;
 203
 204                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
 205                cur = 0;
 206                total_len = btrfs_item_size_nr(leaf, slot);
 207
 208                while (cur < total_len) {
 209                        u32 name_len = btrfs_dir_name_len(leaf, di);
 210                        u32 data_len = btrfs_dir_data_len(leaf, di);
 211                        unsigned long name_ptr, data_ptr;
 212                        const struct prop_handler *handler;
 213
 214                        this_len = sizeof(*di) + name_len + data_len;
 215                        name_ptr = (unsigned long)(di + 1);
 216                        data_ptr = name_ptr + name_len;
 217
 218                        if (verify_dir_item(fs_info, leaf,
 219                                            path->slots[0], di)) {
 220                                ret = -EIO;
 221                                goto out;
 222                        }
 223
 224                        if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
 225                            memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
 226                                                 name_ptr,
 227                                                 XATTR_BTRFS_PREFIX_LEN))
 228                                goto next_dir_item;
 229
 230                        if (name_len >= name_buf_len) {
 231                                kfree(name_buf);
 232                                name_buf_len = name_len + 1;
 233                                name_buf = kmalloc(name_buf_len, GFP_NOFS);
 234                                if (!name_buf) {
 235                                        ret = -ENOMEM;
 236                                        goto out;
 237                                }
 238                        }
 239                        read_extent_buffer(leaf, name_buf, name_ptr, name_len);
 240                        name_buf[name_len] = '\0';
 241
 242                        handler = find_prop_handler(name_buf, handlers);
 243                        if (!handler)
 244                                goto next_dir_item;
 245
 246                        if (data_len > value_buf_len) {
 247                                kfree(value_buf);
 248                                value_buf_len = data_len;
 249                                value_buf = kmalloc(data_len, GFP_NOFS);
 250                                if (!value_buf) {
 251                                        ret = -ENOMEM;
 252                                        goto out;
 253                                }
 254                        }
 255                        read_extent_buffer(leaf, value_buf, data_ptr, data_len);
 256
 257                        iterator(ctx, handler, value_buf, data_len);
 258next_dir_item:
 259                        cur += this_len;
 260                        di = (struct btrfs_dir_item *)((char *) di + this_len);
 261                }
 262
 263next_slot:
 264                path->slots[0]++;
 265        }
 266
 267        ret = 0;
 268out:
 269        btrfs_release_path(path);
 270        kfree(name_buf);
 271        kfree(value_buf);
 272
 273        return ret;
 274}
 275
 276static void inode_prop_iterator(void *ctx,
 277                                const struct prop_handler *handler,
 278                                const char *value,
 279                                size_t len)
 280{
 281        struct inode *inode = ctx;
 282        struct btrfs_root *root = BTRFS_I(inode)->root;
 283        int ret;
 284
 285        ret = handler->apply(inode, value, len);
 286        if (unlikely(ret))
 287                btrfs_warn(root->fs_info,
 288                           "error applying prop %s to ino %llu (root %llu): %d",
 289                           handler->xattr_name, btrfs_ino(BTRFS_I(inode)),
 290                           root->root_key.objectid, ret);
 291        else
 292                set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 293}
 294
 295int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
 296{
 297        struct btrfs_root *root = BTRFS_I(inode)->root;
 298        u64 ino = btrfs_ino(BTRFS_I(inode));
 299        int ret;
 300
 301        ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
 302
 303        return ret;
 304}
 305
 306static int inherit_props(struct btrfs_trans_handle *trans,
 307                         struct inode *inode,
 308                         struct inode *parent)
 309{
 310        struct btrfs_root *root = BTRFS_I(inode)->root;
 311        struct btrfs_fs_info *fs_info = root->fs_info;
 312        int ret;
 313        int i;
 314
 315        if (!test_bit(BTRFS_INODE_HAS_PROPS,
 316                      &BTRFS_I(parent)->runtime_flags))
 317                return 0;
 318
 319        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
 320                const struct prop_handler *h = &prop_handlers[i];
 321                const char *value;
 322                u64 num_bytes;
 323
 324                if (!h->inheritable)
 325                        continue;
 326
 327                value = h->extract(parent);
 328                if (!value)
 329                        continue;
 330
 331                num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
 332                ret = btrfs_block_rsv_add(root, trans->block_rsv,
 333                                          num_bytes, BTRFS_RESERVE_NO_FLUSH);
 334                if (ret)
 335                        goto out;
 336                ret = __btrfs_set_prop(trans, inode, h->xattr_name,
 337                                       value, strlen(value), 0);
 338                btrfs_block_rsv_release(fs_info, trans->block_rsv, num_bytes);
 339                if (ret)
 340                        goto out;
 341        }
 342        ret = 0;
 343out:
 344        return ret;
 345}
 346
 347int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
 348                              struct inode *inode,
 349                              struct inode *dir)
 350{
 351        if (!dir)
 352                return 0;
 353
 354        return inherit_props(trans, inode, dir);
 355}
 356
 357int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
 358                               struct btrfs_root *root,
 359                               struct btrfs_root *parent_root)
 360{
 361        struct super_block *sb = root->fs_info->sb;
 362        struct btrfs_key key;
 363        struct inode *parent_inode, *child_inode;
 364        int ret;
 365
 366        key.objectid = BTRFS_FIRST_FREE_OBJECTID;
 367        key.type = BTRFS_INODE_ITEM_KEY;
 368        key.offset = 0;
 369
 370        parent_inode = btrfs_iget(sb, &key, parent_root, NULL);
 371        if (IS_ERR(parent_inode))
 372                return PTR_ERR(parent_inode);
 373
 374        child_inode = btrfs_iget(sb, &key, root, NULL);
 375        if (IS_ERR(child_inode)) {
 376                iput(parent_inode);
 377                return PTR_ERR(child_inode);
 378        }
 379
 380        ret = inherit_props(trans, child_inode, parent_inode);
 381        iput(child_inode);
 382        iput(parent_inode);
 383
 384        return ret;
 385}
 386
 387static int prop_compression_validate(const char *value, size_t len)
 388{
 389        if (!strncmp("lzo", value, len))
 390                return 0;
 391        else if (!strncmp("zlib", value, len))
 392                return 0;
 393        else if (!strncmp("zstd", value, len))
 394                return 0;
 395
 396        return -EINVAL;
 397}
 398
 399static int prop_compression_apply(struct inode *inode,
 400                                  const char *value,
 401                                  size_t len)
 402{
 403        int type;
 404
 405        if (len == 0) {
 406                BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
 407                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
 408                BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
 409
 410                return 0;
 411        }
 412
 413        if (!strncmp("lzo", value, 3))
 414                type = BTRFS_COMPRESS_LZO;
 415        else if (!strncmp("zlib", value, 4))
 416                type = BTRFS_COMPRESS_ZLIB;
 417        else if (!strncmp("zstd", value, len))
 418                type = BTRFS_COMPRESS_ZSTD;
 419        else
 420                return -EINVAL;
 421
 422        BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
 423        BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
 424        BTRFS_I(inode)->prop_compress = type;
 425
 426        return 0;
 427}
 428
 429static const char *prop_compression_extract(struct inode *inode)
 430{
 431        switch (BTRFS_I(inode)->prop_compress) {
 432        case BTRFS_COMPRESS_ZLIB:
 433                return "zlib";
 434        case BTRFS_COMPRESS_LZO:
 435                return "lzo";
 436        case BTRFS_COMPRESS_ZSTD:
 437                return "zstd";
 438        }
 439
 440        return NULL;
 441}
 442
 443
 444