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