LCOV - code coverage report
Current view: top level - fs/btrfs - export.c (source / functions) Hit Total Coverage
Test: btrfstest.info Lines: 0 130 0.0 %
Date: 2014-11-28 Functions: 0 6 0.0 %

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

Generated by: LCOV version 1.10