aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/export.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/export.c')
-rw-r--r--fs/btrfs/export.c90
1 files changed, 79 insertions, 11 deletions
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index ba5c3fd5ab8c..9786963b07e5 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -65,7 +65,6 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
65{ 65{
66 struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info; 66 struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info;
67 struct btrfs_root *root; 67 struct btrfs_root *root;
68 struct dentry *dentry;
69 struct inode *inode; 68 struct inode *inode;
70 struct btrfs_key key; 69 struct btrfs_key key;
71 int index; 70 int index;
@@ -95,7 +94,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
95 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 94 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
96 key.offset = 0; 95 key.offset = 0;
97 96
98 inode = btrfs_iget(sb, &key, root); 97 inode = btrfs_iget(sb, &key, root, NULL);
99 if (IS_ERR(inode)) { 98 if (IS_ERR(inode)) {
100 err = PTR_ERR(inode); 99 err = PTR_ERR(inode);
101 goto fail; 100 goto fail;
@@ -108,10 +107,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
108 return ERR_PTR(-ESTALE); 107 return ERR_PTR(-ESTALE);
109 } 108 }
110 109
111 dentry = d_obtain_alias(inode); 110 return d_obtain_alias(inode);
112 if (!IS_ERR(dentry))
113 dentry->d_op = &btrfs_dentry_operations;
114 return dentry;
115fail: 111fail:
116 srcu_read_unlock(&fs_info->subvol_srcu, index); 112 srcu_read_unlock(&fs_info->subvol_srcu, index);
117 return ERR_PTR(err); 113 return ERR_PTR(err);
@@ -166,7 +162,6 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
166static struct dentry *btrfs_get_parent(struct dentry *child) 162static struct dentry *btrfs_get_parent(struct dentry *child)
167{ 163{
168 struct inode *dir = child->d_inode; 164 struct inode *dir = child->d_inode;
169 static struct dentry *dentry;
170 struct btrfs_root *root = BTRFS_I(dir)->root; 165 struct btrfs_root *root = BTRFS_I(dir)->root;
171 struct btrfs_path *path; 166 struct btrfs_path *path;
172 struct extent_buffer *leaf; 167 struct extent_buffer *leaf;
@@ -223,18 +218,91 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
223 218
224 key.type = BTRFS_INODE_ITEM_KEY; 219 key.type = BTRFS_INODE_ITEM_KEY;
225 key.offset = 0; 220 key.offset = 0;
226 dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root)); 221 return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
227 if (!IS_ERR(dentry))
228 dentry->d_op = &btrfs_dentry_operations;
229 return dentry;
230fail: 222fail:
231 btrfs_free_path(path); 223 btrfs_free_path(path);
232 return ERR_PTR(ret); 224 return ERR_PTR(ret);
233} 225}
234 226
227static int btrfs_get_name(struct dentry *parent, char *name,
228 struct dentry *child)
229{
230 struct inode *inode = child->d_inode;
231 struct inode *dir = parent->d_inode;
232 struct btrfs_path *path;
233 struct btrfs_root *root = BTRFS_I(dir)->root;
234 struct btrfs_inode_ref *iref;
235 struct btrfs_root_ref *rref;
236 struct extent_buffer *leaf;
237 unsigned long name_ptr;
238 struct btrfs_key key;
239 int name_len;
240 int ret;
241
242 if (!dir || !inode)
243 return -EINVAL;
244
245 if (!S_ISDIR(dir->i_mode))
246 return -EINVAL;
247
248 path = btrfs_alloc_path();
249 if (!path)
250 return -ENOMEM;
251 path->leave_spinning = 1;
252
253 if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
254 key.objectid = BTRFS_I(inode)->root->root_key.objectid;
255 key.type = BTRFS_ROOT_BACKREF_KEY;
256 key.offset = (u64)-1;
257 root = root->fs_info->tree_root;
258 } else {
259 key.objectid = inode->i_ino;
260 key.offset = dir->i_ino;
261 key.type = BTRFS_INODE_REF_KEY;
262 }
263
264 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
265 if (ret < 0) {
266 btrfs_free_path(path);
267 return ret;
268 } else if (ret > 0) {
269 if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
270 path->slots[0]--;
271 } else {
272 btrfs_free_path(path);
273 return -ENOENT;
274 }
275 }
276 leaf = path->nodes[0];
277
278 if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
279 rref = btrfs_item_ptr(leaf, path->slots[0],
280 struct btrfs_root_ref);
281 name_ptr = (unsigned long)(rref + 1);
282 name_len = btrfs_root_ref_name_len(leaf, rref);
283 } else {
284 iref = btrfs_item_ptr(leaf, path->slots[0],
285 struct btrfs_inode_ref);
286 name_ptr = (unsigned long)(iref + 1);
287 name_len = btrfs_inode_ref_name_len(leaf, iref);
288 }
289
290 read_extent_buffer(leaf, name, name_ptr, name_len);
291 btrfs_free_path(path);
292
293 /*
294 * have to add the null termination to make sure that reconnect_path
295 * gets the right len for strlen
296 */
297 name[name_len] = '\0';
298
299 return 0;
300}
301
235const struct export_operations btrfs_export_ops = { 302const struct export_operations btrfs_export_ops = {
236 .encode_fh = btrfs_encode_fh, 303 .encode_fh = btrfs_encode_fh,
237 .fh_to_dentry = btrfs_fh_to_dentry, 304 .fh_to_dentry = btrfs_fh_to_dentry,
238 .fh_to_parent = btrfs_fh_to_parent, 305 .fh_to_parent = btrfs_fh_to_parent,
239 .get_parent = btrfs_get_parent, 306 .get_parent = btrfs_get_parent,
307 .get_name = btrfs_get_name,
240}; 308};