root/fs/btrfs/props.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_prop_handlers_by_hash
  2. find_prop_handler
  3. btrfs_validate_prop
  4. btrfs_set_prop
  5. iterate_object_props
  6. inode_prop_iterator
  7. btrfs_load_inode_props
  8. prop_compression_validate
  9. prop_compression_apply
  10. prop_compression_extract
  11. inherit_props
  12. btrfs_inode_inherit_props
  13. btrfs_subvol_inherit_props
  14. btrfs_props_init

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

/* [<][>][^][v][top][bottom][index][help] */