root/fs/btrfs/export.c

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

DEFINITIONS

This source file includes following definitions.
  1. btrfs_get_dentry
  2. btrfs_fh_to_parent
  3. btrfs_fh_to_dentry
  4. btrfs_get_parent
  5. btrfs_get_name

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

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