diff options
-rw-r--r-- | fs/gfs2/Makefile | 2 | ||||
-rw-r--r-- | fs/gfs2/acl.c | 104 | ||||
-rw-r--r-- | fs/gfs2/eaops.c | 157 | ||||
-rw-r--r-- | fs/gfs2/eaops.h | 30 | ||||
-rw-r--r-- | fs/gfs2/eattr.c | 421 | ||||
-rw-r--r-- | fs/gfs2/eattr.h | 52 | ||||
-rw-r--r-- | fs/gfs2/file.c | 1 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 12 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_inode.c | 78 | ||||
-rw-r--r-- | fs/gfs2/super.h | 1 |
11 files changed, 333 insertions, 526 deletions
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 3da2f1f4f738..2a4fd894858a 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | EXTRA_CFLAGS := -I$(src) | 1 | EXTRA_CFLAGS := -I$(src) |
2 | obj-$(CONFIG_GFS2_FS) += gfs2.o | 2 | obj-$(CONFIG_GFS2_FS) += gfs2.o |
3 | gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \ | 3 | gfs2-y := acl.o bmap.o dir.o eattr.o glock.o \ |
4 | glops.o inode.o log.o lops.o main.o meta_io.o \ | 4 | glops.o inode.o log.o lops.o main.o meta_io.o \ |
5 | aops.o dentry.o export.o file.o \ | 5 | aops.o dentry.o export.o file.o \ |
6 | ops_fstype.o ops_inode.o quota.o \ | 6 | ops_fstype.o ops_inode.o quota.o \ |
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index fa881bdc3d85..f6777f167260 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include "gfs2.h" | 19 | #include "gfs2.h" |
20 | #include "incore.h" | 20 | #include "incore.h" |
21 | #include "acl.h" | 21 | #include "acl.h" |
22 | #include "eaops.h" | ||
23 | #include "eattr.h" | 22 | #include "eattr.h" |
24 | #include "glock.h" | 23 | #include "glock.h" |
25 | #include "inode.h" | 24 | #include "inode.h" |
@@ -31,8 +30,7 @@ | |||
31 | #define ACL_DEFAULT 0 | 30 | #define ACL_DEFAULT 0 |
32 | 31 | ||
33 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, | 32 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, |
34 | struct gfs2_ea_request *er, | 33 | struct gfs2_ea_request *er, int *remove, mode_t *mode) |
35 | int *remove, mode_t *mode) | ||
36 | { | 34 | { |
37 | struct posix_acl *acl; | 35 | struct posix_acl *acl; |
38 | int error; | 36 | int error; |
@@ -83,30 +81,20 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) | |||
83 | return 0; | 81 | return 0; |
84 | } | 82 | } |
85 | 83 | ||
86 | static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | 84 | static int acl_get(struct gfs2_inode *ip, const char *name, |
87 | struct gfs2_ea_location *el, char **data, unsigned int *len) | 85 | struct posix_acl **acl, struct gfs2_ea_location *el, |
86 | char **datap, unsigned int *lenp) | ||
88 | { | 87 | { |
89 | struct gfs2_ea_request er; | 88 | char *data; |
90 | struct gfs2_ea_location el_this; | 89 | unsigned int len; |
91 | int error; | 90 | int error; |
92 | 91 | ||
92 | el->el_bh = NULL; | ||
93 | |||
93 | if (!ip->i_eattr) | 94 | if (!ip->i_eattr) |
94 | return 0; | 95 | return 0; |
95 | 96 | ||
96 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 97 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el); |
97 | if (access) { | ||
98 | er.er_name = GFS2_POSIX_ACL_ACCESS; | ||
99 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
100 | } else { | ||
101 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | ||
102 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | ||
103 | } | ||
104 | er.er_type = GFS2_EATYPE_SYS; | ||
105 | |||
106 | if (!el) | ||
107 | el = &el_this; | ||
108 | |||
109 | error = gfs2_ea_find(ip, &er, el); | ||
110 | if (error) | 98 | if (error) |
111 | return error; | 99 | return error; |
112 | if (!el->el_ea) | 100 | if (!el->el_ea) |
@@ -114,32 +102,31 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | |||
114 | if (!GFS2_EA_DATA_LEN(el->el_ea)) | 102 | if (!GFS2_EA_DATA_LEN(el->el_ea)) |
115 | goto out; | 103 | goto out; |
116 | 104 | ||
117 | er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); | 105 | len = GFS2_EA_DATA_LEN(el->el_ea); |
118 | er.er_data = kmalloc(er.er_data_len, GFP_NOFS); | 106 | data = kmalloc(len, GFP_NOFS); |
119 | error = -ENOMEM; | 107 | error = -ENOMEM; |
120 | if (!er.er_data) | 108 | if (!data) |
121 | goto out; | 109 | goto out; |
122 | 110 | ||
123 | error = gfs2_ea_get_copy(ip, el, er.er_data); | 111 | error = gfs2_ea_get_copy(ip, el, data, len); |
124 | if (error) | 112 | if (error < 0) |
125 | goto out_kfree; | 113 | goto out_kfree; |
114 | error = 0; | ||
126 | 115 | ||
127 | if (acl) { | 116 | if (acl) { |
128 | *acl = posix_acl_from_xattr(er.er_data, er.er_data_len); | 117 | *acl = posix_acl_from_xattr(data, len); |
129 | if (IS_ERR(*acl)) | 118 | if (IS_ERR(*acl)) |
130 | error = PTR_ERR(*acl); | 119 | error = PTR_ERR(*acl); |
131 | } | 120 | } |
132 | 121 | ||
133 | out_kfree: | 122 | out_kfree: |
134 | if (error || !data) | 123 | if (error || !datap) { |
135 | kfree(er.er_data); | 124 | kfree(data); |
136 | else { | 125 | } else { |
137 | *data = er.er_data; | 126 | *datap = data; |
138 | *len = er.er_data_len; | 127 | *lenp = len; |
139 | } | 128 | } |
140 | out: | 129 | out: |
141 | if (error || el == &el_this) | ||
142 | brelse(el->el_bh); | ||
143 | return error; | 130 | return error; |
144 | } | 131 | } |
145 | 132 | ||
@@ -153,10 +140,12 @@ out: | |||
153 | 140 | ||
154 | int gfs2_check_acl(struct inode *inode, int mask) | 141 | int gfs2_check_acl(struct inode *inode, int mask) |
155 | { | 142 | { |
143 | struct gfs2_ea_location el; | ||
156 | struct posix_acl *acl = NULL; | 144 | struct posix_acl *acl = NULL; |
157 | int error; | 145 | int error; |
158 | 146 | ||
159 | error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); | 147 | error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL); |
148 | brelse(el.el_bh); | ||
160 | if (error) | 149 | if (error) |
161 | return error; | 150 | return error; |
162 | 151 | ||
@@ -196,10 +185,12 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) | |||
196 | 185 | ||
197 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | 186 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) |
198 | { | 187 | { |
188 | struct gfs2_ea_location el; | ||
199 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 189 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
200 | struct posix_acl *acl = NULL, *clone; | 190 | struct posix_acl *acl = NULL, *clone; |
201 | struct gfs2_ea_request er; | ||
202 | mode_t mode = ip->i_inode.i_mode; | 191 | mode_t mode = ip->i_inode.i_mode; |
192 | char *data = NULL; | ||
193 | unsigned int len; | ||
203 | int error; | 194 | int error; |
204 | 195 | ||
205 | if (!sdp->sd_args.ar_posix_acl) | 196 | if (!sdp->sd_args.ar_posix_acl) |
@@ -207,11 +198,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
207 | if (S_ISLNK(ip->i_inode.i_mode)) | 198 | if (S_ISLNK(ip->i_inode.i_mode)) |
208 | return 0; | 199 | return 0; |
209 | 200 | ||
210 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 201 | error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len); |
211 | er.er_type = GFS2_EATYPE_SYS; | 202 | brelse(el.el_bh); |
212 | |||
213 | error = acl_get(dip, ACL_DEFAULT, &acl, NULL, | ||
214 | &er.er_data, &er.er_data_len); | ||
215 | if (error) | 203 | if (error) |
216 | return error; | 204 | return error; |
217 | if (!acl) { | 205 | if (!acl) { |
@@ -229,9 +217,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
229 | acl = clone; | 217 | acl = clone; |
230 | 218 | ||
231 | if (S_ISDIR(ip->i_inode.i_mode)) { | 219 | if (S_ISDIR(ip->i_inode.i_mode)) { |
232 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | 220 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, |
233 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | 221 | GFS2_POSIX_ACL_DEFAULT, data, len, 0); |
234 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
235 | if (error) | 222 | if (error) |
236 | goto out; | 223 | goto out; |
237 | } | 224 | } |
@@ -239,21 +226,19 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
239 | error = posix_acl_create_masq(acl, &mode); | 226 | error = posix_acl_create_masq(acl, &mode); |
240 | if (error < 0) | 227 | if (error < 0) |
241 | goto out; | 228 | goto out; |
242 | if (error > 0) { | 229 | if (error == 0) |
243 | er.er_name = GFS2_POSIX_ACL_ACCESS; | 230 | goto munge; |
244 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
245 | posix_acl_to_xattr(acl, er.er_data, er.er_data_len); | ||
246 | er.er_mode = mode; | ||
247 | er.er_flags = GFS2_ERF_MODE; | ||
248 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
249 | if (error) | ||
250 | goto out; | ||
251 | } else | ||
252 | munge_mode(ip, mode); | ||
253 | 231 | ||
232 | posix_acl_to_xattr(acl, data, len); | ||
233 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, | ||
234 | GFS2_POSIX_ACL_ACCESS, data, len, 0); | ||
235 | if (error) | ||
236 | goto out; | ||
237 | munge: | ||
238 | error = munge_mode(ip, mode); | ||
254 | out: | 239 | out: |
255 | posix_acl_release(acl); | 240 | posix_acl_release(acl); |
256 | kfree(er.er_data); | 241 | kfree(data); |
257 | return error; | 242 | return error; |
258 | } | 243 | } |
259 | 244 | ||
@@ -265,9 +250,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
265 | unsigned int len; | 250 | unsigned int len; |
266 | int error; | 251 | int error; |
267 | 252 | ||
268 | error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len); | 253 | error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len); |
269 | if (error) | 254 | if (error) |
270 | return error; | 255 | goto out_brelse; |
271 | if (!acl) | 256 | if (!acl) |
272 | return gfs2_setattr_simple(ip, attr); | 257 | return gfs2_setattr_simple(ip, attr); |
273 | 258 | ||
@@ -286,8 +271,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
286 | 271 | ||
287 | out: | 272 | out: |
288 | posix_acl_release(acl); | 273 | posix_acl_release(acl); |
289 | brelse(el.el_bh); | ||
290 | kfree(data); | 274 | kfree(data); |
275 | out_brelse: | ||
276 | brelse(el.el_bh); | ||
291 | return error; | 277 | return error; |
292 | } | 278 | } |
293 | 279 | ||
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c deleted file mode 100644 index dee9b03e5b37..000000000000 --- a/fs/gfs2/eaops.c +++ /dev/null | |||
@@ -1,157 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License version 2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/slab.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/completion.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | #include <linux/capability.h> | ||
15 | #include <linux/xattr.h> | ||
16 | #include <linux/gfs2_ondisk.h> | ||
17 | #include <asm/uaccess.h> | ||
18 | |||
19 | #include "gfs2.h" | ||
20 | #include "incore.h" | ||
21 | #include "acl.h" | ||
22 | #include "eaops.h" | ||
23 | #include "eattr.h" | ||
24 | #include "util.h" | ||
25 | |||
26 | /** | ||
27 | * gfs2_ea_name2type - get the type of the ea, and truncate type from the name | ||
28 | * @namep: ea name, possibly with type appended | ||
29 | * | ||
30 | * Returns: GFS2_EATYPE_XXX | ||
31 | */ | ||
32 | |||
33 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name) | ||
34 | { | ||
35 | unsigned int type; | ||
36 | |||
37 | if (strncmp(name, "system.", 7) == 0) { | ||
38 | type = GFS2_EATYPE_SYS; | ||
39 | if (truncated_name) | ||
40 | *truncated_name = name + sizeof("system.") - 1; | ||
41 | } else if (strncmp(name, "user.", 5) == 0) { | ||
42 | type = GFS2_EATYPE_USR; | ||
43 | if (truncated_name) | ||
44 | *truncated_name = name + sizeof("user.") - 1; | ||
45 | } else if (strncmp(name, "security.", 9) == 0) { | ||
46 | type = GFS2_EATYPE_SECURITY; | ||
47 | if (truncated_name) | ||
48 | *truncated_name = name + sizeof("security.") - 1; | ||
49 | } else { | ||
50 | type = GFS2_EATYPE_UNUSED; | ||
51 | if (truncated_name) | ||
52 | *truncated_name = NULL; | ||
53 | } | ||
54 | |||
55 | return type; | ||
56 | } | ||
57 | |||
58 | static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
59 | { | ||
60 | if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) && | ||
61 | !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) && | ||
62 | !capable(CAP_SYS_ADMIN)) | ||
63 | return -EPERM; | ||
64 | |||
65 | if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 && | ||
66 | (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) || | ||
67 | GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) | ||
68 | return -EOPNOTSUPP; | ||
69 | |||
70 | return gfs2_ea_get_i(ip, er); | ||
71 | } | ||
72 | |||
73 | static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
74 | { | ||
75 | int remove = 0; | ||
76 | int error; | ||
77 | |||
78 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
79 | if (!(er->er_flags & GFS2_ERF_MODE)) { | ||
80 | er->er_mode = ip->i_inode.i_mode; | ||
81 | er->er_flags |= GFS2_ERF_MODE; | ||
82 | } | ||
83 | error = gfs2_acl_validate_set(ip, 1, er, | ||
84 | &remove, &er->er_mode); | ||
85 | if (error) | ||
86 | return error; | ||
87 | error = gfs2_ea_set_i(ip, er); | ||
88 | if (error) | ||
89 | return error; | ||
90 | if (remove) | ||
91 | gfs2_ea_remove_i(ip, er); | ||
92 | return 0; | ||
93 | |||
94 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
95 | error = gfs2_acl_validate_set(ip, 0, er, | ||
96 | &remove, NULL); | ||
97 | if (error) | ||
98 | return error; | ||
99 | if (!remove) | ||
100 | error = gfs2_ea_set_i(ip, er); | ||
101 | else { | ||
102 | error = gfs2_ea_remove_i(ip, er); | ||
103 | if (error == -ENODATA) | ||
104 | error = 0; | ||
105 | } | ||
106 | return error; | ||
107 | } | ||
108 | |||
109 | return -EPERM; | ||
110 | } | ||
111 | |||
112 | static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
113 | { | ||
114 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
115 | int error = gfs2_acl_validate_remove(ip, 1); | ||
116 | if (error) | ||
117 | return error; | ||
118 | |||
119 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
120 | int error = gfs2_acl_validate_remove(ip, 0); | ||
121 | if (error) | ||
122 | return error; | ||
123 | |||
124 | } else | ||
125 | return -EPERM; | ||
126 | |||
127 | return gfs2_ea_remove_i(ip, er); | ||
128 | } | ||
129 | |||
130 | static const struct gfs2_eattr_operations gfs2_user_eaops = { | ||
131 | .eo_get = gfs2_ea_get_i, | ||
132 | .eo_set = gfs2_ea_set_i, | ||
133 | .eo_remove = gfs2_ea_remove_i, | ||
134 | .eo_name = "user", | ||
135 | }; | ||
136 | |||
137 | const struct gfs2_eattr_operations gfs2_system_eaops = { | ||
138 | .eo_get = system_eo_get, | ||
139 | .eo_set = system_eo_set, | ||
140 | .eo_remove = system_eo_remove, | ||
141 | .eo_name = "system", | ||
142 | }; | ||
143 | |||
144 | static const struct gfs2_eattr_operations gfs2_security_eaops = { | ||
145 | .eo_get = gfs2_ea_get_i, | ||
146 | .eo_set = gfs2_ea_set_i, | ||
147 | .eo_remove = gfs2_ea_remove_i, | ||
148 | .eo_name = "security", | ||
149 | }; | ||
150 | |||
151 | const struct gfs2_eattr_operations *gfs2_ea_ops[] = { | ||
152 | NULL, | ||
153 | &gfs2_user_eaops, | ||
154 | &gfs2_system_eaops, | ||
155 | &gfs2_security_eaops, | ||
156 | }; | ||
157 | |||
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h deleted file mode 100644 index da2f7fbbb40d..000000000000 --- a/fs/gfs2/eaops.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License version 2. | ||
8 | */ | ||
9 | |||
10 | #ifndef __EAOPS_DOT_H__ | ||
11 | #define __EAOPS_DOT_H__ | ||
12 | |||
13 | struct gfs2_ea_request; | ||
14 | struct gfs2_inode; | ||
15 | |||
16 | struct gfs2_eattr_operations { | ||
17 | int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
18 | int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
19 | int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
20 | char *eo_name; | ||
21 | }; | ||
22 | |||
23 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); | ||
24 | |||
25 | extern const struct gfs2_eattr_operations gfs2_system_eaops; | ||
26 | |||
27 | extern const struct gfs2_eattr_operations *gfs2_ea_ops[]; | ||
28 | |||
29 | #endif /* __EAOPS_DOT_H__ */ | ||
30 | |||
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index 07ea9529adda..d9a9e260d5ac 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include "gfs2.h" | 18 | #include "gfs2.h" |
19 | #include "incore.h" | 19 | #include "incore.h" |
20 | #include "acl.h" | 20 | #include "acl.h" |
21 | #include "eaops.h" | ||
22 | #include "eattr.h" | 21 | #include "eattr.h" |
23 | #include "glock.h" | 22 | #include "glock.h" |
24 | #include "inode.h" | 23 | #include "inode.h" |
@@ -38,26 +37,32 @@ | |||
38 | * Returns: 1 if the EA should be stuffed | 37 | * Returns: 1 if the EA should be stuffed |
39 | */ | 38 | */ |
40 | 39 | ||
41 | static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er, | 40 | static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize, |
42 | unsigned int *size) | 41 | unsigned int *size) |
43 | { | 42 | { |
44 | *size = GFS2_EAREQ_SIZE_STUFFED(er); | 43 | unsigned int jbsize = sdp->sd_jbsize; |
45 | if (*size <= sdp->sd_jbsize) | 44 | |
45 | /* Stuffed */ | ||
46 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8); | ||
47 | |||
48 | if (*size <= jbsize) | ||
46 | return 1; | 49 | return 1; |
47 | 50 | ||
48 | *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er); | 51 | /* Unstuffed */ |
52 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + | ||
53 | (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8); | ||
49 | 54 | ||
50 | return 0; | 55 | return 0; |
51 | } | 56 | } |
52 | 57 | ||
53 | static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) | 58 | static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) |
54 | { | 59 | { |
55 | unsigned int size; | 60 | unsigned int size; |
56 | 61 | ||
57 | if (er->er_data_len > GFS2_EA_MAX_DATA_LEN) | 62 | if (dsize > GFS2_EA_MAX_DATA_LEN) |
58 | return -ERANGE; | 63 | return -ERANGE; |
59 | 64 | ||
60 | ea_calc_size(sdp, er, &size); | 65 | ea_calc_size(sdp, nsize, dsize, &size); |
61 | 66 | ||
62 | /* This can only happen with 512 byte blocks */ | 67 | /* This can only happen with 512 byte blocks */ |
63 | if (size > sdp->sd_jbsize) | 68 | if (size > sdp->sd_jbsize) |
@@ -151,7 +156,9 @@ out: | |||
151 | } | 156 | } |
152 | 157 | ||
153 | struct ea_find { | 158 | struct ea_find { |
154 | struct gfs2_ea_request *ef_er; | 159 | int type; |
160 | const char *name; | ||
161 | size_t namel; | ||
155 | struct gfs2_ea_location *ef_el; | 162 | struct gfs2_ea_location *ef_el; |
156 | }; | 163 | }; |
157 | 164 | ||
@@ -160,14 +167,13 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
160 | void *private) | 167 | void *private) |
161 | { | 168 | { |
162 | struct ea_find *ef = private; | 169 | struct ea_find *ef = private; |
163 | struct gfs2_ea_request *er = ef->ef_er; | ||
164 | 170 | ||
165 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | 171 | if (ea->ea_type == GFS2_EATYPE_UNUSED) |
166 | return 0; | 172 | return 0; |
167 | 173 | ||
168 | if (ea->ea_type == er->er_type) { | 174 | if (ea->ea_type == ef->type) { |
169 | if (ea->ea_name_len == er->er_name_len && | 175 | if (ea->ea_name_len == ef->namel && |
170 | !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) { | 176 | !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) { |
171 | struct gfs2_ea_location *el = ef->ef_el; | 177 | struct gfs2_ea_location *el = ef->ef_el; |
172 | get_bh(bh); | 178 | get_bh(bh); |
173 | el->el_bh = bh; | 179 | el->el_bh = bh; |
@@ -180,13 +186,15 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
180 | return 0; | 186 | return 0; |
181 | } | 187 | } |
182 | 188 | ||
183 | int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 189 | int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
184 | struct gfs2_ea_location *el) | 190 | struct gfs2_ea_location *el) |
185 | { | 191 | { |
186 | struct ea_find ef; | 192 | struct ea_find ef; |
187 | int error; | 193 | int error; |
188 | 194 | ||
189 | ef.ef_er = er; | 195 | ef.type = type; |
196 | ef.name = name; | ||
197 | ef.namel = strlen(name); | ||
190 | ef.ef_el = el; | 198 | ef.ef_el = el; |
191 | 199 | ||
192 | memset(el, 0, sizeof(struct gfs2_ea_location)); | 200 | memset(el, 0, sizeof(struct gfs2_ea_location)); |
@@ -344,6 +352,20 @@ struct ea_list { | |||
344 | unsigned int ei_size; | 352 | unsigned int ei_size; |
345 | }; | 353 | }; |
346 | 354 | ||
355 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
356 | { | ||
357 | switch (ea->ea_type) { | ||
358 | case GFS2_EATYPE_USR: | ||
359 | return 5 + ea->ea_name_len + 1; | ||
360 | case GFS2_EATYPE_SYS: | ||
361 | return 7 + ea->ea_name_len + 1; | ||
362 | case GFS2_EATYPE_SECURITY: | ||
363 | return 9 + ea->ea_name_len + 1; | ||
364 | default: | ||
365 | return 0; | ||
366 | } | ||
367 | } | ||
368 | |||
347 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | 369 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, |
348 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | 370 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, |
349 | void *private) | 371 | void *private) |
@@ -392,21 +414,25 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
392 | } | 414 | } |
393 | 415 | ||
394 | /** | 416 | /** |
395 | * gfs2_ea_list - | 417 | * gfs2_listxattr - List gfs2 extended attributes |
396 | * @ip: | 418 | * @dentry: The dentry whose inode we are interested in |
397 | * @er: | 419 | * @buffer: The buffer to write the results |
420 | * @size: The size of the buffer | ||
398 | * | 421 | * |
399 | * Returns: actual size of data on success, -errno on error | 422 | * Returns: actual size of data on success, -errno on error |
400 | */ | 423 | */ |
401 | 424 | ||
402 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 425 | ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) |
403 | { | 426 | { |
427 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
428 | struct gfs2_ea_request er; | ||
404 | struct gfs2_holder i_gh; | 429 | struct gfs2_holder i_gh; |
405 | int error; | 430 | int error; |
406 | 431 | ||
407 | if (!er->er_data || !er->er_data_len) { | 432 | memset(&er, 0, sizeof(struct gfs2_ea_request)); |
408 | er->er_data = NULL; | 433 | if (size) { |
409 | er->er_data_len = 0; | 434 | er.er_data = buffer; |
435 | er.er_data_len = size; | ||
410 | } | 436 | } |
411 | 437 | ||
412 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 438 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
@@ -414,7 +440,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
414 | return error; | 440 | return error; |
415 | 441 | ||
416 | if (ip->i_eattr) { | 442 | if (ip->i_eattr) { |
417 | struct ea_list ei = { .ei_er = er, .ei_size = 0 }; | 443 | struct ea_list ei = { .ei_er = &er, .ei_size = 0 }; |
418 | 444 | ||
419 | error = ea_foreach(ip, ea_list_i, &ei); | 445 | error = ea_foreach(ip, ea_list_i, &ei); |
420 | if (!error) | 446 | if (!error) |
@@ -491,84 +517,61 @@ out: | |||
491 | } | 517 | } |
492 | 518 | ||
493 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 519 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
494 | char *data) | 520 | char *data, size_t size) |
495 | { | 521 | { |
522 | int ret; | ||
523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | ||
524 | if (len > size) | ||
525 | return -ERANGE; | ||
526 | |||
496 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { | 527 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { |
497 | memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea)); | 528 | memcpy(data, GFS2_EA2DATA(el->el_ea), len); |
498 | return 0; | 529 | return len; |
499 | } else | 530 | } |
500 | return ea_get_unstuffed(ip, el->el_ea, data); | 531 | ret = ea_get_unstuffed(ip, el->el_ea, data); |
532 | if (ret < 0) | ||
533 | return ret; | ||
534 | return len; | ||
501 | } | 535 | } |
502 | 536 | ||
503 | /** | 537 | /** |
504 | * gfs2_ea_get_i - | 538 | * gfs2_xattr_get - Get a GFS2 extended attribute |
505 | * @ip: The GFS2 inode | 539 | * @inode: The inode |
506 | * @er: The request structure | 540 | * @type: The type of extended attribute |
541 | * @name: The name of the extended attribute | ||
542 | * @buffer: The buffer to write the result into | ||
543 | * @size: The size of the buffer | ||
507 | * | 544 | * |
508 | * Returns: actual size of data on success, -errno on error | 545 | * Returns: actual size of data on success, -errno on error |
509 | */ | 546 | */ |
510 | 547 | ||
511 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 548 | int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
549 | void *buffer, size_t size) | ||
512 | { | 550 | { |
551 | struct gfs2_inode *ip = GFS2_I(inode); | ||
513 | struct gfs2_ea_location el; | 552 | struct gfs2_ea_location el; |
514 | int error; | 553 | int error; |
515 | 554 | ||
516 | if (!ip->i_eattr) | 555 | if (!ip->i_eattr) |
517 | return -ENODATA; | 556 | return -ENODATA; |
557 | if (strlen(name) > GFS2_EA_MAX_NAME_LEN) | ||
558 | return -EINVAL; | ||
518 | 559 | ||
519 | error = gfs2_ea_find(ip, er, &el); | 560 | error = gfs2_ea_find(ip, type, name, &el); |
520 | if (error) | 561 | if (error) |
521 | return error; | 562 | return error; |
522 | if (!el.el_ea) | 563 | if (!el.el_ea) |
523 | return -ENODATA; | 564 | return -ENODATA; |
524 | 565 | if (size) | |
525 | if (er->er_data_len) { | 566 | error = gfs2_ea_get_copy(ip, &el, buffer, size); |
526 | if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) | 567 | else |
527 | error = -ERANGE; | ||
528 | else | ||
529 | error = gfs2_ea_get_copy(ip, &el, er->er_data); | ||
530 | } | ||
531 | if (!error) | ||
532 | error = GFS2_EA_DATA_LEN(el.el_ea); | 568 | error = GFS2_EA_DATA_LEN(el.el_ea); |
533 | |||
534 | brelse(el.el_bh); | 569 | brelse(el.el_bh); |
535 | 570 | ||
536 | return error; | 571 | return error; |
537 | } | 572 | } |
538 | 573 | ||
539 | /** | 574 | /** |
540 | * gfs2_ea_get - | ||
541 | * @ip: The GFS2 inode | ||
542 | * @er: The request structure | ||
543 | * | ||
544 | * Returns: actual size of data on success, -errno on error | ||
545 | */ | ||
546 | |||
547 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
548 | { | ||
549 | struct gfs2_holder i_gh; | ||
550 | int error; | ||
551 | |||
552 | if (!er->er_name_len || | ||
553 | er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
554 | return -EINVAL; | ||
555 | if (!er->er_data || !er->er_data_len) { | ||
556 | er->er_data = NULL; | ||
557 | er->er_data_len = 0; | ||
558 | } | ||
559 | |||
560 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | ||
561 | if (error) | ||
562 | return error; | ||
563 | |||
564 | error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); | ||
565 | |||
566 | gfs2_glock_dq_uninit(&i_gh); | ||
567 | |||
568 | return error; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * ea_alloc_blk - allocates a new block for extended attributes. | 575 | * ea_alloc_blk - allocates a new block for extended attributes. |
573 | * @ip: A pointer to the inode that's getting extended attributes | 576 | * @ip: A pointer to the inode that's getting extended attributes |
574 | * @bhp: Pointer to pointer to a struct buffer_head | 577 | * @bhp: Pointer to pointer to a struct buffer_head |
@@ -713,12 +716,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
713 | 716 | ||
714 | error = gfs2_meta_inode_buffer(ip, &dibh); | 717 | error = gfs2_meta_inode_buffer(ip, &dibh); |
715 | if (!error) { | 718 | if (!error) { |
716 | if (er->er_flags & GFS2_ERF_MODE) { | ||
717 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
718 | (ip->i_inode.i_mode & S_IFMT) == | ||
719 | (er->er_mode & S_IFMT)); | ||
720 | ip->i_inode.i_mode = er->er_mode; | ||
721 | } | ||
722 | ip->i_inode.i_ctime = CURRENT_TIME; | 719 | ip->i_inode.i_ctime = CURRENT_TIME; |
723 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 720 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
724 | gfs2_dinode_out(ip, dibh->b_data); | 721 | gfs2_dinode_out(ip, dibh->b_data); |
@@ -762,15 +759,23 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
762 | * Returns: errno | 759 | * Returns: errno |
763 | */ | 760 | */ |
764 | 761 | ||
765 | static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 762 | static int ea_init(struct gfs2_inode *ip, int type, const char *name, |
763 | const void *data, size_t size) | ||
766 | { | 764 | { |
765 | struct gfs2_ea_request er; | ||
767 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; | 766 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; |
768 | unsigned int blks = 1; | 767 | unsigned int blks = 1; |
769 | 768 | ||
770 | if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) | 769 | er.er_type = type; |
771 | blks += DIV_ROUND_UP(er->er_data_len, jbsize); | 770 | er.er_name = name; |
771 | er.er_name_len = strlen(name); | ||
772 | er.er_data = (void *)data; | ||
773 | er.er_data_len = size; | ||
774 | |||
775 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize) | ||
776 | blks += DIV_ROUND_UP(er.er_data_len, jbsize); | ||
772 | 777 | ||
773 | return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); | 778 | return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL); |
774 | } | 779 | } |
775 | 780 | ||
776 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) | 781 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) |
@@ -848,12 +853,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, | |||
848 | error = gfs2_meta_inode_buffer(ip, &dibh); | 853 | error = gfs2_meta_inode_buffer(ip, &dibh); |
849 | if (error) | 854 | if (error) |
850 | goto out; | 855 | goto out; |
851 | |||
852 | if (er->er_flags & GFS2_ERF_MODE) { | ||
853 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
854 | (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); | ||
855 | ip->i_inode.i_mode = er->er_mode; | ||
856 | } | ||
857 | ip->i_inode.i_ctime = CURRENT_TIME; | 856 | ip->i_inode.i_ctime = CURRENT_TIME; |
858 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 857 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
859 | gfs2_dinode_out(ip, dibh->b_data); | 858 | gfs2_dinode_out(ip, dibh->b_data); |
@@ -894,7 +893,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, | |||
894 | int stuffed; | 893 | int stuffed; |
895 | int error; | 894 | int error; |
896 | 895 | ||
897 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); | 896 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len, |
897 | es->es_er->er_data_len, &size); | ||
898 | 898 | ||
899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { | 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { |
900 | if (GFS2_EA_REC_LEN(ea) < size) | 900 | if (GFS2_EA_REC_LEN(ea) < size) |
@@ -1005,15 +1005,22 @@ out: | |||
1005 | return error; | 1005 | return error; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 1008 | static int ea_set_i(struct gfs2_inode *ip, int type, const char *name, |
1009 | struct gfs2_ea_location *el) | 1009 | const void *value, size_t size, struct gfs2_ea_location *el) |
1010 | { | 1010 | { |
1011 | struct gfs2_ea_request er; | ||
1011 | struct ea_set es; | 1012 | struct ea_set es; |
1012 | unsigned int blks = 2; | 1013 | unsigned int blks = 2; |
1013 | int error; | 1014 | int error; |
1014 | 1015 | ||
1016 | er.er_type = type; | ||
1017 | er.er_name = name; | ||
1018 | er.er_data = (void *)value; | ||
1019 | er.er_name_len = strlen(name); | ||
1020 | er.er_data_len = size; | ||
1021 | |||
1015 | memset(&es, 0, sizeof(struct ea_set)); | 1022 | memset(&es, 0, sizeof(struct ea_set)); |
1016 | es.es_er = er; | 1023 | es.es_er = &er; |
1017 | es.es_el = el; | 1024 | es.es_el = el; |
1018 | 1025 | ||
1019 | error = ea_foreach(ip, ea_set_simple, &es); | 1026 | error = ea_foreach(ip, ea_set_simple, &es); |
@@ -1024,10 +1031,10 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
1024 | 1031 | ||
1025 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) | 1032 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) |
1026 | blks++; | 1033 | blks++; |
1027 | if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) | 1034 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize) |
1028 | blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); | 1035 | blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); |
1029 | 1036 | ||
1030 | return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); | 1037 | return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el); |
1031 | } | 1038 | } |
1032 | 1039 | ||
1033 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | 1040 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, |
@@ -1042,74 +1049,6 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | |||
1042 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); | 1049 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); |
1043 | } | 1050 | } |
1044 | 1051 | ||
1045 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
1046 | { | ||
1047 | struct gfs2_ea_location el; | ||
1048 | int error; | ||
1049 | |||
1050 | if (!ip->i_eattr) { | ||
1051 | if (er->er_flags & XATTR_REPLACE) | ||
1052 | return -ENODATA; | ||
1053 | return ea_init(ip, er); | ||
1054 | } | ||
1055 | |||
1056 | error = gfs2_ea_find(ip, er, &el); | ||
1057 | if (error) | ||
1058 | return error; | ||
1059 | |||
1060 | if (el.el_ea) { | ||
1061 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { | ||
1062 | brelse(el.el_bh); | ||
1063 | return -EPERM; | ||
1064 | } | ||
1065 | |||
1066 | error = -EEXIST; | ||
1067 | if (!(er->er_flags & XATTR_CREATE)) { | ||
1068 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
1069 | error = ea_set_i(ip, er, &el); | ||
1070 | if (!error && unstuffed) | ||
1071 | ea_set_remove_unstuffed(ip, &el); | ||
1072 | } | ||
1073 | |||
1074 | brelse(el.el_bh); | ||
1075 | } else { | ||
1076 | error = -ENODATA; | ||
1077 | if (!(er->er_flags & XATTR_REPLACE)) | ||
1078 | error = ea_set_i(ip, er, NULL); | ||
1079 | } | ||
1080 | |||
1081 | return error; | ||
1082 | } | ||
1083 | |||
1084 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
1085 | { | ||
1086 | struct gfs2_holder i_gh; | ||
1087 | int error; | ||
1088 | |||
1089 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
1090 | return -EINVAL; | ||
1091 | if (!er->er_data || !er->er_data_len) { | ||
1092 | er->er_data = NULL; | ||
1093 | er->er_data_len = 0; | ||
1094 | } | ||
1095 | error = ea_check_size(GFS2_SB(&ip->i_inode), er); | ||
1096 | if (error) | ||
1097 | return error; | ||
1098 | |||
1099 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
1100 | if (error) | ||
1101 | return error; | ||
1102 | |||
1103 | if (IS_IMMUTABLE(&ip->i_inode)) | ||
1104 | error = -EPERM; | ||
1105 | else | ||
1106 | error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); | ||
1107 | |||
1108 | gfs2_glock_dq_uninit(&i_gh); | ||
1109 | |||
1110 | return error; | ||
1111 | } | ||
1112 | |||
1113 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | 1052 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) |
1114 | { | 1053 | { |
1115 | struct gfs2_ea_header *ea = el->el_ea; | 1054 | struct gfs2_ea_header *ea = el->el_ea; |
@@ -1131,8 +1070,9 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
1131 | 1070 | ||
1132 | if (GFS2_EA_IS_LAST(ea)) | 1071 | if (GFS2_EA_IS_LAST(ea)) |
1133 | prev->ea_flags |= GFS2_EAFLAG_LAST; | 1072 | prev->ea_flags |= GFS2_EAFLAG_LAST; |
1134 | } else | 1073 | } else { |
1135 | ea->ea_type = GFS2_EATYPE_UNUSED; | 1074 | ea->ea_type = GFS2_EATYPE_UNUSED; |
1075 | } | ||
1136 | 1076 | ||
1137 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1077 | error = gfs2_meta_inode_buffer(ip, &dibh); |
1138 | if (!error) { | 1078 | if (!error) { |
@@ -1147,15 +1087,29 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
1147 | return error; | 1087 | return error; |
1148 | } | 1088 | } |
1149 | 1089 | ||
1150 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1090 | /** |
1091 | * gfs2_xattr_remove - Remove a GFS2 extended attribute | ||
1092 | * @inode: The inode | ||
1093 | * @type: The type of the extended attribute | ||
1094 | * @name: The name of the extended attribute | ||
1095 | * | ||
1096 | * This is not called directly by the VFS since we use the (common) | ||
1097 | * scheme of making a "set with NULL data" mean a remove request. Note | ||
1098 | * that this is different from a set with zero length data. | ||
1099 | * | ||
1100 | * Returns: 0, or errno on failure | ||
1101 | */ | ||
1102 | |||
1103 | static int gfs2_xattr_remove(struct inode *inode, int type, const char *name) | ||
1151 | { | 1104 | { |
1105 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1152 | struct gfs2_ea_location el; | 1106 | struct gfs2_ea_location el; |
1153 | int error; | 1107 | int error; |
1154 | 1108 | ||
1155 | if (!ip->i_eattr) | 1109 | if (!ip->i_eattr) |
1156 | return -ENODATA; | 1110 | return -ENODATA; |
1157 | 1111 | ||
1158 | error = gfs2_ea_find(ip, er, &el); | 1112 | error = gfs2_ea_find(ip, type, name, &el); |
1159 | if (error) | 1113 | if (error) |
1160 | return error; | 1114 | return error; |
1161 | if (!el.el_ea) | 1115 | if (!el.el_ea) |
@@ -1164,8 +1118,7 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
1164 | if (GFS2_EA_IS_STUFFED(el.el_ea)) | 1118 | if (GFS2_EA_IS_STUFFED(el.el_ea)) |
1165 | error = ea_remove_stuffed(ip, &el); | 1119 | error = ea_remove_stuffed(ip, &el); |
1166 | else | 1120 | else |
1167 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, | 1121 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); |
1168 | 0); | ||
1169 | 1122 | ||
1170 | brelse(el.el_bh); | 1123 | brelse(el.el_bh); |
1171 | 1124 | ||
@@ -1173,31 +1126,70 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
1173 | } | 1126 | } |
1174 | 1127 | ||
1175 | /** | 1128 | /** |
1176 | * gfs2_ea_remove - sets (or creates or replaces) an extended attribute | 1129 | * gfs2_xattr_set - Set (or remove) a GFS2 extended attribute |
1177 | * @ip: pointer to the inode of the target file | 1130 | * @inode: The inode |
1178 | * @er: request information | 1131 | * @type: The type of the extended attribute |
1132 | * @name: The name of the extended attribute | ||
1133 | * @value: The value of the extended attribute (NULL for remove) | ||
1134 | * @size: The size of the @value argument | ||
1135 | * @flags: Create or Replace | ||
1179 | * | 1136 | * |
1180 | * Returns: errno | 1137 | * See gfs2_xattr_remove() for details of the removal of xattrs. |
1138 | * | ||
1139 | * Returns: 0 or errno on failure | ||
1181 | */ | 1140 | */ |
1182 | 1141 | ||
1183 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1142 | int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
1143 | const void *value, size_t size, int flags) | ||
1184 | { | 1144 | { |
1185 | struct gfs2_holder i_gh; | 1145 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
1146 | struct gfs2_inode *ip = GFS2_I(inode); | ||
1147 | struct gfs2_ea_location el; | ||
1148 | unsigned int namel = strlen(name); | ||
1186 | int error; | 1149 | int error; |
1187 | 1150 | ||
1188 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | 1151 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
1189 | return -EINVAL; | 1152 | return -EPERM; |
1153 | if (namel > GFS2_EA_MAX_NAME_LEN) | ||
1154 | return -ERANGE; | ||
1190 | 1155 | ||
1191 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | 1156 | if (value == NULL) |
1157 | return gfs2_xattr_remove(inode, type, name); | ||
1158 | |||
1159 | if (ea_check_size(sdp, namel, size)) | ||
1160 | return -ERANGE; | ||
1161 | |||
1162 | if (!ip->i_eattr) { | ||
1163 | if (flags & XATTR_REPLACE) | ||
1164 | return -ENODATA; | ||
1165 | return ea_init(ip, type, name, value, size); | ||
1166 | } | ||
1167 | |||
1168 | error = gfs2_ea_find(ip, type, name, &el); | ||
1192 | if (error) | 1169 | if (error) |
1193 | return error; | 1170 | return error; |
1194 | 1171 | ||
1195 | if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) | 1172 | if (el.el_ea) { |
1196 | error = -EPERM; | 1173 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { |
1197 | else | 1174 | brelse(el.el_bh); |
1198 | error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); | 1175 | return -EPERM; |
1176 | } | ||
1199 | 1177 | ||
1200 | gfs2_glock_dq_uninit(&i_gh); | 1178 | error = -EEXIST; |
1179 | if (!(flags & XATTR_CREATE)) { | ||
1180 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
1181 | error = ea_set_i(ip, type, name, value, size, &el); | ||
1182 | if (!error && unstuffed) | ||
1183 | ea_set_remove_unstuffed(ip, &el); | ||
1184 | } | ||
1185 | |||
1186 | brelse(el.el_bh); | ||
1187 | return error; | ||
1188 | } | ||
1189 | |||
1190 | error = -ENODATA; | ||
1191 | if (!(flags & XATTR_REPLACE)) | ||
1192 | error = ea_set_i(ip, type, name, value, size, NULL); | ||
1201 | 1193 | ||
1202 | return error; | 1194 | return error; |
1203 | } | 1195 | } |
@@ -1503,3 +1495,64 @@ out_alloc: | |||
1503 | return error; | 1495 | return error; |
1504 | } | 1496 | } |
1505 | 1497 | ||
1498 | static int gfs2_xattr_user_get(struct inode *inode, const char *name, | ||
1499 | void *buffer, size_t size) | ||
1500 | { | ||
1501 | return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size); | ||
1502 | } | ||
1503 | |||
1504 | static int gfs2_xattr_user_set(struct inode *inode, const char *name, | ||
1505 | const void *value, size_t size, int flags) | ||
1506 | { | ||
1507 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); | ||
1508 | } | ||
1509 | |||
1510 | static int gfs2_xattr_system_get(struct inode *inode, const char *name, | ||
1511 | void *buffer, size_t size) | ||
1512 | { | ||
1513 | return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); | ||
1514 | } | ||
1515 | |||
1516 | static int gfs2_xattr_system_set(struct inode *inode, const char *name, | ||
1517 | const void *value, size_t size, int flags) | ||
1518 | { | ||
1519 | return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags); | ||
1520 | } | ||
1521 | |||
1522 | static int gfs2_xattr_security_get(struct inode *inode, const char *name, | ||
1523 | void *buffer, size_t size) | ||
1524 | { | ||
1525 | return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size); | ||
1526 | } | ||
1527 | |||
1528 | static int gfs2_xattr_security_set(struct inode *inode, const char *name, | ||
1529 | const void *value, size_t size, int flags) | ||
1530 | { | ||
1531 | return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags); | ||
1532 | } | ||
1533 | |||
1534 | static struct xattr_handler gfs2_xattr_user_handler = { | ||
1535 | .prefix = XATTR_USER_PREFIX, | ||
1536 | .get = gfs2_xattr_user_get, | ||
1537 | .set = gfs2_xattr_user_set, | ||
1538 | }; | ||
1539 | |||
1540 | static struct xattr_handler gfs2_xattr_security_handler = { | ||
1541 | .prefix = XATTR_SECURITY_PREFIX, | ||
1542 | .get = gfs2_xattr_security_get, | ||
1543 | .set = gfs2_xattr_security_set, | ||
1544 | }; | ||
1545 | |||
1546 | static struct xattr_handler gfs2_xattr_system_handler = { | ||
1547 | .prefix = XATTR_SYSTEM_PREFIX, | ||
1548 | .get = gfs2_xattr_system_get, | ||
1549 | .set = gfs2_xattr_system_set, | ||
1550 | }; | ||
1551 | |||
1552 | struct xattr_handler *gfs2_xattr_handlers[] = { | ||
1553 | &gfs2_xattr_user_handler, | ||
1554 | &gfs2_xattr_security_handler, | ||
1555 | &gfs2_xattr_system_handler, | ||
1556 | NULL, | ||
1557 | }; | ||
1558 | |||
diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h index c82dbe01d713..4040a188f63b 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/eattr.h | |||
@@ -27,10 +27,6 @@ ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ | |||
27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ | 27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ |
28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) | 28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) |
29 | 29 | ||
30 | #define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \ | ||
31 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | ||
32 | sizeof(__be64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8) | ||
33 | |||
34 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) | 30 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) |
35 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) | 31 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) |
36 | 32 | ||
@@ -43,16 +39,12 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | |||
43 | #define GFS2_EA_BH2FIRST(bh) \ | 39 | #define GFS2_EA_BH2FIRST(bh) \ |
44 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) | 40 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) |
45 | 41 | ||
46 | #define GFS2_ERF_MODE 0x80000000 | ||
47 | |||
48 | struct gfs2_ea_request { | 42 | struct gfs2_ea_request { |
49 | const char *er_name; | 43 | const char *er_name; |
50 | char *er_data; | 44 | char *er_data; |
51 | unsigned int er_name_len; | 45 | unsigned int er_name_len; |
52 | unsigned int er_data_len; | 46 | unsigned int er_data_len; |
53 | unsigned int er_type; /* GFS2_EATYPE_... */ | 47 | unsigned int er_type; /* GFS2_EATYPE_... */ |
54 | int er_flags; | ||
55 | mode_t er_mode; | ||
56 | }; | 48 | }; |
57 | 49 | ||
58 | struct gfs2_ea_location { | 50 | struct gfs2_ea_location { |
@@ -61,40 +53,20 @@ struct gfs2_ea_location { | |||
61 | struct gfs2_ea_header *el_prev; | 53 | struct gfs2_ea_header *el_prev; |
62 | }; | 54 | }; |
63 | 55 | ||
64 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 56 | extern int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
65 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 57 | void *buffer, size_t size); |
66 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 58 | extern int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
67 | 59 | const void *value, size_t size, int flags); | |
68 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 60 | extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); |
69 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 61 | extern int gfs2_ea_dealloc(struct gfs2_inode *ip); |
70 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
71 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
72 | |||
73 | int gfs2_ea_dealloc(struct gfs2_inode *ip); | ||
74 | 62 | ||
75 | /* Exported to acl.c */ | 63 | /* Exported to acl.c */ |
76 | 64 | ||
77 | int gfs2_ea_find(struct gfs2_inode *ip, | 65 | extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
78 | struct gfs2_ea_request *er, | 66 | struct gfs2_ea_location *el); |
79 | struct gfs2_ea_location *el); | 67 | extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
80 | int gfs2_ea_get_copy(struct gfs2_inode *ip, | 68 | char *data, size_t size); |
81 | struct gfs2_ea_location *el, | 69 | extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
82 | char *data); | 70 | struct iattr *attr, char *data); |
83 | int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, | ||
84 | struct iattr *attr, char *data); | ||
85 | |||
86 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
87 | { | ||
88 | switch (ea->ea_type) { | ||
89 | case GFS2_EATYPE_USR: | ||
90 | return 5 + ea->ea_name_len + 1; | ||
91 | case GFS2_EATYPE_SYS: | ||
92 | return 7 + ea->ea_name_len + 1; | ||
93 | case GFS2_EATYPE_SECURITY: | ||
94 | return 9 + ea->ea_name_len + 1; | ||
95 | default: | ||
96 | return 0; | ||
97 | } | ||
98 | } | ||
99 | 71 | ||
100 | #endif /* __EATTR_DOT_H__ */ | 72 | #endif /* __EATTR_DOT_H__ */ |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 73318a3ce6f1..166f38fbd246 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include "rgrp.h" | 38 | #include "rgrp.h" |
39 | #include "trans.h" | 39 | #include "trans.h" |
40 | #include "util.h" | 40 | #include "util.h" |
41 | #include "eaops.h" | ||
42 | 41 | ||
43 | /** | 42 | /** |
44 | * gfs2_llseek - seek to a location in a file | 43 | * gfs2_llseek - seek to a location in a file |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f9b4fe886540..f936d2d68138 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -924,7 +924,6 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
924 | size_t len; | 924 | size_t len; |
925 | void *value; | 925 | void *value; |
926 | char *name; | 926 | char *name; |
927 | struct gfs2_ea_request er; | ||
928 | 927 | ||
929 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, | 928 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, |
930 | &name, &value, &len); | 929 | &name, &value, &len); |
@@ -935,16 +934,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
935 | return err; | 934 | return err; |
936 | } | 935 | } |
937 | 936 | ||
938 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 937 | err = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SECURITY, name, value, len, 0); |
939 | |||
940 | er.er_type = GFS2_EATYPE_SECURITY; | ||
941 | er.er_name = name; | ||
942 | er.er_data = value; | ||
943 | er.er_name_len = strlen(name); | ||
944 | er.er_data_len = len; | ||
945 | |||
946 | err = gfs2_ea_set_i(ip, &er); | ||
947 | |||
948 | kfree(value); | 938 | kfree(value); |
949 | kfree(name); | 939 | kfree(name); |
950 | 940 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 165518a1041e..1ec69e63c694 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -1186,6 +1186,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1186 | sb->s_magic = GFS2_MAGIC; | 1186 | sb->s_magic = GFS2_MAGIC; |
1187 | sb->s_op = &gfs2_super_ops; | 1187 | sb->s_op = &gfs2_super_ops; |
1188 | sb->s_export_op = &gfs2_export_ops; | 1188 | sb->s_export_op = &gfs2_export_ops; |
1189 | sb->s_xattr = gfs2_xattr_handlers; | ||
1189 | sb->s_time_gran = 1; | 1190 | sb->s_time_gran = 1; |
1190 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1191 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
1191 | 1192 | ||
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index ce551f85524f..1ee0c2657467 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include "acl.h" | 26 | #include "acl.h" |
27 | #include "bmap.h" | 27 | #include "bmap.h" |
28 | #include "dir.h" | 28 | #include "dir.h" |
29 | #include "eaops.h" | ||
30 | #include "eattr.h" | 29 | #include "eattr.h" |
31 | #include "glock.h" | 30 | #include "glock.h" |
32 | #include "inode.h" | 31 | #include "inode.h" |
@@ -1302,60 +1301,53 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, | |||
1302 | const void *data, size_t size, int flags) | 1301 | const void *data, size_t size, int flags) |
1303 | { | 1302 | { |
1304 | struct inode *inode = dentry->d_inode; | 1303 | struct inode *inode = dentry->d_inode; |
1305 | struct gfs2_ea_request er; | 1304 | struct gfs2_inode *ip = GFS2_I(inode); |
1306 | 1305 | struct gfs2_holder gh; | |
1307 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1306 | int ret; |
1308 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | ||
1309 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
1310 | return -EOPNOTSUPP; | ||
1311 | er.er_data = (char *)data; | ||
1312 | er.er_name_len = strlen(er.er_name); | ||
1313 | er.er_data_len = size; | ||
1314 | er.er_flags = flags; | ||
1315 | |||
1316 | gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE)); | ||
1317 | 1307 | ||
1318 | return gfs2_ea_set(GFS2_I(inode), &er); | 1308 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
1309 | ret = gfs2_glock_nq(&gh); | ||
1310 | if (ret == 0) { | ||
1311 | ret = generic_setxattr(dentry, name, data, size, flags); | ||
1312 | gfs2_glock_dq(&gh); | ||
1313 | } | ||
1314 | gfs2_holder_uninit(&gh); | ||
1315 | return ret; | ||
1319 | } | 1316 | } |
1320 | 1317 | ||
1321 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, | 1318 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, |
1322 | void *data, size_t size) | 1319 | void *data, size_t size) |
1323 | { | 1320 | { |
1324 | struct gfs2_ea_request er; | 1321 | struct inode *inode = dentry->d_inode; |
1325 | 1322 | struct gfs2_inode *ip = GFS2_I(inode); | |
1326 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1323 | struct gfs2_holder gh; |
1327 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1324 | int ret; |
1328 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
1329 | return -EOPNOTSUPP; | ||
1330 | er.er_data = data; | ||
1331 | er.er_name_len = strlen(er.er_name); | ||
1332 | er.er_data_len = size; | ||
1333 | |||
1334 | return gfs2_ea_get(GFS2_I(dentry->d_inode), &er); | ||
1335 | } | ||
1336 | |||
1337 | static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
1338 | { | ||
1339 | struct gfs2_ea_request er; | ||
1340 | |||
1341 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | ||
1342 | er.er_data = (size) ? buffer : NULL; | ||
1343 | er.er_data_len = size; | ||
1344 | 1325 | ||
1345 | return gfs2_ea_list(GFS2_I(dentry->d_inode), &er); | 1326 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); |
1327 | ret = gfs2_glock_nq(&gh); | ||
1328 | if (ret == 0) { | ||
1329 | ret = generic_getxattr(dentry, name, data, size); | ||
1330 | gfs2_glock_dq(&gh); | ||
1331 | } | ||
1332 | gfs2_holder_uninit(&gh); | ||
1333 | return ret; | ||
1346 | } | 1334 | } |
1347 | 1335 | ||
1348 | static int gfs2_removexattr(struct dentry *dentry, const char *name) | 1336 | static int gfs2_removexattr(struct dentry *dentry, const char *name) |
1349 | { | 1337 | { |
1350 | struct gfs2_ea_request er; | 1338 | struct inode *inode = dentry->d_inode; |
1351 | 1339 | struct gfs2_inode *ip = GFS2_I(inode); | |
1352 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1340 | struct gfs2_holder gh; |
1353 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1341 | int ret; |
1354 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
1355 | return -EOPNOTSUPP; | ||
1356 | er.er_name_len = strlen(er.er_name); | ||
1357 | 1342 | ||
1358 | return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); | 1343 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
1344 | ret = gfs2_glock_nq(&gh); | ||
1345 | if (ret == 0) { | ||
1346 | ret = generic_removexattr(dentry, name); | ||
1347 | gfs2_glock_dq(&gh); | ||
1348 | } | ||
1349 | gfs2_holder_uninit(&gh); | ||
1350 | return ret; | ||
1359 | } | 1351 | } |
1360 | 1352 | ||
1361 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 1353 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 911c954cefbd..235db3682885 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
@@ -54,6 +54,7 @@ extern struct file_system_type gfs2meta_fs_type; | |||
54 | extern const struct export_operations gfs2_export_ops; | 54 | extern const struct export_operations gfs2_export_ops; |
55 | extern const struct super_operations gfs2_super_ops; | 55 | extern const struct super_operations gfs2_super_ops; |
56 | extern const struct dentry_operations gfs2_dops; | 56 | extern const struct dentry_operations gfs2_dops; |
57 | extern struct xattr_handler *gfs2_xattr_handlers[]; | ||
57 | 58 | ||
58 | #endif /* __SUPER_DOT_H__ */ | 59 | #endif /* __SUPER_DOT_H__ */ |
59 | 60 | ||