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
  26#define BTRFS_PROP_HANDLERS_HT_BITS 8
  27static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
  28
  29struct prop_handler {
  30        struct hlist_node node;
  31        const char *xattr_name;
  32        int (*validate)(const char *value, size_t len);
  33        int (*apply)(struct inode *inode, const char *value, size_t len);
  34        const char *(*extract)(struct inode *inode);
  35        int inheritable;
  36};
  37
  38static int prop_compression_validate(const char *value, size_t len);
  39static int prop_compression_apply(struct inode *inode,
  40                                  const char *value,
  41                                  size_t len);
  42static const char *prop_compression_extract(struct inode *inode);
  43
  44static struct prop_handler prop_handlers[] = {
  45        {
  46                .xattr_name = XATTR_BTRFS_PREFIX "compression",
  47                .validate = prop_compression_validate,
  48                .apply = prop_compression_apply,
  49                .extract = prop_compression_extract,
  50                .inheritable = 1
  51        },
  52        {
  53                .xattr_name = NULL
  54        }
  55};
  56
  57void __init btrfs_props_init(void)
  58{
  59        struct prop_handler *p;
  60
  61        hash_init(prop_handlers_ht);
  62
  63        for (p = &prop_handlers[0]; p->xattr_name; p++) {
  64                u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
  65
  66                hash_add(prop_handlers_ht, &p->node, h);
  67        }
  68}
  69
  70static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
  71{
  72        struct hlist_head *h;
  73
  74        h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
  75        if (hlist_empty(h))
  76                return NULL;
  77
  78        return h;
  79}
  80
  81static const struct prop_handler *
  82find_prop_handler(const char *name,
  83                  const struct hlist_head *handlers)
  84{
  85        struct prop_handler *h;
  86
  87        if (!handlers) {
  88                u64 hash = btrfs_name_hash(name, strlen(name));
  89
  90                handlers = find_prop_handlers_by_hash(hash);
  91                if (!handlers)
  92                        return NULL;
  93        }
  94
  95        hlist_for_each_entry(h, handlers, node)
  96                if (!strcmp(h->xattr_name, name))
  97                        return h;
  98
  99        return NULL;
 100}
 101
 102static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
 103                            struct inode *inode,
 104                            const char *name,
 105                            const char *value,
 106                            size_t value_len,
 107                            int flags)
 108{
 109        const struct prop_handler *handler;
 110        int ret;
 111
 112        if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
 113                return -EINVAL;
 114
 115        handler = find_prop_handler(name, NULL);
 116        if (!handler)
 117                return -EINVAL;
 118
 119        if (value_len == 0) {
 120                ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
 121                                       NULL, 0, flags);
 122                if (ret)
 123                        return ret;
 124
 125                ret = handler->apply(inode, NULL, 0);
 126                ASSERT(ret == 0);
 127
 128                return ret;
 129        }
 130
 131        ret = handler->validate(value, value_len);
 132        if (ret)
 133                return ret;
 134        ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
 135                               value, value_len, flags);
 136        if (ret)
 137                return ret;
 138        ret = handler->apply(inode, value, value_len);
 139        if (ret) {
 140                __btrfs_setxattr(trans, inode, handler->xattr_name,
 141                                 NULL, 0, flags);
 142                return ret;
 143        }
 144
 145        set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 146
 147        return 0;
 148}
 149
 150int btrfs_set_prop(struct inode *inode,
 151                   const char *name,
 152                   const char *value,
 153                   size_t value_len,
 154                   int flags)
 155{
 156        return __btrfs_set_prop(NULL, inode, name, value, value_len, flags);
 157}
 158
 159static int iterate_object_props(struct btrfs_root *root,
 160                                struct btrfs_path *path,
 161                                u64 objectid,
 162                                void (*iterator)(void *,
 163                                                 const struct prop_handler *,
 164                                                 const char *,
 165                                                 size_t),
 166                                void *ctx)
 167{
 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 (name_len <= XATTR_BTRFS_PREFIX_LEN ||
 219                            memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
 220                                                 name_ptr,
 221                                                 XATTR_BTRFS_PREFIX_LEN))
 222                                goto next_dir_item;
 223
 224                        if (name_len >= name_buf_len) {
 225                                kfree(name_buf);
 226                                name_buf_len = name_len + 1;
 227                                name_buf = kmalloc(name_buf_len, GFP_NOFS);
 228                                if (!name_buf) {
 229                                        ret = -ENOMEM;
 230                                        goto out;
 231                                }
 232                        }
 233                        read_extent_buffer(leaf, name_buf, name_ptr, name_len);
 234                        name_buf[name_len] = '\0';
 235
 236                        handler = find_prop_handler(name_buf, handlers);
 237                        if (!handler)
 238                                goto next_dir_item;
 239
 240                        if (data_len > value_buf_len) {
 241                                kfree(value_buf);
 242                                value_buf_len = data_len;
 243                                value_buf = kmalloc(data_len, GFP_NOFS);
 244                                if (!value_buf) {
 245                                        ret = -ENOMEM;
 246                                        goto out;
 247                                }
 248                        }
 249                        read_extent_buffer(leaf, value_buf, data_ptr, data_len);
 250
 251                        iterator(ctx, handler, value_buf, data_len);
 252next_dir_item:
 253                        cur += this_len;
 254                        di = (struct btrfs_dir_item *)((char *) di + this_len);
 255                }
 256
 257next_slot:
 258                path->slots[0]++;
 259        }
 260
 261        ret = 0;
 262out:
 263        btrfs_release_path(path);
 264        kfree(name_buf);
 265        kfree(value_buf);
 266
 267        return ret;
 268}
 269
 270static void inode_prop_iterator(void *ctx,
 271                                const struct prop_handler *handler,
 272                                const char *value,
 273                                size_t len)
 274{
 275        struct inode *inode = ctx;
 276        struct btrfs_root *root = BTRFS_I(inode)->root;
 277        int ret;
 278
 279        ret = handler->apply(inode, value, len);
 280        if (unlikely(ret))
 281                btrfs_warn(root->fs_info,
 282                           "error applying prop %s to ino %llu (root %llu): %d",
 283                           handler->xattr_name, btrfs_ino(inode),
 284                           root->root_key.objectid, ret);
 285        else
 286                set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
 287}
 288
 289int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
 290{
 291        struct btrfs_root *root = BTRFS_I(inode)->root;
 292        u64 ino = btrfs_ino(inode);
 293        int ret;
 294
 295        ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
 296
 297        return ret;
 298}
 299
 300static int inherit_props(struct btrfs_trans_handle *trans,
 301                         struct inode *inode,
 302                         struct inode *parent)
 303{
 304        const struct prop_handler *h;
 305        struct btrfs_root *root = BTRFS_I(inode)->root;
 306        int ret;
 307
 308        if (!test_bit(BTRFS_INODE_HAS_PROPS,
 309                      &BTRFS_I(parent)->runtime_flags))
 310                return 0;
 311
 312        for (h = &prop_handlers[0]; h->xattr_name; h++) {
 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