LCOV - code coverage report
Current view: top level - fs/btrfs - export.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 110 158 69.6 %
Date: 2023-07-31 20:08:22 Functions: 5 6 83.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : 
       3             : #include <linux/fs.h>
       4             : #include <linux/types.h>
       5             : #include "ctree.h"
       6             : #include "disk-io.h"
       7             : #include "btrfs_inode.h"
       8             : #include "print-tree.h"
       9             : #include "export.h"
      10             : #include "accessors.h"
      11             : #include "super.h"
      12             : 
      13             : #define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
      14             :                                                  parent_objectid) / 4)
      15             : #define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, \
      16             :                                              parent_root_objectid) / 4)
      17             : #define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4)
      18             : 
      19       11821 : static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
      20             :                            struct inode *parent)
      21             : {
      22       11821 :         struct btrfs_fid *fid = (struct btrfs_fid *)fh;
      23       11821 :         int len = *max_len;
      24       11821 :         int type;
      25             : 
      26       11821 :         if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
      27           0 :                 *max_len = BTRFS_FID_SIZE_CONNECTABLE;
      28           0 :                 return FILEID_INVALID;
      29       11821 :         } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
      30           0 :                 *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
      31           0 :                 return FILEID_INVALID;
      32             :         }
      33             : 
      34       11821 :         len  = BTRFS_FID_SIZE_NON_CONNECTABLE;
      35       11821 :         type = FILEID_BTRFS_WITHOUT_PARENT;
      36             : 
      37       11821 :         fid->objectid = btrfs_ino(BTRFS_I(inode));
      38       11821 :         fid->root_objectid = BTRFS_I(inode)->root->root_key.objectid;
      39       11821 :         fid->gen = inode->i_generation;
      40             : 
      41       11821 :         if (parent) {
      42           0 :                 u64 parent_root_id;
      43             : 
      44           0 :                 fid->parent_objectid = BTRFS_I(parent)->location.objectid;
      45           0 :                 fid->parent_gen = parent->i_generation;
      46           0 :                 parent_root_id = BTRFS_I(parent)->root->root_key.objectid;
      47             : 
      48           0 :                 if (parent_root_id != fid->root_objectid) {
      49           0 :                         fid->parent_root_objectid = parent_root_id;
      50           0 :                         len = BTRFS_FID_SIZE_CONNECTABLE_ROOT;
      51           0 :                         type = FILEID_BTRFS_WITH_PARENT_ROOT;
      52             :                 } else {
      53             :                         len = BTRFS_FID_SIZE_CONNECTABLE;
      54             :                         type = FILEID_BTRFS_WITH_PARENT;
      55             :                 }
      56             :         }
      57             : 
      58       11821 :         *max_len = len;
      59       11821 :         return type;
      60             : }
      61             : 
      62             : /*
      63             :  * Read dentry of inode with @objectid from filesystem root @root_objectid.
      64             :  *
      65             :  * @sb:             the filesystem super block
      66             :  * @objectid:       inode objectid
      67             :  * @root_objectid:  object id of the subvolume root where to look up the inode
      68             :  * @generation:     optional, if not zero, verify that the found inode
      69             :  *                  generation matches
      70             :  *
      71             :  * Return dentry alias for the inode, otherwise an error. In case the
      72             :  * generation does not match return ESTALE.
      73             :  */
      74        4235 : struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
      75             :                                 u64 root_objectid, u64 generation)
      76             : {
      77        4235 :         struct btrfs_fs_info *fs_info = btrfs_sb(sb);
      78        4235 :         struct btrfs_root *root;
      79        4235 :         struct inode *inode;
      80             : 
      81        4235 :         if (objectid < BTRFS_FIRST_FREE_OBJECTID)
      82             :                 return ERR_PTR(-ESTALE);
      83             : 
      84        4235 :         root = btrfs_get_fs_root(fs_info, root_objectid, true);
      85        4235 :         if (IS_ERR(root))
      86             :                 return ERR_CAST(root);
      87             : 
      88        4235 :         inode = btrfs_iget(sb, objectid, root);
      89        4235 :         btrfs_put_root(root);
      90        4235 :         if (IS_ERR(inode))
      91             :                 return ERR_CAST(inode);
      92             : 
      93        3200 :         if (generation != 0 && generation != inode->i_generation) {
      94           0 :                 iput(inode);
      95           0 :                 return ERR_PTR(-ESTALE);
      96             :         }
      97             : 
      98        3200 :         return d_obtain_alias(inode);
      99             : }
     100             : 
     101           0 : static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
     102             :                                          int fh_len, int fh_type)
     103             : {
     104           0 :         struct btrfs_fid *fid = (struct btrfs_fid *) fh;
     105           0 :         u64 objectid, root_objectid;
     106           0 :         u32 generation;
     107             : 
     108           0 :         if (fh_type == FILEID_BTRFS_WITH_PARENT) {
     109           0 :                 if (fh_len <  BTRFS_FID_SIZE_CONNECTABLE)
     110             :                         return NULL;
     111           0 :                 root_objectid = fid->root_objectid;
     112           0 :         } else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) {
     113           0 :                 if (fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT)
     114             :                         return NULL;
     115           0 :                 root_objectid = fid->parent_root_objectid;
     116             :         } else
     117             :                 return NULL;
     118             : 
     119           0 :         objectid = fid->parent_objectid;
     120           0 :         generation = fid->parent_gen;
     121             : 
     122           0 :         return btrfs_get_dentry(sb, objectid, root_objectid, generation);
     123             : }
     124             : 
     125        4223 : static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
     126             :                                          int fh_len, int fh_type)
     127             : {
     128        4223 :         struct btrfs_fid *fid = (struct btrfs_fid *) fh;
     129        4223 :         u64 objectid, root_objectid;
     130        4223 :         u32 generation;
     131             : 
     132        4223 :         if ((fh_type != FILEID_BTRFS_WITH_PARENT ||
     133        4223 :              fh_len < BTRFS_FID_SIZE_CONNECTABLE) &&
     134        4223 :             (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT ||
     135        4223 :              fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) &&
     136        4223 :             (fh_type != FILEID_BTRFS_WITHOUT_PARENT ||
     137        4223 :              fh_len < BTRFS_FID_SIZE_NON_CONNECTABLE))
     138             :                 return NULL;
     139             : 
     140        4223 :         objectid = fid->objectid;
     141        4223 :         root_objectid = fid->root_objectid;
     142        4223 :         generation = fid->gen;
     143             : 
     144        4223 :         return btrfs_get_dentry(sb, objectid, root_objectid, generation);
     145             : }
     146             : 
     147          15 : struct dentry *btrfs_get_parent(struct dentry *child)
     148             : {
     149          15 :         struct inode *dir = d_inode(child);
     150          15 :         struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
     151          15 :         struct btrfs_root *root = BTRFS_I(dir)->root;
     152          15 :         struct btrfs_path *path;
     153          15 :         struct extent_buffer *leaf;
     154          15 :         struct btrfs_root_ref *ref;
     155          15 :         struct btrfs_key key;
     156          15 :         struct btrfs_key found_key;
     157          15 :         int ret;
     158             : 
     159          15 :         path = btrfs_alloc_path();
     160          15 :         if (!path)
     161             :                 return ERR_PTR(-ENOMEM);
     162             : 
     163          15 :         if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) {
     164           6 :                 key.objectid = root->root_key.objectid;
     165           6 :                 key.type = BTRFS_ROOT_BACKREF_KEY;
     166           6 :                 key.offset = (u64)-1;
     167           6 :                 root = fs_info->tree_root;
     168             :         } else {
     169           9 :                 key.objectid = btrfs_ino(BTRFS_I(dir));
     170           9 :                 key.type = BTRFS_INODE_REF_KEY;
     171           9 :                 key.offset = (u64)-1;
     172             :         }
     173             : 
     174          15 :         ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
     175          15 :         if (ret < 0)
     176           0 :                 goto fail;
     177             : 
     178          15 :         BUG_ON(ret == 0); /* Key with offset of -1 found */
     179          15 :         if (path->slots[0] == 0) {
     180           0 :                 ret = -ENOENT;
     181           0 :                 goto fail;
     182             :         }
     183             : 
     184          15 :         path->slots[0]--;
     185          15 :         leaf = path->nodes[0];
     186             : 
     187          15 :         btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
     188          15 :         if (found_key.objectid != key.objectid || found_key.type != key.type) {
     189           0 :                 ret = -ENOENT;
     190           0 :                 goto fail;
     191             :         }
     192             : 
     193          15 :         if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
     194           6 :                 ref = btrfs_item_ptr(leaf, path->slots[0],
     195             :                                      struct btrfs_root_ref);
     196           6 :                 key.objectid = btrfs_root_ref_dirid(leaf, ref);
     197             :         } else {
     198           9 :                 key.objectid = found_key.offset;
     199             :         }
     200          15 :         btrfs_free_path(path);
     201             : 
     202          15 :         if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
     203           6 :                 return btrfs_get_dentry(fs_info->sb, key.objectid,
     204             :                                         found_key.offset, 0);
     205             :         }
     206             : 
     207           9 :         return d_obtain_alias(btrfs_iget(fs_info->sb, key.objectid, root));
     208           0 : fail:
     209           0 :         btrfs_free_path(path);
     210           0 :         return ERR_PTR(ret);
     211             : }
     212             : 
     213           9 : static int btrfs_get_name(struct dentry *parent, char *name,
     214             :                           struct dentry *child)
     215             : {
     216           9 :         struct inode *inode = d_inode(child);
     217           9 :         struct inode *dir = d_inode(parent);
     218           9 :         struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
     219           9 :         struct btrfs_path *path;
     220           9 :         struct btrfs_root *root = BTRFS_I(dir)->root;
     221           9 :         struct btrfs_inode_ref *iref;
     222           9 :         struct btrfs_root_ref *rref;
     223           9 :         struct extent_buffer *leaf;
     224           9 :         unsigned long name_ptr;
     225           9 :         struct btrfs_key key;
     226           9 :         int name_len;
     227           9 :         int ret;
     228           9 :         u64 ino;
     229             : 
     230           9 :         if (!S_ISDIR(dir->i_mode))
     231             :                 return -EINVAL;
     232             : 
     233           9 :         ino = btrfs_ino(BTRFS_I(inode));
     234             : 
     235           9 :         path = btrfs_alloc_path();
     236           9 :         if (!path)
     237             :                 return -ENOMEM;
     238             : 
     239           9 :         if (ino == BTRFS_FIRST_FREE_OBJECTID) {
     240           0 :                 key.objectid = BTRFS_I(inode)->root->root_key.objectid;
     241           0 :                 key.type = BTRFS_ROOT_BACKREF_KEY;
     242           0 :                 key.offset = (u64)-1;
     243           0 :                 root = fs_info->tree_root;
     244             :         } else {
     245           9 :                 key.objectid = ino;
     246           9 :                 key.offset = btrfs_ino(BTRFS_I(dir));
     247           9 :                 key.type = BTRFS_INODE_REF_KEY;
     248             :         }
     249             : 
     250           9 :         ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
     251           9 :         if (ret < 0) {
     252           0 :                 btrfs_free_path(path);
     253           0 :                 return ret;
     254           9 :         } else if (ret > 0) {
     255           0 :                 if (ino == BTRFS_FIRST_FREE_OBJECTID) {
     256           0 :                         path->slots[0]--;
     257             :                 } else {
     258           0 :                         btrfs_free_path(path);
     259           0 :                         return -ENOENT;
     260             :                 }
     261             :         }
     262           9 :         leaf = path->nodes[0];
     263             : 
     264           9 :         if (ino == BTRFS_FIRST_FREE_OBJECTID) {
     265           0 :                 rref = btrfs_item_ptr(leaf, path->slots[0],
     266             :                                      struct btrfs_root_ref);
     267           0 :                 name_ptr = (unsigned long)(rref + 1);
     268           0 :                 name_len = btrfs_root_ref_name_len(leaf, rref);
     269             :         } else {
     270           9 :                 iref = btrfs_item_ptr(leaf, path->slots[0],
     271             :                                       struct btrfs_inode_ref);
     272           9 :                 name_ptr = (unsigned long)(iref + 1);
     273           9 :                 name_len = btrfs_inode_ref_name_len(leaf, iref);
     274             :         }
     275             : 
     276           9 :         read_extent_buffer(leaf, name, name_ptr, name_len);
     277           9 :         btrfs_free_path(path);
     278             : 
     279             :         /*
     280             :          * have to add the null termination to make sure that reconnect_path
     281             :          * gets the right len for strlen
     282             :          */
     283           9 :         name[name_len] = '\0';
     284             : 
     285           9 :         return 0;
     286             : }
     287             : 
     288             : const struct export_operations btrfs_export_ops = {
     289             :         .encode_fh      = btrfs_encode_fh,
     290             :         .fh_to_dentry   = btrfs_fh_to_dentry,
     291             :         .fh_to_parent   = btrfs_fh_to_parent,
     292             :         .get_parent     = btrfs_get_parent,
     293             :         .get_name       = btrfs_get_name,
     294             : };

Generated by: LCOV version 1.14