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        int ret;
 168        char *name_buf = NULL;
 169        char *value_buf = NULL;
 170        int name_buf_len = 0;
 171        int value_buf_len = 0;
 172
 173        while (1) {
 174                struct btrfs_key key;
 175                struct btrfs_dir_item *di;
 176                struct extent_buffer *leaf;
 177                u32 total_len, cur, this_len;
 178                int slot;
 179                const struct hlist_head *handlers;
 180
 181                slot = path->slots[0];
 182                leaf = path->nodes[0];
 183
 184                if (slot >= btrfs_header_nritems(leaf)) {
 185                        ret = btrfs_next_leaf(root, path);
 186                        if (ret < 0)
 187                                goto out;
 188                        else if (ret > 0)
 189                                break;
 190                        continue;
 191                }
 192
 193                btrfs_item_key_to_cpu(leaf, &key, slot);
 194                if (key.objectid != objectid)
 195                        break;
 196                if (key.type != BTRFS_XATTR_ITEM_KEY)
 197                        break;
 198
 199                handlers = find_prop_handlers_by_hash(key.offset);
 200                if (!handlers)
 201                        goto next_slot;
 202
 203                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
 204                cur = 0;
 205                total_len = btrfs_item_size_nr(leaf, slot);
 206
 207                while (cur < total_len) {
 208                        u32 name_len = btrfs_dir_name_len(leaf, di);
 209                        u32 data_len = btrfs_dir_data_len(leaf, di);
 210                        unsigned long name_ptr, data_ptr;
 211                        const struct prop_handler *handler;
 212
 213                        this_len = sizeof(*di) + name_len + data_len;
 214                        name_ptr = (unsigned long)(di + 1);
 215                        data_ptr = name_ptr + name_len;
 216
 217                        if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
 218                            memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
 219                                                 name_ptr,
 220                                                 XATTR_BTRFS_PREFIX_LEN))
 221                                goto next_dir_item;
 222
 223                        if (name_len >= name_buf_len) {
 224                                kfree(name_buf);
 225                                name_buf_len = name_len + 1;
 226                                name_buf = kmalloc(name_buf_len, GFP_NOFS);
 227                                if (!name_buf) {
 228                                        ret = -ENOMEM;
 229                                        goto out;
 230                                }
 231                        }
 232                        read_extent_buffer(leaf, name_buf, name_ptr, name_len);
 233                        name_buf[name_len] = '\0';
 234
 235                        handler = find_prop_handler(name_buf, handlers);
 236                        if (!handler)
 237                                goto next_dir_item;
 238
 239                        if (data_len > value_buf_len) {
 240                                kfree(value_buf);
 241                                value_buf_len = data_len;
 242                                value_buf = kmalloc(data_len, GFP_NOFS);
 243                                if (!value_buf) {
 244                                        ret = -ENOMEM;
 245                                        goto out;
 246                                }
 247                        }
 248                        read_extent_buffer(leaf, value_buf, data_ptr, data_len);
 249
 250                        iterator(ctx, handler, value_buf, data_len);
 251next_dir_item:
 252                        cur += this_len;
 253                        di = (struct btrfs_dir_item *)((char *) di + this_len);
 254                }
 255
 256next_slot:
 257                path->slots[0]++;
 258        }
 259
 260        ret = 0;
 261out:
 262        btrfs_release_path(path);
 263        kfree(name_buf);
 264        kfree(value_buf);
 265
 266        return ret;
 267}
 268
 269static void inode_prop_iterator(void *ctx,
 270                                const struct prop_handler *handler,
 271                                const char *value,
 272                                size_t len)
 273{
 274        struct inode *inode = ctx;
 275        struct btrfs_root *root = BTRFS_I(inode)->root;
 276        int ret;
 277
 278        ret = handler->apply(inode, value, len);
 279        if (unlikely(ret))
 280                btrfs_warn(root->fs_info,
 281                           "error applying prop %s to ino %llu (root %llu): %d",
 282                           handler->xattr_name, btrfs_ino(inode),
 283                           root->root_key.objectid, ret);
 284        else
 285                set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 286}
 287
 288int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
 289{
 290        struct btrfs_root *root = BTRFS_I(inode)->root;
 291        u64 ino = btrfs_ino(inode);
 292        int ret;
 293
 294        ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
 295
 296        return ret;
 297}
 298
 299static int inherit_props(struct btrfs_trans_handle *trans,
 300                         struct inode *inode,
 301                         struct inode *parent)
 302{
 303        struct btrfs_root *root = BTRFS_I(inode)->root;
 304        int ret;
 305        int i;
 306
 307        if (!test_bit(BTRFS_INODE_HAS_PROPS,
 308                      &BTRFS_I(parent)->runtime_flags))
 309                return 0;
 310
 311        for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
 312                const struct prop_handler *h = &prop_handlers[i];
 313                const char *value;
 314                u64 num_bytes;
 315
 316                if (!h->inheritable)
 317                        continue;
 318
 319                value = h->extract(parent);
 320                if (!value)
 321                        continue;
 322
 323                num_bytes = btrfs_calc_trans_metadata_size(root, 1);
 324                ret = btrfs_block_rsv_add(root, trans->block_rsv,
 325                                          num_bytes, BTRFS_RESERVE_NO_FLUSH);
 326                if (ret)
 327                        goto out;
 328                ret = __btrfs_set_prop(trans, inode, h->xattr_name,
 329                                       value, strlen(value), 0);
 330                btrfs_block_rsv_release(root, trans->block_rsv, num_bytes);
 331                if (ret)
 332                        goto out;
 333        }
 334        ret = 0;
 335out:
 336        return ret;
 337}
 338
 339int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
 340                              struct inode *inode,
 341                              struct inode *dir)
 342{
 343        if (!dir)
 344                return 0;
 345
 346        return inherit_props(trans, inode, dir);
 347}
 348
 349int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
 350                               struct btrfs_root *root,
 351                               struct btrfs_root *parent_root)
 352{
 353        struct btrfs_key key;
 354        struct inode *parent_inode, *child_inode;
 355        int ret;
 356
 357        key.objectid = BTRFS_FIRST_FREE_OBJECTID;
 358        key.type = BTRFS_INODE_ITEM_KEY;
 359        key.offset = 0;
 360
 361        parent_inode = btrfs_iget(parent_root->fs_info->sb, &key,
 362                                  parent_root, NULL);
 363        if (IS_ERR(parent_inode))
 364                return PTR_ERR(parent_inode);
 365
 366        child_inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
 367        if (IS_ERR(child_inode)) {
 368                iput(parent_inode);
 369                return PTR_ERR(child_inode);
 370        }
 371
 372        ret = inherit_props(trans, child_inode, parent_inode);
 373        iput(child_inode);
 374        iput(parent_inode);
 375
 376        return ret;
 377}
 378
 379static int prop_compression_validate(const char *value, size_t len)
 380{
 381        if (!strncmp("lzo", value, len))
 382                return 0;
 383        else if (!strncmp("zlib", value, len))
 384                return 0;
 385
 386        return -EINVAL;
 387}
 388
 389static int prop_compression_apply(struct inode *inode,
 390                                  const char *value,
 391                                  size_t len)
 392{
 393        int type;
 394
 395        if (len == 0) {
 396                BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
 397                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
 398                BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
 399
 400                return 0;
 401        }
 402
 403        if (!strncmp("lzo", value, len))
 404                type = BTRFS_COMPRESS_LZO;
 405        else if (!strncmp("zlib", value, len))
 406                type = BTRFS_COMPRESS_ZLIB;
 407        else
 408                return -EINVAL;
 409
 410        BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
 411        BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
 412        BTRFS_I(inode)->force_compress = type;
 413
 414        return 0;
 415}
 416
 417static const char *prop_compression_extract(struct inode *inode)
 418{
 419        switch (BTRFS_I(inode)->force_compress) {
 420        case BTRFS_COMPRESS_ZLIB:
 421                return "zlib";
 422        case BTRFS_COMPRESS_LZO:
 423                return "lzo";
 424        }
 425
 426        return NULL;
 427}
 428
 429
 430