Blame view

fs/btrfs/export.c 7.77 KB
be6e8dc0b   Balaji Rao   NFS support for b...
1
2
3
4
5
6
7
8
  #include <linux/fs.h>
  #include <linux/types.h>
  #include "ctree.h"
  #include "disk-io.h"
  #include "btrfs_inode.h"
  #include "print-tree.h"
  #include "export.h"
  #include "compat.h"
d397712bc   Chris Mason   Btrfs: Fix checkp...
9
10
11
12
13
  #define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
  						 parent_objectid) / 4)
  #define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, \
  					     parent_root_objectid) / 4)
  #define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4)
be6e8dc0b   Balaji Rao   NFS support for b...
14
15
16
17
18
19
20
21
  
  static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
  			   int connectable)
  {
  	struct btrfs_fid *fid = (struct btrfs_fid *)fh;
  	struct inode *inode = dentry->d_inode;
  	int len = *max_len;
  	int type;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
22
23
  	if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
  		*max_len = BTRFS_FID_SIZE_CONNECTABLE;
be6e8dc0b   Balaji Rao   NFS support for b...
24
  		return 255;
5fe0c2378   Aneesh Kumar K.V   exportfs: Return ...
25
26
27
28
  	} else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
  		*max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
  		return 255;
  	}
be6e8dc0b   Balaji Rao   NFS support for b...
29
30
31
  
  	len  = BTRFS_FID_SIZE_NON_CONNECTABLE;
  	type = FILEID_BTRFS_WITHOUT_PARENT;
33345d015   Li Zefan   Btrfs: Always use...
32
  	fid->objectid = btrfs_ino(inode);
be6e8dc0b   Balaji Rao   NFS support for b...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  	fid->root_objectid = BTRFS_I(inode)->root->objectid;
  	fid->gen = inode->i_generation;
  
  	if (connectable && !S_ISDIR(inode->i_mode)) {
  		struct inode *parent;
  		u64 parent_root_id;
  
  		spin_lock(&dentry->d_lock);
  
  		parent = dentry->d_parent->d_inode;
  		fid->parent_objectid = BTRFS_I(parent)->location.objectid;
  		fid->parent_gen = parent->i_generation;
  		parent_root_id = BTRFS_I(parent)->root->objectid;
  
  		spin_unlock(&dentry->d_lock);
  
  		if (parent_root_id != fid->root_objectid) {
  			fid->parent_root_objectid = parent_root_id;
  			len = BTRFS_FID_SIZE_CONNECTABLE_ROOT;
  			type = FILEID_BTRFS_WITH_PARENT_ROOT;
  		} else {
  			len = BTRFS_FID_SIZE_CONNECTABLE;
  			type = FILEID_BTRFS_WITH_PARENT;
  		}
  	}
  
  	*max_len = len;
  	return type;
  }
  
  static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
64
65
  				       u64 root_objectid, u32 generation,
  				       int check_generation)
be6e8dc0b   Balaji Rao   NFS support for b...
66
  {
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
67
  	struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info;
be6e8dc0b   Balaji Rao   NFS support for b...
68
69
  	struct btrfs_root *root;
  	struct inode *inode;
be6e8dc0b   Balaji Rao   NFS support for b...
70
  	struct btrfs_key key;
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
71
72
73
74
75
  	int index;
  	int err = 0;
  
  	if (objectid < BTRFS_FIRST_FREE_OBJECTID)
  		return ERR_PTR(-ESTALE);
be6e8dc0b   Balaji Rao   NFS support for b...
76

2d4d9fbd6   David Woodhouse   Btrfs: Fix NFS ex...
77
78
79
  	key.objectid = root_objectid;
  	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
  	key.offset = (u64)-1;
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
80
81
82
83
84
85
86
87
88
89
90
91
  	index = srcu_read_lock(&fs_info->subvol_srcu);
  
  	root = btrfs_read_fs_root_no_name(fs_info, &key);
  	if (IS_ERR(root)) {
  		err = PTR_ERR(root);
  		goto fail;
  	}
  
  	if (btrfs_root_refs(&root->root_item) == 0) {
  		err = -ENOENT;
  		goto fail;
  	}
2d4d9fbd6   David Woodhouse   Btrfs: Fix NFS ex...
92

be6e8dc0b   Balaji Rao   NFS support for b...
93
94
95
  	key.objectid = objectid;
  	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
  	key.offset = 0;
73f73415c   Josef Bacik   Btrfs: change how...
96
  	inode = btrfs_iget(sb, &key, root, NULL);
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
97
98
99
100
101
102
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		goto fail;
  	}
  
  	srcu_read_unlock(&fs_info->subvol_srcu, index);
be6e8dc0b   Balaji Rao   NFS support for b...
103

76dda93c6   Yan, Zheng   Btrfs: add snapsh...
104
  	if (check_generation && generation != inode->i_generation) {
be6e8dc0b   Balaji Rao   NFS support for b...
105
106
107
  		iput(inode);
  		return ERR_PTR(-ESTALE);
  	}
af53d29ac   Al Viro   switch btrfs, clo...
108
  	return d_obtain_alias(inode);
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
109
110
111
  fail:
  	srcu_read_unlock(&fs_info->subvol_srcu, index);
  	return ERR_PTR(err);
be6e8dc0b   Balaji Rao   NFS support for b...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  }
  
  static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
  					 int fh_len, int fh_type)
  {
  	struct btrfs_fid *fid = (struct btrfs_fid *) fh;
  	u64 objectid, root_objectid;
  	u32 generation;
  
  	if (fh_type == FILEID_BTRFS_WITH_PARENT) {
  		if (fh_len !=  BTRFS_FID_SIZE_CONNECTABLE)
  			return NULL;
  		root_objectid = fid->root_objectid;
  	} else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) {
  		if (fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT)
  			return NULL;
  		root_objectid = fid->parent_root_objectid;
  	} else
  		return NULL;
  
  	objectid = fid->parent_objectid;
  	generation = fid->parent_gen;
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
134
  	return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
be6e8dc0b   Balaji Rao   NFS support for b...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  }
  
  static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
  					 int fh_len, int fh_type)
  {
  	struct btrfs_fid *fid = (struct btrfs_fid *) fh;
  	u64 objectid, root_objectid;
  	u32 generation;
  
  	if ((fh_type != FILEID_BTRFS_WITH_PARENT ||
  	     fh_len != BTRFS_FID_SIZE_CONNECTABLE) &&
  	    (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT ||
  	     fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT) &&
  	    (fh_type != FILEID_BTRFS_WITHOUT_PARENT ||
  	     fh_len != BTRFS_FID_SIZE_NON_CONNECTABLE))
  		return NULL;
  
  	objectid = fid->objectid;
  	root_objectid = fid->root_objectid;
  	generation = fid->gen;
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
155
  	return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
be6e8dc0b   Balaji Rao   NFS support for b...
156
157
158
159
160
  }
  
  static struct dentry *btrfs_get_parent(struct dentry *child)
  {
  	struct inode *dir = child->d_inode;
be6e8dc0b   Balaji Rao   NFS support for b...
161
  	struct btrfs_root *root = BTRFS_I(dir)->root;
be6e8dc0b   Balaji Rao   NFS support for b...
162
163
  	struct btrfs_path *path;
  	struct extent_buffer *leaf;
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
164
165
166
  	struct btrfs_root_ref *ref;
  	struct btrfs_key key;
  	struct btrfs_key found_key;
be6e8dc0b   Balaji Rao   NFS support for b...
167
168
169
  	int ret;
  
  	path = btrfs_alloc_path();
2a29edc6b   liubo   btrfs: fix severa...
170
171
  	if (!path)
  		return ERR_PTR(-ENOMEM);
be6e8dc0b   Balaji Rao   NFS support for b...
172

33345d015   Li Zefan   Btrfs: Always use...
173
  	if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) {
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
174
175
176
177
178
  		key.objectid = root->root_key.objectid;
  		key.type = BTRFS_ROOT_BACKREF_KEY;
  		key.offset = (u64)-1;
  		root = root->fs_info->tree_root;
  	} else {
33345d015   Li Zefan   Btrfs: Always use...
179
  		key.objectid = btrfs_ino(dir);
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
180
181
182
  		key.type = BTRFS_INODE_REF_KEY;
  		key.offset = (u64)-1;
  	}
be6e8dc0b   Balaji Rao   NFS support for b...
183

87acb4ef9   David Woodhouse   Simplify btrfs_ge...
184
  	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
185
186
187
188
189
190
191
  	if (ret < 0)
  		goto fail;
  
  	BUG_ON(ret == 0);
  	if (path->slots[0] == 0) {
  		ret = -ENOENT;
  		goto fail;
d54a83901   David Woodhouse   Clean up btrfs_ge...
192
  	}
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
193
194
  
  	path->slots[0]--;
be6e8dc0b   Balaji Rao   NFS support for b...
195
  	leaf = path->nodes[0];
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
196
197
198
199
200
  
  	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
  	if (found_key.objectid != key.objectid || found_key.type != key.type) {
  		ret = -ENOENT;
  		goto fail;
be6e8dc0b   Balaji Rao   NFS support for b...
201
  	}
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
202
203
204
205
206
207
208
  	if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
  		ref = btrfs_item_ptr(leaf, path->slots[0],
  				     struct btrfs_root_ref);
  		key.objectid = btrfs_root_ref_dirid(leaf, ref);
  	} else {
  		key.objectid = found_key.offset;
  	}
be6e8dc0b   Balaji Rao   NFS support for b...
209
  	btrfs_free_path(path);
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
210
211
212
213
  	if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
  		return btrfs_get_dentry(root->fs_info->sb, key.objectid,
  					found_key.offset, 0, 0);
  	}
2d4d9fbd6   David Woodhouse   Btrfs: Fix NFS ex...
214

76dda93c6   Yan, Zheng   Btrfs: add snapsh...
215
  	key.type = BTRFS_INODE_ITEM_KEY;
be6e8dc0b   Balaji Rao   NFS support for b...
216
  	key.offset = 0;
af53d29ac   Al Viro   switch btrfs, clo...
217
  	return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
76dda93c6   Yan, Zheng   Btrfs: add snapsh...
218
219
220
  fail:
  	btrfs_free_path(path);
  	return ERR_PTR(ret);
be6e8dc0b   Balaji Rao   NFS support for b...
221
  }
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  static int btrfs_get_name(struct dentry *parent, char *name,
  			  struct dentry *child)
  {
  	struct inode *inode = child->d_inode;
  	struct inode *dir = parent->d_inode;
  	struct btrfs_path *path;
  	struct btrfs_root *root = BTRFS_I(dir)->root;
  	struct btrfs_inode_ref *iref;
  	struct btrfs_root_ref *rref;
  	struct extent_buffer *leaf;
  	unsigned long name_ptr;
  	struct btrfs_key key;
  	int name_len;
  	int ret;
33345d015   Li Zefan   Btrfs: Always use...
236
  	u64 ino;
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
237
238
239
240
241
242
  
  	if (!dir || !inode)
  		return -EINVAL;
  
  	if (!S_ISDIR(dir->i_mode))
  		return -EINVAL;
33345d015   Li Zefan   Btrfs: Always use...
243
  	ino = btrfs_ino(inode);
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
244
245
246
247
  	path = btrfs_alloc_path();
  	if (!path)
  		return -ENOMEM;
  	path->leave_spinning = 1;
33345d015   Li Zefan   Btrfs: Always use...
248
  	if (ino == BTRFS_FIRST_FREE_OBJECTID) {
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
249
250
251
252
253
  		key.objectid = BTRFS_I(inode)->root->root_key.objectid;
  		key.type = BTRFS_ROOT_BACKREF_KEY;
  		key.offset = (u64)-1;
  		root = root->fs_info->tree_root;
  	} else {
33345d015   Li Zefan   Btrfs: Always use...
254
255
  		key.objectid = ino;
  		key.offset = btrfs_ino(dir);
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
256
257
258
259
260
261
262
263
  		key.type = BTRFS_INODE_REF_KEY;
  	}
  
  	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
  	if (ret < 0) {
  		btrfs_free_path(path);
  		return ret;
  	} else if (ret > 0) {
33345d015   Li Zefan   Btrfs: Always use...
264
  		if (ino == BTRFS_FIRST_FREE_OBJECTID) {
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
265
266
267
268
269
270
271
  			path->slots[0]--;
  		} else {
  			btrfs_free_path(path);
  			return -ENOENT;
  		}
  	}
  	leaf = path->nodes[0];
33345d015   Li Zefan   Btrfs: Always use...
272
273
  	if (ino == BTRFS_FIRST_FREE_OBJECTID) {
  		rref = btrfs_item_ptr(leaf, path->slots[0],
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
274
  				     struct btrfs_root_ref);
33345d015   Li Zefan   Btrfs: Always use...
275
276
  		name_ptr = (unsigned long)(rref + 1);
  		name_len = btrfs_root_ref_name_len(leaf, rref);
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  	} else {
  		iref = btrfs_item_ptr(leaf, path->slots[0],
  				      struct btrfs_inode_ref);
  		name_ptr = (unsigned long)(iref + 1);
  		name_len = btrfs_inode_ref_name_len(leaf, iref);
  	}
  
  	read_extent_buffer(leaf, name, name_ptr, name_len);
  	btrfs_free_path(path);
  
  	/*
  	 * have to add the null termination to make sure that reconnect_path
  	 * gets the right len for strlen
  	 */
  	name[name_len] = '\0';
  
  	return 0;
  }
be6e8dc0b   Balaji Rao   NFS support for b...
295
296
297
298
299
  const struct export_operations btrfs_export_ops = {
  	.encode_fh	= btrfs_encode_fh,
  	.fh_to_dentry	= btrfs_fh_to_dentry,
  	.fh_to_parent	= btrfs_fh_to_parent,
  	.get_parent	= btrfs_get_parent,
2ede0daf0   Josef Bacik   Btrfs: handle NFS...
300
  	.get_name	= btrfs_get_name,
be6e8dc0b   Balaji Rao   NFS support for b...
301
  };