diff options
Diffstat (limited to 'fs/btrfs/export.c')
-rw-r--r-- | fs/btrfs/export.c | 90 |
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; | ||
115 | fail: | 111 | fail: |
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, | |||
166 | static struct dentry *btrfs_get_parent(struct dentry *child) | 162 | static 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; | ||
230 | fail: | 222 | fail: |
231 | btrfs_free_path(path); | 223 | btrfs_free_path(path); |
232 | return ERR_PTR(ret); | 224 | return ERR_PTR(ret); |
233 | } | 225 | } |
234 | 226 | ||
227 | static 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 | |||
235 | const struct export_operations btrfs_export_ops = { | 302 | const 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 | }; |