LCOV - code coverage report
Current view: top level - fs/btrfs - props.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 7 209 3.3 %
Date: 2023-07-31 20:08:17 Functions: 1 13 7.7 %

          Line data    Source code
       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 "messages.h"
       8             : #include "props.h"
       9             : #include "btrfs_inode.h"
      10             : #include "transaction.h"
      11             : #include "ctree.h"
      12             : #include "xattr.h"
      13             : #include "compression.h"
      14             : #include "space-info.h"
      15             : #include "fs.h"
      16             : #include "accessors.h"
      17             : #include "super.h"
      18             : 
      19             : #define BTRFS_PROP_HANDLERS_HT_BITS 8
      20             : static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
      21             : 
      22             : struct prop_handler {
      23             :         struct hlist_node node;
      24             :         const char *xattr_name;
      25             :         int (*validate)(const struct btrfs_inode *inode, const char *value,
      26             :                         size_t len);
      27             :         int (*apply)(struct inode *inode, const char *value, size_t len);
      28             :         const char *(*extract)(struct inode *inode);
      29             :         bool (*ignore)(const struct btrfs_inode *inode);
      30             :         int inheritable;
      31             : };
      32             : 
      33             : static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
      34             : {
      35           0 :         struct hlist_head *h;
      36             : 
      37           0 :         h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
      38           0 :         if (hlist_empty(h))
      39             :                 return NULL;
      40             : 
      41             :         return h;
      42             : }
      43             : 
      44             : static const struct prop_handler *
      45           0 : find_prop_handler(const char *name,
      46             :                   const struct hlist_head *handlers)
      47             : {
      48           0 :         struct prop_handler *h;
      49             : 
      50           0 :         if (!handlers) {
      51           0 :                 u64 hash = btrfs_name_hash(name, strlen(name));
      52             : 
      53           0 :                 handlers = find_prop_handlers_by_hash(hash);
      54             :                 if (!handlers)
      55             :                         return NULL;
      56             :         }
      57             : 
      58           0 :         hlist_for_each_entry(h, handlers, node)
      59           0 :                 if (!strcmp(h->xattr_name, name))
      60           0 :                         return h;
      61             : 
      62             :         return NULL;
      63             : }
      64             : 
      65           0 : int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name,
      66             :                         const char *value, size_t value_len)
      67             : {
      68           0 :         const struct prop_handler *handler;
      69             : 
      70           0 :         if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
      71             :                 return -EINVAL;
      72             : 
      73           0 :         handler = find_prop_handler(name, NULL);
      74           0 :         if (!handler)
      75             :                 return -EINVAL;
      76             : 
      77           0 :         if (value_len == 0)
      78             :                 return 0;
      79             : 
      80           0 :         return handler->validate(inode, value, value_len);
      81             : }
      82             : 
      83             : /*
      84             :  * Check if a property should be ignored (not set) for an inode.
      85             :  *
      86             :  * @inode:     The target inode.
      87             :  * @name:      The property's name.
      88             :  *
      89             :  * The caller must be sure the given property name is valid, for example by
      90             :  * having previously called btrfs_validate_prop().
      91             :  *
      92             :  * Returns:    true if the property should be ignored for the given inode
      93             :  *             false if the property must not be ignored for the given inode
      94             :  */
      95           0 : bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name)
      96             : {
      97           0 :         const struct prop_handler *handler;
      98             : 
      99           0 :         handler = find_prop_handler(name, NULL);
     100           0 :         ASSERT(handler != NULL);
     101             : 
     102           0 :         return handler->ignore(inode);
     103             : }
     104             : 
     105           0 : int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
     106             :                    const char *name, const char *value, size_t value_len,
     107             :                    int flags)
     108             : {
     109           0 :         const struct prop_handler *handler;
     110           0 :         int ret;
     111             : 
     112           0 :         handler = find_prop_handler(name, NULL);
     113           0 :         if (!handler)
     114             :                 return -EINVAL;
     115             : 
     116           0 :         if (value_len == 0) {
     117           0 :                 ret = btrfs_setxattr(trans, inode, handler->xattr_name,
     118             :                                      NULL, 0, flags);
     119           0 :                 if (ret)
     120             :                         return ret;
     121             : 
     122           0 :                 ret = handler->apply(inode, NULL, 0);
     123           0 :                 ASSERT(ret == 0);
     124             : 
     125           0 :                 return ret;
     126             :         }
     127             : 
     128           0 :         ret = btrfs_setxattr(trans, inode, handler->xattr_name, value,
     129             :                              value_len, flags);
     130           0 :         if (ret)
     131             :                 return ret;
     132           0 :         ret = handler->apply(inode, value, value_len);
     133           0 :         if (ret) {
     134           0 :                 btrfs_setxattr(trans, inode, handler->xattr_name, NULL,
     135             :                                0, flags);
     136           0 :                 return ret;
     137             :         }
     138             : 
     139           0 :         set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
     140             : 
     141             :         return 0;
     142             : }
     143             : 
     144           0 : static int iterate_object_props(struct btrfs_root *root,
     145             :                                 struct btrfs_path *path,
     146             :                                 u64 objectid,
     147             :                                 void (*iterator)(void *,
     148             :                                                  const struct prop_handler *,
     149             :                                                  const char *,
     150             :                                                  size_t),
     151             :                                 void *ctx)
     152             : {
     153           0 :         int ret;
     154           0 :         char *name_buf = NULL;
     155           0 :         char *value_buf = NULL;
     156           0 :         int name_buf_len = 0;
     157           0 :         int value_buf_len = 0;
     158             : 
     159           0 :         while (1) {
     160           0 :                 struct btrfs_key key;
     161           0 :                 struct btrfs_dir_item *di;
     162           0 :                 struct extent_buffer *leaf;
     163           0 :                 u32 total_len, cur, this_len;
     164           0 :                 int slot;
     165           0 :                 const struct hlist_head *handlers;
     166             : 
     167           0 :                 slot = path->slots[0];
     168           0 :                 leaf = path->nodes[0];
     169             : 
     170           0 :                 if (slot >= btrfs_header_nritems(leaf)) {
     171           0 :                         ret = btrfs_next_leaf(root, path);
     172           0 :                         if (ret < 0)
     173           0 :                                 goto out;
     174           0 :                         else if (ret > 0)
     175             :                                 break;
     176           0 :                         continue;
     177             :                 }
     178             : 
     179           0 :                 btrfs_item_key_to_cpu(leaf, &key, slot);
     180           0 :                 if (key.objectid != objectid)
     181             :                         break;
     182           0 :                 if (key.type != BTRFS_XATTR_ITEM_KEY)
     183             :                         break;
     184             : 
     185           0 :                 handlers = find_prop_handlers_by_hash(key.offset);
     186           0 :                 if (!handlers)
     187           0 :                         goto next_slot;
     188             : 
     189           0 :                 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
     190           0 :                 cur = 0;
     191           0 :                 total_len = btrfs_item_size(leaf, slot);
     192             : 
     193           0 :                 while (cur < total_len) {
     194           0 :                         u32 name_len = btrfs_dir_name_len(leaf, di);
     195           0 :                         u32 data_len = btrfs_dir_data_len(leaf, di);
     196           0 :                         unsigned long name_ptr, data_ptr;
     197           0 :                         const struct prop_handler *handler;
     198             : 
     199           0 :                         this_len = sizeof(*di) + name_len + data_len;
     200           0 :                         name_ptr = (unsigned long)(di + 1);
     201           0 :                         data_ptr = name_ptr + name_len;
     202             : 
     203           0 :                         if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
     204           0 :                             memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
     205             :                                                  name_ptr,
     206             :                                                  XATTR_BTRFS_PREFIX_LEN))
     207           0 :                                 goto next_dir_item;
     208             : 
     209           0 :                         if (name_len >= name_buf_len) {
     210           0 :                                 kfree(name_buf);
     211           0 :                                 name_buf_len = name_len + 1;
     212           0 :                                 name_buf = kmalloc(name_buf_len, GFP_NOFS);
     213           0 :                                 if (!name_buf) {
     214           0 :                                         ret = -ENOMEM;
     215           0 :                                         goto out;
     216             :                                 }
     217             :                         }
     218           0 :                         read_extent_buffer(leaf, name_buf, name_ptr, name_len);
     219           0 :                         name_buf[name_len] = '\0';
     220             : 
     221           0 :                         handler = find_prop_handler(name_buf, handlers);
     222           0 :                         if (!handler)
     223           0 :                                 goto next_dir_item;
     224             : 
     225           0 :                         if (data_len > value_buf_len) {
     226           0 :                                 kfree(value_buf);
     227           0 :                                 value_buf_len = data_len;
     228           0 :                                 value_buf = kmalloc(data_len, GFP_NOFS);
     229           0 :                                 if (!value_buf) {
     230           0 :                                         ret = -ENOMEM;
     231           0 :                                         goto out;
     232             :                                 }
     233             :                         }
     234           0 :                         read_extent_buffer(leaf, value_buf, data_ptr, data_len);
     235             : 
     236           0 :                         iterator(ctx, handler, value_buf, data_len);
     237           0 : next_dir_item:
     238           0 :                         cur += this_len;
     239           0 :                         di = (struct btrfs_dir_item *)((char *) di + this_len);
     240             :                 }
     241             : 
     242           0 : next_slot:
     243           0 :                 path->slots[0]++;
     244             :         }
     245             : 
     246           0 :         ret = 0;
     247           0 : out:
     248           0 :         btrfs_release_path(path);
     249           0 :         kfree(name_buf);
     250           0 :         kfree(value_buf);
     251             : 
     252           0 :         return ret;
     253             : }
     254             : 
     255           0 : static void inode_prop_iterator(void *ctx,
     256             :                                 const struct prop_handler *handler,
     257             :                                 const char *value,
     258             :                                 size_t len)
     259             : {
     260           0 :         struct inode *inode = ctx;
     261           0 :         struct btrfs_root *root = BTRFS_I(inode)->root;
     262           0 :         int ret;
     263             : 
     264           0 :         ret = handler->apply(inode, value, len);
     265           0 :         if (unlikely(ret))
     266           0 :                 btrfs_warn(root->fs_info,
     267             :                            "error applying prop %s to ino %llu (root %llu): %d",
     268             :                            handler->xattr_name, btrfs_ino(BTRFS_I(inode)),
     269             :                            root->root_key.objectid, ret);
     270             :         else
     271           0 :                 set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
     272           0 : }
     273             : 
     274           0 : int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
     275             : {
     276           0 :         struct btrfs_root *root = BTRFS_I(inode)->root;
     277           0 :         u64 ino = btrfs_ino(BTRFS_I(inode));
     278             : 
     279           0 :         return iterate_object_props(root, path, ino, inode_prop_iterator, inode);
     280             : }
     281             : 
     282           0 : static int prop_compression_validate(const struct btrfs_inode *inode,
     283             :                                      const char *value, size_t len)
     284             : {
     285           0 :         if (!btrfs_inode_can_compress(inode))
     286             :                 return -EINVAL;
     287             : 
     288           0 :         if (!value)
     289             :                 return 0;
     290             : 
     291           0 :         if (btrfs_compress_is_valid_type(value, len))
     292             :                 return 0;
     293             : 
     294           0 :         if ((len == 2 && strncmp("no", value, 2) == 0) ||
     295           0 :             (len == 4 && strncmp("none", value, 4) == 0))
     296           0 :                 return 0;
     297             : 
     298             :         return -EINVAL;
     299             : }
     300             : 
     301           0 : static int prop_compression_apply(struct inode *inode, const char *value,
     302             :                                   size_t len)
     303             : {
     304           0 :         struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
     305           0 :         int type;
     306             : 
     307             :         /* Reset to defaults */
     308           0 :         if (len == 0) {
     309           0 :                 BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
     310           0 :                 BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
     311           0 :                 BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
     312           0 :                 return 0;
     313             :         }
     314             : 
     315             :         /* Set NOCOMPRESS flag */
     316           0 :         if ((len == 2 && strncmp("no", value, 2) == 0) ||
     317           0 :             (len == 4 && strncmp("none", value, 4) == 0)) {
     318           0 :                 BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
     319           0 :                 BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
     320           0 :                 BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
     321             : 
     322           0 :                 return 0;
     323             :         }
     324             : 
     325           0 :         if (!strncmp("lzo", value, 3)) {
     326           0 :                 type = BTRFS_COMPRESS_LZO;
     327           0 :                 btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
     328           0 :         } else if (!strncmp("zlib", value, 4)) {
     329             :                 type = BTRFS_COMPRESS_ZLIB;
     330           0 :         } else if (!strncmp("zstd", value, 4)) {
     331           0 :                 type = BTRFS_COMPRESS_ZSTD;
     332           0 :                 btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
     333             :         } else {
     334             :                 return -EINVAL;
     335             :         }
     336             : 
     337           0 :         BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
     338           0 :         BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
     339           0 :         BTRFS_I(inode)->prop_compress = type;
     340             : 
     341           0 :         return 0;
     342             : }
     343             : 
     344           0 : static bool prop_compression_ignore(const struct btrfs_inode *inode)
     345             : {
     346             :         /*
     347             :          * Compression only has effect for regular files, and for directories
     348             :          * we set it just to propagate it to new files created inside them.
     349             :          * Everything else (symlinks, devices, sockets, fifos) is pointless as
     350             :          * it will do nothing, so don't waste metadata space on a compression
     351             :          * xattr for anything that is neither a file nor a directory.
     352             :          */
     353           0 :         if (!S_ISREG(inode->vfs_inode.i_mode) &&
     354             :             !S_ISDIR(inode->vfs_inode.i_mode))
     355           0 :                 return true;
     356             : 
     357             :         return false;
     358             : }
     359             : 
     360           0 : static const char *prop_compression_extract(struct inode *inode)
     361             : {
     362           0 :         switch (BTRFS_I(inode)->prop_compress) {
     363             :         case BTRFS_COMPRESS_ZLIB:
     364             :         case BTRFS_COMPRESS_LZO:
     365             :         case BTRFS_COMPRESS_ZSTD:
     366           0 :                 return btrfs_compress_type2str(BTRFS_I(inode)->prop_compress);
     367             :         default:
     368             :                 break;
     369             :         }
     370             : 
     371             :         return NULL;
     372             : }
     373             : 
     374             : static struct prop_handler prop_handlers[] = {
     375             :         {
     376             :                 .xattr_name = XATTR_BTRFS_PREFIX "compression",
     377             :                 .validate = prop_compression_validate,
     378             :                 .apply = prop_compression_apply,
     379             :                 .extract = prop_compression_extract,
     380             :                 .ignore = prop_compression_ignore,
     381             :                 .inheritable = 1
     382             :         },
     383             : };
     384             : 
     385           0 : int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
     386             :                               struct inode *inode, struct inode *parent)
     387             : {
     388           0 :         struct btrfs_root *root = BTRFS_I(inode)->root;
     389           0 :         struct btrfs_fs_info *fs_info = root->fs_info;
     390           0 :         int ret;
     391           0 :         int i;
     392           0 :         bool need_reserve = false;
     393             : 
     394           0 :         if (!test_bit(BTRFS_INODE_HAS_PROPS,
     395             :                       &BTRFS_I(parent)->runtime_flags))
     396             :                 return 0;
     397             : 
     398           0 :         for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
     399           0 :                 const struct prop_handler *h = &prop_handlers[i];
     400           0 :                 const char *value;
     401           0 :                 u64 num_bytes = 0;
     402             : 
     403           0 :                 if (!h->inheritable)
     404           0 :                         continue;
     405             : 
     406           0 :                 if (h->ignore(BTRFS_I(inode)))
     407           0 :                         continue;
     408             : 
     409           0 :                 value = h->extract(parent);
     410           0 :                 if (!value)
     411           0 :                         continue;
     412             : 
     413             :                 /*
     414             :                  * This is not strictly necessary as the property should be
     415             :                  * valid, but in case it isn't, don't propagate it further.
     416             :                  */
     417           0 :                 ret = h->validate(BTRFS_I(inode), value, strlen(value));
     418           0 :                 if (ret)
     419           0 :                         continue;
     420             : 
     421             :                 /*
     422             :                  * Currently callers should be reserving 1 item for properties,
     423             :                  * since we only have 1 property that we currently support.  If
     424             :                  * we add more in the future we need to try and reserve more
     425             :                  * space for them.  But we should also revisit how we do space
     426             :                  * reservations if we do add more properties in the future.
     427             :                  */
     428           0 :                 if (need_reserve) {
     429           0 :                         num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
     430           0 :                         ret = btrfs_block_rsv_add(fs_info, trans->block_rsv,
     431             :                                                   num_bytes,
     432             :                                                   BTRFS_RESERVE_NO_FLUSH);
     433           0 :                         if (ret)
     434           0 :                                 return ret;
     435             :                 }
     436             : 
     437           0 :                 ret = btrfs_setxattr(trans, inode, h->xattr_name, value,
     438             :                                      strlen(value), 0);
     439           0 :                 if (!ret) {
     440           0 :                         ret = h->apply(inode, value, strlen(value));
     441           0 :                         if (ret)
     442           0 :                                 btrfs_setxattr(trans, inode, h->xattr_name,
     443             :                                                NULL, 0, 0);
     444             :                         else
     445           0 :                                 set_bit(BTRFS_INODE_HAS_PROPS,
     446           0 :                                         &BTRFS_I(inode)->runtime_flags);
     447             :                 }
     448             : 
     449           0 :                 if (need_reserve) {
     450           0 :                         btrfs_block_rsv_release(fs_info, trans->block_rsv,
     451             :                                         num_bytes, NULL);
     452           0 :                         if (ret)
     453           0 :                                 return ret;
     454             :                 }
     455             :                 need_reserve = true;
     456             :         }
     457             : 
     458             :         return 0;
     459             : }
     460             : 
     461           2 : int __init btrfs_props_init(void)
     462             : {
     463           2 :         int i;
     464             : 
     465           4 :         for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
     466           2 :                 struct prop_handler *p = &prop_handlers[i];
     467           2 :                 u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
     468             : 
     469           2 :                 hash_add(prop_handlers_ht, &p->node, h);
     470             :         }
     471           2 :         return 0;
     472             : }
     473             : 

Generated by: LCOV version 1.14