Skip to content

Commit be6e8dc

Browse files
balajirraochrismason-xx
authored andcommitted
NFS support for btrfs - v3
Date: Mon, 21 Jul 2008 02:01:56 +0530 Here's an implementation of NFS support for btrfs. It relies on the fixes which are going in to 2.6.28 for the NFS readdir/lookup deadlock. This uses the btrfs_iget helper introduced previously. [dwmw2: Tidy up a little, switch to d_obtain_alias() w/compat routine, change fh_type, store parent's root object ID where needed, fix some get_parent() and fs_to_dentry() bugs] Signed-off-by: Balaji Rao <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 1a54ef8 commit be6e8dc

File tree

5 files changed

+247
-1
lines changed

5 files changed

+247
-1
lines changed

fs/btrfs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
77
transaction.o bit-radix.o inode.o file.o tree-defrag.o \
88
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
99
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
10-
ref-cache.o
10+
ref-cache.o export.o
1111

1212
btrfs-$(CONFIG_FS_POSIX_ACL) += acl.o
1313
else

fs/btrfs/compat.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@
55
#define trylock_page(page) (!TestSetPageLocked(page))
66
#endif
77

8+
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
9+
static inline struct dentry *d_obtain_alias(struct inode *inode)
10+
{
11+
struct dentry *d;
12+
13+
if (!inode)
14+
return NULL;
15+
if (IS_ERR(inode))
16+
return ERR_CAST(inode);
17+
18+
d = d_alloc_anon(inode);
19+
if (!d)
20+
iput(inode);
21+
return d;
22+
}
23+
#endif
24+
825
/*
926
* Even if AppArmor isn't enabled, it still has different prototypes.
1027
* Add more distro/version pairs here to declare which has AppArmor applied.

fs/btrfs/export.c

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#include <linux/fs.h>
2+
#include <linux/types.h>
3+
#include "ctree.h"
4+
#include "disk-io.h"
5+
#include "btrfs_inode.h"
6+
#include "print-tree.h"
7+
#include "export.h"
8+
#include "compat.h"
9+
10+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
11+
#define FILEID_BTRFS_WITHOUT_PARENT 0x4d
12+
#define FILEID_BTRFS_WITH_PARENT 0x4e
13+
#define FILEID_BTRFS_WITH_PARENT_ROOT 0x4f
14+
#endif
15+
16+
#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, parent_objectid)/4)
17+
#define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, parent_root_objectid)/4)
18+
#define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid)/4)
19+
20+
static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
21+
int connectable)
22+
{
23+
struct btrfs_fid *fid = (struct btrfs_fid *)fh;
24+
struct inode *inode = dentry->d_inode;
25+
int len = *max_len;
26+
int type;
27+
28+
if ((len < BTRFS_FID_SIZE_NON_CONNECTABLE) ||
29+
(connectable && len < BTRFS_FID_SIZE_CONNECTABLE))
30+
return 255;
31+
32+
len = BTRFS_FID_SIZE_NON_CONNECTABLE;
33+
type = FILEID_BTRFS_WITHOUT_PARENT;
34+
35+
fid->objectid = BTRFS_I(inode)->location.objectid;
36+
fid->root_objectid = BTRFS_I(inode)->root->objectid;
37+
fid->gen = inode->i_generation;
38+
39+
if (connectable && !S_ISDIR(inode->i_mode)) {
40+
struct inode *parent;
41+
u64 parent_root_id;
42+
43+
spin_lock(&dentry->d_lock);
44+
45+
parent = dentry->d_parent->d_inode;
46+
fid->parent_objectid = BTRFS_I(parent)->location.objectid;
47+
fid->parent_gen = parent->i_generation;
48+
parent_root_id = BTRFS_I(parent)->root->objectid;
49+
50+
spin_unlock(&dentry->d_lock);
51+
52+
if (parent_root_id != fid->root_objectid) {
53+
fid->parent_root_objectid = parent_root_id;
54+
len = BTRFS_FID_SIZE_CONNECTABLE_ROOT;
55+
type = FILEID_BTRFS_WITH_PARENT_ROOT;
56+
} else {
57+
len = BTRFS_FID_SIZE_CONNECTABLE;
58+
type = FILEID_BTRFS_WITH_PARENT;
59+
}
60+
}
61+
62+
*max_len = len;
63+
return type;
64+
}
65+
66+
static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
67+
u64 root_objectid, u32 generation)
68+
{
69+
struct btrfs_root *root;
70+
struct inode *inode;
71+
struct dentry *result;
72+
struct btrfs_key key;
73+
74+
key.objectid = objectid;
75+
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
76+
key.offset = 0;
77+
78+
root = btrfs_lookup_fs_root(btrfs_sb(sb)->fs_info, root_objectid);
79+
inode = btrfs_iget(sb, &key, root, NULL);
80+
if (IS_ERR(inode))
81+
return (void *)inode;
82+
83+
if (generation != inode->i_generation) {
84+
iput(inode);
85+
return ERR_PTR(-ESTALE);
86+
}
87+
88+
result = d_obtain_alias(inode);
89+
if (!result)
90+
return ERR_PTR(-ENOMEM);
91+
92+
return result;
93+
}
94+
95+
static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
96+
int fh_len, int fh_type)
97+
{
98+
struct btrfs_fid *fid = (struct btrfs_fid *) fh;
99+
u64 objectid, root_objectid;
100+
u32 generation;
101+
102+
if (fh_type == FILEID_BTRFS_WITH_PARENT) {
103+
if (fh_len != BTRFS_FID_SIZE_CONNECTABLE)
104+
return NULL;
105+
root_objectid = fid->root_objectid;
106+
} else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) {
107+
if (fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT)
108+
return NULL;
109+
root_objectid = fid->parent_root_objectid;
110+
} else
111+
return NULL;
112+
113+
objectid = fid->parent_objectid;
114+
generation = fid->parent_gen;
115+
116+
return btrfs_get_dentry(sb, objectid, root_objectid, generation);
117+
}
118+
119+
static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
120+
int fh_len, int fh_type)
121+
{
122+
struct btrfs_fid *fid = (struct btrfs_fid *) fh;
123+
u64 objectid, root_objectid;
124+
u32 generation;
125+
126+
if ((fh_type != FILEID_BTRFS_WITH_PARENT ||
127+
fh_len != BTRFS_FID_SIZE_CONNECTABLE) &&
128+
(fh_type != FILEID_BTRFS_WITH_PARENT_ROOT ||
129+
fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT) &&
130+
(fh_type != FILEID_BTRFS_WITHOUT_PARENT ||
131+
fh_len != BTRFS_FID_SIZE_NON_CONNECTABLE))
132+
return NULL;
133+
134+
objectid = fid->objectid;
135+
root_objectid = fid->root_objectid;
136+
generation = fid->gen;
137+
138+
return btrfs_get_dentry(sb, objectid, root_objectid, generation);
139+
}
140+
141+
static struct dentry *btrfs_get_parent(struct dentry *child)
142+
{
143+
struct inode *dir = child->d_inode;
144+
struct inode *inode;
145+
struct dentry *parent;
146+
struct btrfs_root *root = BTRFS_I(dir)->root;
147+
struct btrfs_key key;
148+
struct btrfs_path *path;
149+
struct extent_buffer *leaf;
150+
u32 nritems;
151+
int slot;
152+
u64 objectid;
153+
int ret;
154+
155+
path = btrfs_alloc_path();
156+
157+
key.objectid = dir->i_ino;
158+
btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
159+
key.offset = 0;
160+
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
161+
BUG_ON(ret == 0);
162+
ret = 0;
163+
164+
leaf = path->nodes[0];
165+
slot = path->slots[0];
166+
nritems = btrfs_header_nritems(leaf);
167+
if (slot >= nritems) {
168+
ret = btrfs_next_leaf(root, path);
169+
if (ret) {
170+
btrfs_free_path(path);
171+
goto out;
172+
}
173+
leaf = path->nodes[0];
174+
slot = path->slots[0];
175+
}
176+
177+
btrfs_free_path(path);
178+
179+
btrfs_item_key_to_cpu(leaf, &key, slot);
180+
if (key.objectid != dir->i_ino || key.type != BTRFS_INODE_REF_KEY)
181+
goto out;
182+
183+
objectid = key.offset;
184+
185+
/* Build a new key for the inode item */
186+
key.objectid = objectid;
187+
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
188+
key.offset = 0;
189+
190+
inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
191+
192+
parent = d_obtain_alias(inode);
193+
if (!parent)
194+
parent = ERR_PTR(-ENOMEM);
195+
196+
return parent;
197+
198+
out:
199+
btrfs_free_path(path);
200+
return ERR_PTR(-EINVAL);
201+
}
202+
203+
const struct export_operations btrfs_export_ops = {
204+
.encode_fh = btrfs_encode_fh,
205+
.fh_to_dentry = btrfs_fh_to_dentry,
206+
.fh_to_parent = btrfs_fh_to_parent,
207+
.get_parent = btrfs_get_parent,
208+
};

fs/btrfs/export.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef BTRFS_EXPORT_H
2+
#define BTRFS_EXPORT_H
3+
4+
#include <linux/exportfs.h>
5+
6+
extern const struct export_operations btrfs_export_ops;
7+
8+
struct btrfs_fid {
9+
u64 objectid;
10+
u64 root_objectid;
11+
u32 gen;
12+
13+
u64 parent_objectid;
14+
u32 parent_gen;
15+
16+
u64 parent_root_objectid;
17+
} __attribute__ ((packed));
18+
19+
#endif

fs/btrfs/super.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "xattr.h"
4747
#include "volumes.h"
4848
#include "version.h"
49+
#include "export.h"
4950

5051
#define BTRFS_SUPER_MAGIC 0x9123683E
5152

@@ -303,6 +304,7 @@ static int btrfs_fill_super(struct super_block * sb,
303304
sb->s_maxbytes = MAX_LFS_FILESIZE;
304305
sb->s_magic = BTRFS_SUPER_MAGIC;
305306
sb->s_op = &btrfs_super_ops;
307+
sb->s_export_op = &btrfs_export_ops;
306308
sb->s_xattr = btrfs_xattr_handlers;
307309
sb->s_time_gran = 1;
308310
sb->s_flags |= MS_POSIXACL;

0 commit comments

Comments
 (0)