export.c 7.8 KB
Newer Older
B
Balaji Rao 已提交
1 2 3 4 5 6 7 8 9
#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"

C
Chris Mason 已提交
10 11 12 13 14
#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)
B
Balaji Rao 已提交
15 16 17 18 19 20 21 22 23

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;

24 25
	if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
		*max_len = BTRFS_FID_SIZE_CONNECTABLE;
B
Balaji Rao 已提交
26
		return 255;
27 28 29 30
	} else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
		*max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
		return 255;
	}
B
Balaji Rao 已提交
31 32 33 34

	len  = BTRFS_FID_SIZE_NON_CONNECTABLE;
	type = FILEID_BTRFS_WITHOUT_PARENT;

L
Li Zefan 已提交
35
	fid->objectid = btrfs_ino(inode);
B
Balaji Rao 已提交
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 64 65 66
	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,
67 68
				       u64 root_objectid, u32 generation,
				       int check_generation)
B
Balaji Rao 已提交
69
{
70
	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
B
Balaji Rao 已提交
71 72 73
	struct btrfs_root *root;
	struct inode *inode;
	struct btrfs_key key;
74 75 76 77 78
	int index;
	int err = 0;

	if (objectid < BTRFS_FIRST_FREE_OBJECTID)
		return ERR_PTR(-ESTALE);
B
Balaji Rao 已提交
79

80 81 82 83
	key.objectid = root_objectid;
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	key.offset = (u64)-1;

84 85 86 87 88 89 90 91 92 93 94 95
	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;
	}
96

B
Balaji Rao 已提交
97 98 99 100
	key.objectid = objectid;
	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
	key.offset = 0;

101
	inode = btrfs_iget(sb, &key, root, NULL);
102 103 104 105 106 107
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto fail;
	}

	srcu_read_unlock(&fs_info->subvol_srcu, index);
B
Balaji Rao 已提交
108

109
	if (check_generation && generation != inode->i_generation) {
B
Balaji Rao 已提交
110 111 112 113
		iput(inode);
		return ERR_PTR(-ESTALE);
	}

A
Al Viro 已提交
114
	return d_obtain_alias(inode);
115 116 117
fail:
	srcu_read_unlock(&fs_info->subvol_srcu, index);
	return ERR_PTR(err);
B
Balaji Rao 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
}

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;

141
	return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
B
Balaji Rao 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
}

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;

163
	return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
B
Balaji Rao 已提交
164 165 166 167 168 169 170 171
}

static struct dentry *btrfs_get_parent(struct dentry *child)
{
	struct inode *dir = child->d_inode;
	struct btrfs_root *root = BTRFS_I(dir)->root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
172 173 174
	struct btrfs_root_ref *ref;
	struct btrfs_key key;
	struct btrfs_key found_key;
B
Balaji Rao 已提交
175 176 177
	int ret;

	path = btrfs_alloc_path();
178 179
	if (!path)
		return ERR_PTR(-ENOMEM);
B
Balaji Rao 已提交
180

L
Li Zefan 已提交
181
	if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) {
182 183 184 185 186
		key.objectid = root->root_key.objectid;
		key.type = BTRFS_ROOT_BACKREF_KEY;
		key.offset = (u64)-1;
		root = root->fs_info->tree_root;
	} else {
L
Li Zefan 已提交
187
		key.objectid = btrfs_ino(dir);
188 189 190
		key.type = BTRFS_INODE_REF_KEY;
		key.offset = (u64)-1;
	}
B
Balaji Rao 已提交
191

192
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
193 194 195 196 197 198 199
	if (ret < 0)
		goto fail;

	BUG_ON(ret == 0);
	if (path->slots[0] == 0) {
		ret = -ENOENT;
		goto fail;
200
	}
201 202

	path->slots[0]--;
B
Balaji Rao 已提交
203
	leaf = path->nodes[0];
204 205 206 207 208

	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;
B
Balaji Rao 已提交
209 210
	}

211 212 213 214 215 216 217
	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;
	}
B
Balaji Rao 已提交
218 219
	btrfs_free_path(path);

220 221 222 223
	if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
		return btrfs_get_dentry(root->fs_info->sb, key.objectid,
					found_key.offset, 0, 0);
	}
224

225
	key.type = BTRFS_INODE_ITEM_KEY;
B
Balaji Rao 已提交
226
	key.offset = 0;
A
Al Viro 已提交
227
	return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
228 229 230
fail:
	btrfs_free_path(path);
	return ERR_PTR(ret);
B
Balaji Rao 已提交
231 232
}

J
Josef Bacik 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246
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;
L
Li Zefan 已提交
247
	u64 ino;
J
Josef Bacik 已提交
248 249 250 251 252 253 254

	if (!dir || !inode)
		return -EINVAL;

	if (!S_ISDIR(dir->i_mode))
		return -EINVAL;

L
Li Zefan 已提交
255 256
	ino = btrfs_ino(inode);

J
Josef Bacik 已提交
257 258 259 260 261
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	path->leave_spinning = 1;

L
Li Zefan 已提交
262
	if (ino == BTRFS_FIRST_FREE_OBJECTID) {
J
Josef Bacik 已提交
263 264 265 266 267
		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 {
L
Li Zefan 已提交
268 269
		key.objectid = ino;
		key.offset = btrfs_ino(dir);
J
Josef Bacik 已提交
270 271 272 273 274 275 276 277
		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) {
L
Li Zefan 已提交
278
		if (ino == BTRFS_FIRST_FREE_OBJECTID) {
J
Josef Bacik 已提交
279 280 281 282 283 284 285 286
			path->slots[0]--;
		} else {
			btrfs_free_path(path);
			return -ENOENT;
		}
	}
	leaf = path->nodes[0];

L
Li Zefan 已提交
287 288
	if (ino == BTRFS_FIRST_FREE_OBJECTID) {
		rref = btrfs_item_ptr(leaf, path->slots[0],
J
Josef Bacik 已提交
289
				     struct btrfs_root_ref);
L
Li Zefan 已提交
290 291
		name_ptr = (unsigned long)(rref + 1);
		name_len = btrfs_root_ref_name_len(leaf, rref);
J
Josef Bacik 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	} 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;
}

B
Balaji Rao 已提交
311 312 313 314 315
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,
J
Josef Bacik 已提交
316
	.get_name	= btrfs_get_name,
B
Balaji Rao 已提交
317
};