1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2c1d7c514SDavid Sterba
3be6e8dc0SBalaji Rao #include <linux/fs.h>
4be6e8dc0SBalaji Rao #include <linux/types.h>
5be6e8dc0SBalaji Rao #include "ctree.h"
6be6e8dc0SBalaji Rao #include "disk-io.h"
7be6e8dc0SBalaji Rao #include "btrfs_inode.h"
8be6e8dc0SBalaji Rao #include "print-tree.h"
9be6e8dc0SBalaji Rao #include "export.h"
1007e81dc9SJosef Bacik #include "accessors.h"
117f0add25SJosef Bacik #include "super.h"
12be6e8dc0SBalaji Rao
13d397712bSChris Mason #define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
14d397712bSChris Mason parent_objectid) / 4)
15d397712bSChris Mason #define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, \
16d397712bSChris Mason parent_root_objectid) / 4)
17be6e8dc0SBalaji Rao #define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4)
18be6e8dc0SBalaji Rao
btrfs_encode_fh(struct inode * inode,u32 * fh,int * max_len,struct inode * parent)19b0b0382bSAl Viro static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
20b0b0382bSAl Viro struct inode *parent)
21be6e8dc0SBalaji Rao {
22be6e8dc0SBalaji Rao struct btrfs_fid *fid = (struct btrfs_fid *)fh;
23be6e8dc0SBalaji Rao int len = *max_len;
24be6e8dc0SBalaji Rao int type;
25be6e8dc0SBalaji Rao
26b0b0382bSAl Viro if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
275fe0c237SAneesh Kumar K.V *max_len = BTRFS_FID_SIZE_CONNECTABLE;
2894e07a75SNamjae Jeon return FILEID_INVALID;
295fe0c237SAneesh Kumar K.V } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
305fe0c237SAneesh Kumar K.V *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
3194e07a75SNamjae Jeon return FILEID_INVALID;
325fe0c237SAneesh Kumar K.V }
33be6e8dc0SBalaji Rao
34be6e8dc0SBalaji Rao len = BTRFS_FID_SIZE_NON_CONNECTABLE;
35be6e8dc0SBalaji Rao type = FILEID_BTRFS_WITHOUT_PARENT;
36be6e8dc0SBalaji Rao
374a0cc7caSNikolay Borisov fid->objectid = btrfs_ino(BTRFS_I(inode));
384fd786e6SMisono Tomohiro fid->root_objectid = BTRFS_I(inode)->root->root_key.objectid;
39be6e8dc0SBalaji Rao fid->gen = inode->i_generation;
40be6e8dc0SBalaji Rao
41b0b0382bSAl Viro if (parent) {
42be6e8dc0SBalaji Rao u64 parent_root_id;
43be6e8dc0SBalaji Rao
44be6e8dc0SBalaji Rao fid->parent_objectid = BTRFS_I(parent)->location.objectid;
45be6e8dc0SBalaji Rao fid->parent_gen = parent->i_generation;
464fd786e6SMisono Tomohiro parent_root_id = BTRFS_I(parent)->root->root_key.objectid;
47be6e8dc0SBalaji Rao
48be6e8dc0SBalaji Rao if (parent_root_id != fid->root_objectid) {
49be6e8dc0SBalaji Rao fid->parent_root_objectid = parent_root_id;
50be6e8dc0SBalaji Rao len = BTRFS_FID_SIZE_CONNECTABLE_ROOT;
51be6e8dc0SBalaji Rao type = FILEID_BTRFS_WITH_PARENT_ROOT;
52be6e8dc0SBalaji Rao } else {
53be6e8dc0SBalaji Rao len = BTRFS_FID_SIZE_CONNECTABLE;
54be6e8dc0SBalaji Rao type = FILEID_BTRFS_WITH_PARENT;
55be6e8dc0SBalaji Rao }
56be6e8dc0SBalaji Rao }
57be6e8dc0SBalaji Rao
58be6e8dc0SBalaji Rao *max_len = len;
59be6e8dc0SBalaji Rao return type;
60be6e8dc0SBalaji Rao }
61be6e8dc0SBalaji Rao
62b307f06dSDavid Sterba /*
63b307f06dSDavid Sterba * Read dentry of inode with @objectid from filesystem root @root_objectid.
64b307f06dSDavid Sterba *
65b307f06dSDavid Sterba * @sb: the filesystem super block
66b307f06dSDavid Sterba * @objectid: inode objectid
67b307f06dSDavid Sterba * @root_objectid: object id of the subvolume root where to look up the inode
68b307f06dSDavid Sterba * @generation: optional, if not zero, verify that the found inode
69b307f06dSDavid Sterba * generation matches
70b307f06dSDavid Sterba *
71b307f06dSDavid Sterba * Return dentry alias for the inode, otherwise an error. In case the
72b307f06dSDavid Sterba * generation does not match return ESTALE.
73b307f06dSDavid Sterba */
btrfs_get_dentry(struct super_block * sb,u64 objectid,u64 root_objectid,u64 generation)74c0c907a4SMarcos Paulo de Souza struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
75b307f06dSDavid Sterba u64 root_objectid, u64 generation)
76be6e8dc0SBalaji Rao {
77815745cfSAl Viro struct btrfs_fs_info *fs_info = btrfs_sb(sb);
78be6e8dc0SBalaji Rao struct btrfs_root *root;
79be6e8dc0SBalaji Rao struct inode *inode;
8076dda93cSYan, Zheng
8176dda93cSYan, Zheng if (objectid < BTRFS_FIRST_FREE_OBJECTID)
8276dda93cSYan, Zheng return ERR_PTR(-ESTALE);
83be6e8dc0SBalaji Rao
8456e9357aSDavid Sterba root = btrfs_get_fs_root(fs_info, root_objectid, true);
85c75e8394SJosef Bacik if (IS_ERR(root))
86c75e8394SJosef Bacik return ERR_CAST(root);
8776dda93cSYan, Zheng
880202e83fSDavid Sterba inode = btrfs_iget(sb, objectid, root);
8900246528SJosef Bacik btrfs_put_root(root);
90c75e8394SJosef Bacik if (IS_ERR(inode))
91c75e8394SJosef Bacik return ERR_CAST(inode);
9276dda93cSYan, Zheng
93b307f06dSDavid Sterba if (generation != 0 && generation != inode->i_generation) {
94be6e8dc0SBalaji Rao iput(inode);
95be6e8dc0SBalaji Rao return ERR_PTR(-ESTALE);
96be6e8dc0SBalaji Rao }
97be6e8dc0SBalaji Rao
98af53d29aSAl Viro return d_obtain_alias(inode);
99be6e8dc0SBalaji Rao }
100be6e8dc0SBalaji Rao
btrfs_fh_to_parent(struct super_block * sb,struct fid * fh,int fh_len,int fh_type)101be6e8dc0SBalaji Rao static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
102be6e8dc0SBalaji Rao int fh_len, int fh_type)
103be6e8dc0SBalaji Rao {
104be6e8dc0SBalaji Rao struct btrfs_fid *fid = (struct btrfs_fid *) fh;
105be6e8dc0SBalaji Rao u64 objectid, root_objectid;
106be6e8dc0SBalaji Rao u32 generation;
107be6e8dc0SBalaji Rao
108be6e8dc0SBalaji Rao if (fh_type == FILEID_BTRFS_WITH_PARENT) {
1097d35199eSNeilBrown if (fh_len < BTRFS_FID_SIZE_CONNECTABLE)
110be6e8dc0SBalaji Rao return NULL;
111be6e8dc0SBalaji Rao root_objectid = fid->root_objectid;
112be6e8dc0SBalaji Rao } else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) {
1137d35199eSNeilBrown if (fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT)
114be6e8dc0SBalaji Rao return NULL;
115be6e8dc0SBalaji Rao root_objectid = fid->parent_root_objectid;
116be6e8dc0SBalaji Rao } else
117be6e8dc0SBalaji Rao return NULL;
118be6e8dc0SBalaji Rao
119be6e8dc0SBalaji Rao objectid = fid->parent_objectid;
120be6e8dc0SBalaji Rao generation = fid->parent_gen;
121be6e8dc0SBalaji Rao
122b307f06dSDavid Sterba return btrfs_get_dentry(sb, objectid, root_objectid, generation);
123be6e8dc0SBalaji Rao }
124be6e8dc0SBalaji Rao
btrfs_fh_to_dentry(struct super_block * sb,struct fid * fh,int fh_len,int fh_type)125be6e8dc0SBalaji Rao static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
126be6e8dc0SBalaji Rao int fh_len, int fh_type)
127be6e8dc0SBalaji Rao {
128be6e8dc0SBalaji Rao struct btrfs_fid *fid = (struct btrfs_fid *) fh;
129be6e8dc0SBalaji Rao u64 objectid, root_objectid;
130be6e8dc0SBalaji Rao u32 generation;
131be6e8dc0SBalaji Rao
132be6e8dc0SBalaji Rao if ((fh_type != FILEID_BTRFS_WITH_PARENT ||
1337d35199eSNeilBrown fh_len < BTRFS_FID_SIZE_CONNECTABLE) &&
134be6e8dc0SBalaji Rao (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT ||
1357d35199eSNeilBrown fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) &&
136be6e8dc0SBalaji Rao (fh_type != FILEID_BTRFS_WITHOUT_PARENT ||
1377d35199eSNeilBrown fh_len < BTRFS_FID_SIZE_NON_CONNECTABLE))
138be6e8dc0SBalaji Rao return NULL;
139be6e8dc0SBalaji Rao
140be6e8dc0SBalaji Rao objectid = fid->objectid;
141be6e8dc0SBalaji Rao root_objectid = fid->root_objectid;
142be6e8dc0SBalaji Rao generation = fid->gen;
143be6e8dc0SBalaji Rao
144b307f06dSDavid Sterba return btrfs_get_dentry(sb, objectid, root_objectid, generation);
145be6e8dc0SBalaji Rao }
146be6e8dc0SBalaji Rao
btrfs_get_parent(struct dentry * child)147c0c907a4SMarcos Paulo de Souza struct dentry *btrfs_get_parent(struct dentry *child)
148be6e8dc0SBalaji Rao {
1492b0143b5SDavid Howells struct inode *dir = d_inode(child);
1500b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
151be6e8dc0SBalaji Rao struct btrfs_root *root = BTRFS_I(dir)->root;
152be6e8dc0SBalaji Rao struct btrfs_path *path;
153be6e8dc0SBalaji Rao struct extent_buffer *leaf;
15476dda93cSYan, Zheng struct btrfs_root_ref *ref;
15576dda93cSYan, Zheng struct btrfs_key key;
15676dda93cSYan, Zheng struct btrfs_key found_key;
157be6e8dc0SBalaji Rao int ret;
158be6e8dc0SBalaji Rao
159be6e8dc0SBalaji Rao path = btrfs_alloc_path();
1602a29edc6Sliubo if (!path)
1612a29edc6Sliubo return ERR_PTR(-ENOMEM);
162be6e8dc0SBalaji Rao
1634a0cc7caSNikolay Borisov if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) {
16476dda93cSYan, Zheng key.objectid = root->root_key.objectid;
16576dda93cSYan, Zheng key.type = BTRFS_ROOT_BACKREF_KEY;
16687acb4efSDavid Woodhouse key.offset = (u64)-1;
1670b246afaSJeff Mahoney root = fs_info->tree_root;
16876dda93cSYan, Zheng } else {
1694a0cc7caSNikolay Borisov key.objectid = btrfs_ino(BTRFS_I(dir));
17076dda93cSYan, Zheng key.type = BTRFS_INODE_REF_KEY;
17176dda93cSYan, Zheng key.offset = (u64)-1;
17276dda93cSYan, Zheng }
173be6e8dc0SBalaji Rao
17487acb4efSDavid Woodhouse ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
17576dda93cSYan, Zheng if (ret < 0)
17676dda93cSYan, Zheng goto fail;
177*30237d67SDavid Sterba if (ret == 0) {
178*30237d67SDavid Sterba /*
179*30237d67SDavid Sterba * Key with offset of -1 found, there would have to exist an
180*30237d67SDavid Sterba * inode with such number or a root with such id.
181*30237d67SDavid Sterba */
182*30237d67SDavid Sterba ret = -EUCLEAN;
183*30237d67SDavid Sterba goto fail;
184*30237d67SDavid Sterba }
18576dda93cSYan, Zheng
18676dda93cSYan, Zheng if (path->slots[0] == 0) {
18776dda93cSYan, Zheng ret = -ENOENT;
18876dda93cSYan, Zheng goto fail;
18976dda93cSYan, Zheng }
19076dda93cSYan, Zheng
19176dda93cSYan, Zheng path->slots[0]--;
19276dda93cSYan, Zheng leaf = path->nodes[0];
19376dda93cSYan, Zheng
19476dda93cSYan, Zheng btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
19576dda93cSYan, Zheng if (found_key.objectid != key.objectid || found_key.type != key.type) {
19676dda93cSYan, Zheng ret = -ENOENT;
19776dda93cSYan, Zheng goto fail;
19876dda93cSYan, Zheng }
19976dda93cSYan, Zheng
20076dda93cSYan, Zheng if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
20176dda93cSYan, Zheng ref = btrfs_item_ptr(leaf, path->slots[0],
20276dda93cSYan, Zheng struct btrfs_root_ref);
20376dda93cSYan, Zheng key.objectid = btrfs_root_ref_dirid(leaf, ref);
20476dda93cSYan, Zheng } else {
20576dda93cSYan, Zheng key.objectid = found_key.offset;
20676dda93cSYan, Zheng }
20776dda93cSYan, Zheng btrfs_free_path(path);
20876dda93cSYan, Zheng
20976dda93cSYan, Zheng if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
2100b246afaSJeff Mahoney return btrfs_get_dentry(fs_info->sb, key.objectid,
211b307f06dSDavid Sterba found_key.offset, 0);
21276dda93cSYan, Zheng }
21376dda93cSYan, Zheng
2140202e83fSDavid Sterba return d_obtain_alias(btrfs_iget(fs_info->sb, key.objectid, root));
21576dda93cSYan, Zheng fail:
216d54a8390SDavid Woodhouse btrfs_free_path(path);
217d54a8390SDavid Woodhouse return ERR_PTR(ret);
218d54a8390SDavid Woodhouse }
219be6e8dc0SBalaji Rao
btrfs_get_name(struct dentry * parent,char * name,struct dentry * child)2202ede0dafSJosef Bacik static int btrfs_get_name(struct dentry *parent, char *name,
2212ede0dafSJosef Bacik struct dentry *child)
2222ede0dafSJosef Bacik {
2232b0143b5SDavid Howells struct inode *inode = d_inode(child);
2242b0143b5SDavid Howells struct inode *dir = d_inode(parent);
2250b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
2262ede0dafSJosef Bacik struct btrfs_path *path;
2272ede0dafSJosef Bacik struct btrfs_root *root = BTRFS_I(dir)->root;
2282ede0dafSJosef Bacik struct btrfs_inode_ref *iref;
2292ede0dafSJosef Bacik struct btrfs_root_ref *rref;
2302ede0dafSJosef Bacik struct extent_buffer *leaf;
2312ede0dafSJosef Bacik unsigned long name_ptr;
2322ede0dafSJosef Bacik struct btrfs_key key;
2332ede0dafSJosef Bacik int name_len;
2342ede0dafSJosef Bacik int ret;
23533345d01SLi Zefan u64 ino;
2362ede0dafSJosef Bacik
2372ede0dafSJosef Bacik if (!S_ISDIR(dir->i_mode))
2382ede0dafSJosef Bacik return -EINVAL;
2392ede0dafSJosef Bacik
2404a0cc7caSNikolay Borisov ino = btrfs_ino(BTRFS_I(inode));
24133345d01SLi Zefan
2422ede0dafSJosef Bacik path = btrfs_alloc_path();
2432ede0dafSJosef Bacik if (!path)
2442ede0dafSJosef Bacik return -ENOMEM;
2452ede0dafSJosef Bacik
24633345d01SLi Zefan if (ino == BTRFS_FIRST_FREE_OBJECTID) {
2472ede0dafSJosef Bacik key.objectid = BTRFS_I(inode)->root->root_key.objectid;
2482ede0dafSJosef Bacik key.type = BTRFS_ROOT_BACKREF_KEY;
2492ede0dafSJosef Bacik key.offset = (u64)-1;
2500b246afaSJeff Mahoney root = fs_info->tree_root;
2512ede0dafSJosef Bacik } else {
25233345d01SLi Zefan key.objectid = ino;
2534a0cc7caSNikolay Borisov key.offset = btrfs_ino(BTRFS_I(dir));
2542ede0dafSJosef Bacik key.type = BTRFS_INODE_REF_KEY;
2552ede0dafSJosef Bacik }
2562ede0dafSJosef Bacik
2572ede0dafSJosef Bacik ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2582ede0dafSJosef Bacik if (ret < 0) {
2592ede0dafSJosef Bacik btrfs_free_path(path);
2602ede0dafSJosef Bacik return ret;
2612ede0dafSJosef Bacik } else if (ret > 0) {
26233345d01SLi Zefan if (ino == BTRFS_FIRST_FREE_OBJECTID) {
2632ede0dafSJosef Bacik path->slots[0]--;
2642ede0dafSJosef Bacik } else {
2652ede0dafSJosef Bacik btrfs_free_path(path);
2662ede0dafSJosef Bacik return -ENOENT;
2672ede0dafSJosef Bacik }
2682ede0dafSJosef Bacik }
2692ede0dafSJosef Bacik leaf = path->nodes[0];
2702ede0dafSJosef Bacik
27133345d01SLi Zefan if (ino == BTRFS_FIRST_FREE_OBJECTID) {
2722ede0dafSJosef Bacik rref = btrfs_item_ptr(leaf, path->slots[0],
2732ede0dafSJosef Bacik struct btrfs_root_ref);
2742ede0dafSJosef Bacik name_ptr = (unsigned long)(rref + 1);
2752ede0dafSJosef Bacik name_len = btrfs_root_ref_name_len(leaf, rref);
2762ede0dafSJosef Bacik } else {
2772ede0dafSJosef Bacik iref = btrfs_item_ptr(leaf, path->slots[0],
2782ede0dafSJosef Bacik struct btrfs_inode_ref);
2792ede0dafSJosef Bacik name_ptr = (unsigned long)(iref + 1);
2802ede0dafSJosef Bacik name_len = btrfs_inode_ref_name_len(leaf, iref);
2812ede0dafSJosef Bacik }
2822ede0dafSJosef Bacik
2832ede0dafSJosef Bacik read_extent_buffer(leaf, name, name_ptr, name_len);
2842ede0dafSJosef Bacik btrfs_free_path(path);
2852ede0dafSJosef Bacik
2862ede0dafSJosef Bacik /*
2872ede0dafSJosef Bacik * have to add the null termination to make sure that reconnect_path
2882ede0dafSJosef Bacik * gets the right len for strlen
2892ede0dafSJosef Bacik */
2902ede0dafSJosef Bacik name[name_len] = '\0';
2912ede0dafSJosef Bacik
2922ede0dafSJosef Bacik return 0;
2932ede0dafSJosef Bacik }
2942ede0dafSJosef Bacik
295be6e8dc0SBalaji Rao const struct export_operations btrfs_export_ops = {
296be6e8dc0SBalaji Rao .encode_fh = btrfs_encode_fh,
297be6e8dc0SBalaji Rao .fh_to_dentry = btrfs_fh_to_dentry,
298be6e8dc0SBalaji Rao .fh_to_parent = btrfs_fh_to_parent,
299be6e8dc0SBalaji Rao .get_parent = btrfs_get_parent,
3002ede0dafSJosef Bacik .get_name = btrfs_get_name,
301be6e8dc0SBalaji Rao };
302