aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/Makefile3
-rw-r--r--fs/jffs2/acl.c483
-rw-r--r--fs/jffs2/acl.h46
-rw-r--r--fs/jffs2/build.c2
-rw-r--r--fs/jffs2/debug.h6
-rw-r--r--fs/jffs2/dir.c62
-rw-r--r--fs/jffs2/file.c7
-rw-r--r--fs/jffs2/fs.c11
-rw-r--r--fs/jffs2/gc.c16
-rw-r--r--fs/jffs2/jffs2_fs_i.h5
-rw-r--r--fs/jffs2/jffs2_fs_sb.h10
-rw-r--r--fs/jffs2/malloc.c68
-rw-r--r--fs/jffs2/nodelist.c1
-rw-r--r--fs/jffs2/nodelist.h21
-rw-r--r--fs/jffs2/os-linux.h4
-rw-r--r--fs/jffs2/readinode.c1
-rw-r--r--fs/jffs2/scan.c168
-rw-r--r--fs/jffs2/security.c82
-rw-r--r--fs/jffs2/summary.c191
-rw-r--r--fs/jffs2/summary.h42
-rw-r--r--fs/jffs2/super.c6
-rw-r--r--fs/jffs2/symlink.c7
-rw-r--r--fs/jffs2/write.c2
-rw-r--r--fs/jffs2/xattr.c1271
-rw-r--r--fs/jffs2/xattr.h120
-rw-r--r--fs/jffs2/xattr_trusted.c51
-rw-r--r--fs/jffs2/xattr_user.c51
27 files changed, 2722 insertions, 15 deletions
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index 77dc5561a04e..7f28ee0bd132 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -12,6 +12,9 @@ jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
12jffs2-y += super.o debug.o 12jffs2-y += super.o debug.o
13 13
14jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o 14jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
15jffs2-$(CONFIG_JFFS2_FS_XATTR) += xattr.o xattr_trusted.o xattr_user.o
16jffs2-$(CONFIG_JFFS2_FS_SECURITY) += security.o
17jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL) += acl.o
15jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o 18jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
16jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o 19jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
17jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o 20jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
new file mode 100644
index 000000000000..080bb51e4b65
--- /dev/null
+++ b/fs/jffs2/acl.c
@@ -0,0 +1,483 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/acl.c
3 * POSIX ACL support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10#include <linux/kernel.h>
11#include <linux/slab.h>
12#include <linux/fs.h>
13#include <linux/time.h>
14#include <linux/crc32.h>
15#include <linux/jffs2.h>
16#include <linux/xattr.h>
17#include <linux/posix_acl_xattr.h>
18#include <linux/mtd/mtd.h>
19#include "nodelist.h"
20
21static size_t jffs2_acl_size(int count)
22{
23 if (count <= 4) {
24 return sizeof(jffs2_acl_header)
25 + count * sizeof(jffs2_acl_entry_short);
26 } else {
27 return sizeof(jffs2_acl_header)
28 + 4 * sizeof(jffs2_acl_entry_short)
29 + (count - 4) * sizeof(jffs2_acl_entry);
30 }
31}
32
33static int jffs2_acl_count(size_t size)
34{
35 size_t s;
36
37 size -= sizeof(jffs2_acl_header);
38 s = size - 4 * sizeof(jffs2_acl_entry_short);
39 if (s < 0) {
40 if (size % sizeof(jffs2_acl_entry_short))
41 return -1;
42 return size / sizeof(jffs2_acl_entry_short);
43 } else {
44 if (s % sizeof(jffs2_acl_entry))
45 return -1;
46 return s / sizeof(jffs2_acl_entry) + 4;
47 }
48}
49
50static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size)
51{
52 const char *end = (char *)value + size;
53 struct posix_acl *acl;
54 uint32_t ver;
55 int i, count;
56
57 if (!value)
58 return NULL;
59 if (size < sizeof(jffs2_acl_header))
60 return ERR_PTR(-EINVAL);
61 ver = je32_to_cpu(((jffs2_acl_header *)value)->a_version);
62 if (ver != JFFS2_ACL_VERSION) {
63 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
64 return ERR_PTR(-EINVAL);
65 }
66
67 value = (char *)value + sizeof(jffs2_acl_header);
68 count = jffs2_acl_count(size);
69 if (count < 0)
70 return ERR_PTR(-EINVAL);
71 if (count == 0)
72 return NULL;
73
74 acl = posix_acl_alloc(count, GFP_KERNEL);
75 if (!acl)
76 return ERR_PTR(-ENOMEM);
77
78 for (i=0; i < count; i++) {
79 jffs2_acl_entry *entry = (jffs2_acl_entry *)value;
80 if ((char *)value + sizeof(jffs2_acl_entry_short) > end)
81 goto fail;
82 acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
83 acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
84 switch (acl->a_entries[i].e_tag) {
85 case ACL_USER_OBJ:
86 case ACL_GROUP_OBJ:
87 case ACL_MASK:
88 case ACL_OTHER:
89 value = (char *)value + sizeof(jffs2_acl_entry_short);
90 acl->a_entries[i].e_id = ACL_UNDEFINED_ID;
91 break;
92
93 case ACL_USER:
94 case ACL_GROUP:
95 value = (char *)value + sizeof(jffs2_acl_entry);
96 if ((char *)value > end)
97 goto fail;
98 acl->a_entries[i].e_id = je32_to_cpu(entry->e_id);
99 break;
100
101 default:
102 goto fail;
103 }
104 }
105 if (value != end)
106 goto fail;
107 return acl;
108 fail:
109 posix_acl_release(acl);
110 return ERR_PTR(-EINVAL);
111}
112
113static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
114{
115 jffs2_acl_header *jffs2_acl;
116 char *e;
117 size_t i;
118
119 *size = jffs2_acl_size(acl->a_count);
120 jffs2_acl = (jffs2_acl_header *)kmalloc(sizeof(jffs2_acl_header)
121 + acl->a_count * sizeof(jffs2_acl_entry),
122 GFP_KERNEL);
123 if (!jffs2_acl)
124 return ERR_PTR(-ENOMEM);
125 jffs2_acl->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
126 e = (char *)jffs2_acl + sizeof(jffs2_acl_header);
127 for (i=0; i < acl->a_count; i++) {
128 jffs2_acl_entry *entry = (jffs2_acl_entry *)e;
129 entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag);
130 entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm);
131 switch(acl->a_entries[i].e_tag) {
132 case ACL_USER:
133 case ACL_GROUP:
134 entry->e_id = cpu_to_je32(acl->a_entries[i].e_id);
135 e += sizeof(jffs2_acl_entry);
136 break;
137
138 case ACL_USER_OBJ:
139 case ACL_GROUP_OBJ:
140 case ACL_MASK:
141 case ACL_OTHER:
142 e += sizeof(jffs2_acl_entry_short);
143 break;
144
145 default:
146 goto fail;
147 }
148 }
149 return (char *)jffs2_acl;
150 fail:
151 kfree(jffs2_acl);
152 return ERR_PTR(-EINVAL);
153}
154
155static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
156{
157 struct posix_acl *acl = JFFS2_ACL_NOT_CACHED;
158
159 spin_lock(&inode->i_lock);
160 if (*i_acl != JFFS2_ACL_NOT_CACHED)
161 acl = posix_acl_dup(*i_acl);
162 spin_unlock(&inode->i_lock);
163 return acl;
164}
165
166static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl)
167{
168 spin_lock(&inode->i_lock);
169 if (*i_acl != JFFS2_ACL_NOT_CACHED)
170 posix_acl_release(*i_acl);
171 *i_acl = posix_acl_dup(acl);
172 spin_unlock(&inode->i_lock);
173}
174
175static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
176{
177 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
178 struct posix_acl *acl;
179 char *value = NULL;
180 int rc, xprefix;
181
182 switch (type) {
183 case ACL_TYPE_ACCESS:
184 acl = jffs2_iget_acl(inode, &f->i_acl_access);
185 if (acl != JFFS2_ACL_NOT_CACHED)
186 return acl;
187 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
188 break;
189 case ACL_TYPE_DEFAULT:
190 acl = jffs2_iget_acl(inode, &f->i_acl_default);
191 if (acl != JFFS2_ACL_NOT_CACHED)
192 return acl;
193 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
194 break;
195 default:
196 return ERR_PTR(-EINVAL);
197 }
198 rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
199 if (rc > 0) {
200 value = kmalloc(rc, GFP_KERNEL);
201 if (!value)
202 return ERR_PTR(-ENOMEM);
203 rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
204 }
205 if (rc > 0) {
206 acl = jffs2_acl_from_medium(value, rc);
207 } else if (rc == -ENODATA || rc == -ENOSYS) {
208 acl = NULL;
209 } else {
210 acl = ERR_PTR(rc);
211 }
212 if (value)
213 kfree(value);
214 if (!IS_ERR(acl)) {
215 switch (type) {
216 case ACL_TYPE_ACCESS:
217 jffs2_iset_acl(inode, &f->i_acl_access, acl);
218 break;
219 case ACL_TYPE_DEFAULT:
220 jffs2_iset_acl(inode, &f->i_acl_default, acl);
221 break;
222 }
223 }
224 return acl;
225}
226
227static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
228{
229 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
230 size_t size = 0;
231 char *value = NULL;
232 int rc, xprefix;
233
234 if (S_ISLNK(inode->i_mode))
235 return -EOPNOTSUPP;
236
237 switch (type) {
238 case ACL_TYPE_ACCESS:
239 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
240 if (acl) {
241 mode_t mode = inode->i_mode;
242 rc = posix_acl_equiv_mode(acl, &mode);
243 if (rc < 0)
244 return rc;
245 if (inode->i_mode != mode) {
246 inode->i_mode = mode;
247 jffs2_dirty_inode(inode);
248 }
249 if (rc == 0)
250 acl = NULL;
251 }
252 break;
253 case ACL_TYPE_DEFAULT:
254 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
255 if (!S_ISDIR(inode->i_mode))
256 return acl ? -EACCES : 0;
257 break;
258 default:
259 return -EINVAL;
260 }
261 if (acl) {
262 value = jffs2_acl_to_medium(acl, &size);
263 if (IS_ERR(value))
264 return PTR_ERR(value);
265 }
266
267 rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
268 if (value)
269 kfree(value);
270 if (!rc) {
271 switch(type) {
272 case ACL_TYPE_ACCESS:
273 jffs2_iset_acl(inode, &f->i_acl_access, acl);
274 break;
275 case ACL_TYPE_DEFAULT:
276 jffs2_iset_acl(inode, &f->i_acl_default, acl);
277 break;
278 }
279 }
280 return rc;
281}
282
283static int jffs2_check_acl(struct inode *inode, int mask)
284{
285 struct posix_acl *acl;
286 int rc;
287
288 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
289 if (IS_ERR(acl))
290 return PTR_ERR(acl);
291 if (acl) {
292 rc = posix_acl_permission(inode, acl, mask);
293 posix_acl_release(acl);
294 return rc;
295 }
296 return -EAGAIN;
297}
298
299int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
300{
301 return generic_permission(inode, mask, jffs2_check_acl);
302}
303
304int jffs2_init_acl(struct inode *inode, struct inode *dir)
305{
306 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
307 struct posix_acl *acl = NULL, *clone;
308 mode_t mode;
309 int rc = 0;
310
311 f->i_acl_access = JFFS2_ACL_NOT_CACHED;
312 f->i_acl_default = JFFS2_ACL_NOT_CACHED;
313 if (!S_ISLNK(inode->i_mode)) {
314 acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT);
315 if (IS_ERR(acl))
316 return PTR_ERR(acl);
317 if (!acl)
318 inode->i_mode &= ~current->fs->umask;
319 }
320 if (acl) {
321 if (S_ISDIR(inode->i_mode)) {
322 rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
323 if (rc)
324 goto cleanup;
325 }
326 clone = posix_acl_clone(acl, GFP_KERNEL);
327 rc = -ENOMEM;
328 if (!clone)
329 goto cleanup;
330 mode = inode->i_mode;
331 rc = posix_acl_create_masq(clone, &mode);
332 if (rc >= 0) {
333 inode->i_mode = mode;
334 if (rc > 0)
335 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
336 }
337 posix_acl_release(clone);
338 }
339 cleanup:
340 posix_acl_release(acl);
341 return rc;
342}
343
344void jffs2_clear_acl(struct inode *inode)
345{
346 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
347
348 if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) {
349 posix_acl_release(f->i_acl_access);
350 f->i_acl_access = JFFS2_ACL_NOT_CACHED;
351 }
352 if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) {
353 posix_acl_release(f->i_acl_default);
354 f->i_acl_default = JFFS2_ACL_NOT_CACHED;
355 }
356}
357
358int jffs2_acl_chmod(struct inode *inode)
359{
360 struct posix_acl *acl, *clone;
361 int rc;
362
363 if (S_ISLNK(inode->i_mode))
364 return -EOPNOTSUPP;
365 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
366 if (IS_ERR(acl) || !acl)
367 return PTR_ERR(acl);
368 clone = posix_acl_clone(acl, GFP_KERNEL);
369 posix_acl_release(acl);
370 if (!clone)
371 return -ENOMEM;
372 rc = posix_acl_chmod_masq(clone, inode->i_mode);
373 if (!rc)
374 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
375 posix_acl_release(clone);
376 return rc;
377}
378
379static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size,
380 const char *name, size_t name_len)
381{
382 const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);
383
384 if (list && retlen <= list_size)
385 strcpy(list, POSIX_ACL_XATTR_ACCESS);
386 return retlen;
387}
388
389static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size,
390 const char *name, size_t name_len)
391{
392 const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);
393
394 if (list && retlen <= list_size)
395 strcpy(list, POSIX_ACL_XATTR_DEFAULT);
396 return retlen;
397}
398
399static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size)
400{
401 struct posix_acl *acl;
402 int rc;
403
404 acl = jffs2_get_acl(inode, type);
405 if (IS_ERR(acl))
406 return PTR_ERR(acl);
407 if (!acl)
408 return -ENODATA;
409 rc = posix_acl_to_xattr(acl, buffer, size);
410 posix_acl_release(acl);
411
412 return rc;
413}
414
415static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
416{
417 if (name[0] != '\0')
418 return -EINVAL;
419 return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size);
420}
421
422static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
423{
424 if (name[0] != '\0')
425 return -EINVAL;
426 return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
427}
428
429static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size)
430{
431 struct posix_acl *acl;
432 int rc;
433
434 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
435 return -EPERM;
436
437 if (value) {
438 acl = posix_acl_from_xattr(value, size);
439 if (IS_ERR(acl))
440 return PTR_ERR(acl);
441 if (acl) {
442 rc = posix_acl_valid(acl);
443 if (rc)
444 goto out;
445 }
446 } else {
447 acl = NULL;
448 }
449 rc = jffs2_set_acl(inode, type, acl);
450 out:
451 posix_acl_release(acl);
452 return rc;
453}
454
455static int jffs2_acl_access_setxattr(struct inode *inode, const char *name,
456 const void *buffer, size_t size, int flags)
457{
458 if (name[0] != '\0')
459 return -EINVAL;
460 return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size);
461}
462
463static int jffs2_acl_default_setxattr(struct inode *inode, const char *name,
464 const void *buffer, size_t size, int flags)
465{
466 if (name[0] != '\0')
467 return -EINVAL;
468 return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
469}
470
471struct xattr_handler jffs2_acl_access_xattr_handler = {
472 .prefix = POSIX_ACL_XATTR_ACCESS,
473 .list = jffs2_acl_access_listxattr,
474 .get = jffs2_acl_access_getxattr,
475 .set = jffs2_acl_access_setxattr,
476};
477
478struct xattr_handler jffs2_acl_default_xattr_handler = {
479 .prefix = POSIX_ACL_XATTR_DEFAULT,
480 .list = jffs2_acl_default_listxattr,
481 .get = jffs2_acl_default_getxattr,
482 .set = jffs2_acl_default_setxattr,
483};
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
new file mode 100644
index 000000000000..c98610b4e81c
--- /dev/null
+++ b/fs/jffs2/acl.h
@@ -0,0 +1,46 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/acl.h
3 * POSIX ACL support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10typedef struct {
11 jint16_t e_tag;
12 jint16_t e_perm;
13 jint32_t e_id;
14} jffs2_acl_entry;
15
16typedef struct {
17 jint16_t e_tag;
18 jint16_t e_perm;
19} jffs2_acl_entry_short;
20
21typedef struct {
22 jint32_t a_version;
23} jffs2_acl_header;
24
25#ifdef __KERNEL__
26#ifdef CONFIG_JFFS2_FS_POSIX_ACL
27
28#define JFFS2_ACL_NOT_CACHED ((void *)-1)
29
30extern int jffs2_permission(struct inode *, int, struct nameidata *);
31extern int jffs2_acl_chmod(struct inode *);
32extern int jffs2_init_acl(struct inode *, struct inode *);
33extern void jffs2_clear_acl(struct inode *);
34
35extern struct xattr_handler jffs2_acl_access_xattr_handler;
36extern struct xattr_handler jffs2_acl_default_xattr_handler;
37
38#else
39
40#define jffs2_permission NULL
41#define jffs2_acl_chmod(inode) (0)
42#define jffs2_init_acl(inode,dir) (0)
43#define jffs2_clear_acl(inode)
44
45#endif /* CONFIG_JFFS2_FS_POSIX_ACL */
46#endif /* __KERNEL__ */
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 70f7a896c04a..02826967ab58 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
160 ic->scan_dents = NULL; 160 ic->scan_dents = NULL;
161 cond_resched(); 161 cond_resched();
162 } 162 }
163 jffs2_build_xattr_subsystem(c);
163 c->flags &= ~JFFS2_SB_FLAG_BUILDING; 164 c->flags &= ~JFFS2_SB_FLAG_BUILDING;
164 165
165 dbg_fsbuild("FS build complete\n"); 166 dbg_fsbuild("FS build complete\n");
@@ -178,6 +179,7 @@ exit:
178 jffs2_free_full_dirent(fd); 179 jffs2_free_full_dirent(fd);
179 } 180 }
180 } 181 }
182 jffs2_clear_xattr_subsystem(c);
181 } 183 }
182 184
183 return ret; 185 return ret;
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 162af6dfe292..5fa494a792b2 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -171,6 +171,12 @@
171#define dbg_memalloc(fmt, ...) 171#define dbg_memalloc(fmt, ...)
172#endif 172#endif
173 173
174/* Watch the XATTR subsystem */
175#ifdef JFFS2_DBG_XATTR_MESSAGES
176#define dbg_xattr(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
177#else
178#define dbg_xattr(fmt, ...)
179#endif
174 180
175/* "Sanity" checks */ 181/* "Sanity" checks */
176void 182void
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 1c8e8c0f6cea..f1b18b99a3cd 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_operations =
57 .rmdir = jffs2_rmdir, 57 .rmdir = jffs2_rmdir,
58 .mknod = jffs2_mknod, 58 .mknod = jffs2_mknod,
59 .rename = jffs2_rename, 59 .rename = jffs2_rename,
60 .permission = jffs2_permission,
60 .setattr = jffs2_setattr, 61 .setattr = jffs2_setattr,
62 .setxattr = jffs2_setxattr,
63 .getxattr = jffs2_getxattr,
64 .listxattr = jffs2_listxattr,
65 .removexattr = jffs2_removexattr
61}; 66};
62 67
63/***********************************************************************/ 68/***********************************************************************/
@@ -209,12 +214,15 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
209 ret = jffs2_do_create(c, dir_f, f, ri, 214 ret = jffs2_do_create(c, dir_f, f, ri,
210 dentry->d_name.name, dentry->d_name.len); 215 dentry->d_name.name, dentry->d_name.len);
211 216
212 if (ret) { 217 if (ret)
213 make_bad_inode(inode); 218 goto fail;
214 iput(inode); 219
215 jffs2_free_raw_inode(ri); 220 ret = jffs2_init_security(inode, dir_i);
216 return ret; 221 if (ret)
217 } 222 goto fail;
223 ret = jffs2_init_acl(inode, dir_i);
224 if (ret)
225 goto fail;
218 226
219 dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); 227 dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
220 228
@@ -224,6 +232,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
224 D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", 232 D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
225 inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); 233 inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
226 return 0; 234 return 0;
235
236 fail:
237 make_bad_inode(inode);
238 iput(inode);
239 jffs2_free_raw_inode(ri);
240 return ret;
227} 241}
228 242
229/***********************************************************************/ 243/***********************************************************************/
@@ -374,6 +388,18 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
374 up(&f->sem); 388 up(&f->sem);
375 389
376 jffs2_complete_reservation(c); 390 jffs2_complete_reservation(c);
391
392 ret = jffs2_init_security(inode, dir_i);
393 if (ret) {
394 jffs2_clear_inode(inode);
395 return ret;
396 }
397 ret = jffs2_init_acl(inode, dir_i);
398 if (ret) {
399 jffs2_clear_inode(inode);
400 return ret;
401 }
402
377 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, 403 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
378 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 404 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
379 if (ret) { 405 if (ret) {
@@ -504,6 +530,18 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
504 up(&f->sem); 530 up(&f->sem);
505 531
506 jffs2_complete_reservation(c); 532 jffs2_complete_reservation(c);
533
534 ret = jffs2_init_security(inode, dir_i);
535 if (ret) {
536 jffs2_clear_inode(inode);
537 return ret;
538 }
539 ret = jffs2_init_acl(inode, dir_i);
540 if (ret) {
541 jffs2_clear_inode(inode);
542 return ret;
543 }
544
507 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, 545 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
508 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 546 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
509 if (ret) { 547 if (ret) {
@@ -660,6 +698,18 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
660 up(&f->sem); 698 up(&f->sem);
661 699
662 jffs2_complete_reservation(c); 700 jffs2_complete_reservation(c);
701
702 ret = jffs2_init_security(inode, dir_i);
703 if (ret) {
704 jffs2_clear_inode(inode);
705 return ret;
706 }
707 ret = jffs2_init_acl(inode, dir_i);
708 if (ret) {
709 jffs2_clear_inode(inode);
710 return ret;
711 }
712
663 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, 713 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
664 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); 714 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
665 if (ret) { 715 if (ret) {
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 9f4171213e58..e92187f34d5f 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -54,7 +54,12 @@ const struct file_operations jffs2_file_operations =
54 54
55struct inode_operations jffs2_file_inode_operations = 55struct inode_operations jffs2_file_inode_operations =
56{ 56{
57 .setattr = jffs2_setattr 57 .permission = jffs2_permission,
58 .setattr = jffs2_setattr,
59 .setxattr = jffs2_setxattr,
60 .getxattr = jffs2_getxattr,
61 .listxattr = jffs2_listxattr,
62 .removexattr = jffs2_removexattr
58}; 63};
59 64
60struct address_space_operations jffs2_file_address_operations = 65struct address_space_operations jffs2_file_address_operations =
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index ea1f37d4fc58..4607cdc4c46d 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -185,7 +185,12 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
185 185
186int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) 186int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
187{ 187{
188 return jffs2_do_setattr(dentry->d_inode, iattr); 188 int rc;
189
190 rc = jffs2_do_setattr(dentry->d_inode, iattr);
191 if (!rc && (iattr->ia_valid & ATTR_MODE))
192 rc = jffs2_acl_chmod(dentry->d_inode);
193 return rc;
189} 194}
190 195
191int jffs2_statfs(struct super_block *sb, struct kstatfs *buf) 196int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -224,6 +229,7 @@ void jffs2_clear_inode (struct inode *inode)
224 229
225 D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); 230 D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
226 231
232 jffs2_xattr_delete_inode(c, f->inocache);
227 jffs2_do_clear_inode(c, f); 233 jffs2_do_clear_inode(c, f);
228} 234}
229 235
@@ -497,6 +503,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
497 } 503 }
498 memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *)); 504 memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
499 505
506 jffs2_init_xattr_subsystem(c);
507
500 if ((ret = jffs2_do_mount_fs(c))) 508 if ((ret = jffs2_do_mount_fs(c)))
501 goto out_inohash; 509 goto out_inohash;
502 510
@@ -531,6 +539,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
531 else 539 else
532 kfree(c->blocks); 540 kfree(c->blocks);
533 out_inohash: 541 out_inohash:
542 jffs2_clear_xattr_subsystem(c);
534 kfree(c->inocache_list); 543 kfree(c->inocache_list);
535 out_wbuf: 544 out_wbuf:
536 jffs2_flash_cleanup(c); 545 jffs2_flash_cleanup(c);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 967fb2cf8e21..4ea1b7f0ae78 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
125 struct jffs2_eraseblock *jeb; 125 struct jffs2_eraseblock *jeb;
126 struct jffs2_raw_node_ref *raw; 126 struct jffs2_raw_node_ref *raw;
127 int ret = 0, inum, nlink; 127 int ret = 0, inum, nlink;
128 int xattr = 0;
128 129
129 if (down_interruptible(&c->alloc_sem)) 130 if (down_interruptible(&c->alloc_sem))
130 return -EINTR; 131 return -EINTR;
@@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
138 the node CRCs etc. Do it now. */ 139 the node CRCs etc. Do it now. */
139 140
140 /* checked_ino is protected by the alloc_sem */ 141 /* checked_ino is protected by the alloc_sem */
141 if (c->checked_ino > c->highest_ino) { 142 if (c->checked_ino > c->highest_ino && xattr) {
142 printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", 143 printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
143 c->unchecked_size); 144 c->unchecked_size);
144 jffs2_dbg_dump_block_lists_nolock(c); 145 jffs2_dbg_dump_block_lists_nolock(c);
@@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
148 149
149 spin_unlock(&c->erase_completion_lock); 150 spin_unlock(&c->erase_completion_lock);
150 151
152 if (!xattr)
153 xattr = jffs2_verify_xattr(c);
154
151 spin_lock(&c->inocache_lock); 155 spin_lock(&c->inocache_lock);
152 156
153 ic = jffs2_get_ino_cache(c, c->checked_ino++); 157 ic = jffs2_get_ino_cache(c, c->checked_ino++);
@@ -262,6 +266,16 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
262 266
263 ic = jffs2_raw_ref_to_ic(raw); 267 ic = jffs2_raw_ref_to_ic(raw);
264 268
269 /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr.
270 We can decide whether this node is inode or xattr by ic->class.
271 ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED.
272 ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED.
273 ret > 0 : ic is NOT xattr_datum/xattr_ref.
274 */
275 ret = jffs2_garbage_collect_xattr(c, ic);
276 if (ret <= 0)
277 goto release_sem;
278
265 /* We need to hold the inocache. Either the erase_completion_lock or 279 /* We need to hold the inocache. Either the erase_completion_lock or
266 the inocache_lock are sufficient; we trade down since the inocache_lock 280 the inocache_lock are sufficient; we trade down since the inocache_lock
267 causes less contention. */ 281 causes less contention. */
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h
index ad565bf9dcc1..2e0cc8e00b85 100644
--- a/fs/jffs2/jffs2_fs_i.h
+++ b/fs/jffs2/jffs2_fs_i.h
@@ -5,6 +5,7 @@
5 5
6#include <linux/version.h> 6#include <linux/version.h>
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include <linux/posix_acl.h>
8#include <asm/semaphore.h> 9#include <asm/semaphore.h>
9 10
10struct jffs2_inode_info { 11struct jffs2_inode_info {
@@ -45,6 +46,10 @@ struct jffs2_inode_info {
45 struct inode vfs_inode; 46 struct inode vfs_inode;
46#endif 47#endif
47#endif 48#endif
49#ifdef CONFIG_JFFS2_FS_POSIX_ACL
50 struct posix_acl *i_acl_access;
51 struct posix_acl *i_acl_default;
52#endif
48}; 53};
49 54
50#endif /* _JFFS2_FS_I */ 55#endif /* _JFFS2_FS_I */
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 4bcfb5570221..3b4e0edd6dbb 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -115,6 +115,16 @@ struct jffs2_sb_info {
115 115
116 struct jffs2_summary *summary; /* Summary information */ 116 struct jffs2_summary *summary; /* Summary information */
117 117
118#ifdef CONFIG_JFFS2_FS_XATTR
119#define XATTRINDEX_HASHSIZE (57)
120 uint32_t highest_xid;
121 struct list_head xattrindex[XATTRINDEX_HASHSIZE];
122 struct list_head xattr_temp;
123 struct list_head xattr_unchecked;
124 struct rw_semaphore xattr_sem;
125 uint32_t xdatum_mem_usage;
126 uint32_t xdatum_mem_threshold;
127#endif
118 /* OS-private pointer for getting back to master superblock info */ 128 /* OS-private pointer for getting back to master superblock info */
119 void *os_priv; 129 void *os_priv;
120}; 130};
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 036cbd11c004..3d5b7ecfbf8d 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab;
26static kmem_cache_t *raw_node_ref_slab; 26static kmem_cache_t *raw_node_ref_slab;
27static kmem_cache_t *node_frag_slab; 27static kmem_cache_t *node_frag_slab;
28static kmem_cache_t *inode_cache_slab; 28static kmem_cache_t *inode_cache_slab;
29#ifdef CONFIG_JFFS2_FS_XATTR
30static kmem_cache_t *xattr_datum_cache;
31static kmem_cache_t *xattr_ref_cache;
32#endif
29 33
30int __init jffs2_create_slab_caches(void) 34int __init jffs2_create_slab_caches(void)
31{ 35{
@@ -68,8 +72,24 @@ int __init jffs2_create_slab_caches(void)
68 inode_cache_slab = kmem_cache_create("jffs2_inode_cache", 72 inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
69 sizeof(struct jffs2_inode_cache), 73 sizeof(struct jffs2_inode_cache),
70 0, 0, NULL, NULL); 74 0, 0, NULL, NULL);
71 if (inode_cache_slab) 75 if (!inode_cache_slab)
72 return 0; 76 goto err;
77
78#ifdef CONFIG_JFFS2_FS_XATTR
79 xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum",
80 sizeof(struct jffs2_xattr_datum),
81 0, 0, NULL, NULL);
82 if (!xattr_datum_cache)
83 goto err;
84
85 xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref",
86 sizeof(struct jffs2_xattr_ref),
87 0, 0, NULL, NULL);
88 if (!xattr_ref_cache)
89 goto err;
90#endif
91
92 return 0;
73 err: 93 err:
74 jffs2_destroy_slab_caches(); 94 jffs2_destroy_slab_caches();
75 return -ENOMEM; 95 return -ENOMEM;
@@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void)
91 kmem_cache_destroy(node_frag_slab); 111 kmem_cache_destroy(node_frag_slab);
92 if(inode_cache_slab) 112 if(inode_cache_slab)
93 kmem_cache_destroy(inode_cache_slab); 113 kmem_cache_destroy(inode_cache_slab);
114#ifdef CONFIG_JFFS2_FS_XATTR
115 if (xattr_datum_cache)
116 kmem_cache_destroy(xattr_datum_cache);
117 if (xattr_ref_cache)
118 kmem_cache_destroy(xattr_ref_cache);
119#endif
94} 120}
95 121
96struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) 122struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
@@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
205 dbg_memalloc("%p\n", x); 231 dbg_memalloc("%p\n", x);
206 kmem_cache_free(inode_cache_slab, x); 232 kmem_cache_free(inode_cache_slab, x);
207} 233}
234
235#ifdef CONFIG_JFFS2_FS_XATTR
236struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
237{
238 struct jffs2_xattr_datum *xd;
239 xd = kmem_cache_alloc(xattr_datum_cache, GFP_KERNEL);
240 dbg_memalloc("%p\n", xd);
241
242 memset(xd, 0, sizeof(struct jffs2_xattr_datum));
243 xd->class = RAWNODE_CLASS_XATTR_DATUM;
244 INIT_LIST_HEAD(&xd->xindex);
245 return xd;
246}
247
248void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd)
249{
250 dbg_memalloc("%p\n", xd);
251 kmem_cache_free(xattr_datum_cache, xd);
252}
253
254struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
255{
256 struct jffs2_xattr_ref *ref;
257 ref = kmem_cache_alloc(xattr_ref_cache, GFP_KERNEL);
258 dbg_memalloc("%p\n", ref);
259
260 memset(ref, 0, sizeof(struct jffs2_xattr_ref));
261 ref->class = RAWNODE_CLASS_XATTR_REF;
262 INIT_LIST_HEAD(&ref->ilist);
263 return ref;
264}
265
266void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref)
267{
268 dbg_memalloc("%p\n", ref);
269 kmem_cache_free(xattr_ref_cache, ref);
270}
271#endif
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index d4d0c41490cd..9c575733659b 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -938,6 +938,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
938 this = c->inocache_list[i]; 938 this = c->inocache_list[i];
939 while (this) { 939 while (this) {
940 next = this->next; 940 next = this->next;
941 jffs2_xattr_free_inode(c, this);
941 jffs2_free_inode_cache(this); 942 jffs2_free_inode_cache(this);
942 this = next; 943 this = next;
943 } 944 }
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index f6645afe88e4..6f6279cf4909 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -20,6 +20,8 @@
20#include <linux/jffs2.h> 20#include <linux/jffs2.h>
21#include "jffs2_fs_sb.h" 21#include "jffs2_fs_sb.h"
22#include "jffs2_fs_i.h" 22#include "jffs2_fs_i.h"
23#include "xattr.h"
24#include "acl.h"
23#include "summary.h" 25#include "summary.h"
24 26
25#ifdef __ECOS 27#ifdef __ECOS
@@ -107,11 +109,16 @@ struct jffs2_inode_cache {
107 temporary lists of dirents, and later must be set to 109 temporary lists of dirents, and later must be set to
108 NULL to mark the end of the raw_node_ref->next_in_ino 110 NULL to mark the end of the raw_node_ref->next_in_ino
109 chain. */ 111 chain. */
112 u8 class; /* It's used for identification */
113 u8 flags;
114 uint16_t state;
110 struct jffs2_inode_cache *next; 115 struct jffs2_inode_cache *next;
111 struct jffs2_raw_node_ref *nodes; 116 struct jffs2_raw_node_ref *nodes;
112 uint32_t ino; 117 uint32_t ino;
113 int nlink; 118 int nlink;
114 int state; 119#ifdef CONFIG_JFFS2_FS_XATTR
120 struct list_head ilist;
121#endif
115}; 122};
116 123
117/* Inode states for 'state' above. We need the 'GC' state to prevent 124/* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -125,6 +132,12 @@ struct jffs2_inode_cache {
125#define INO_STATE_READING 5 /* In read_inode() */ 132#define INO_STATE_READING 5 /* In read_inode() */
126#define INO_STATE_CLEARING 6 /* In clear_inode() */ 133#define INO_STATE_CLEARING 6 /* In clear_inode() */
127 134
135#define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */
136
137#define RAWNODE_CLASS_INODE_CACHE 0
138#define RAWNODE_CLASS_XATTR_DATUM 1
139#define RAWNODE_CLASS_XATTR_REF 2
140
128#define INOCACHE_HASHSIZE 128 141#define INOCACHE_HASHSIZE 128
129 142
130/* 143/*
@@ -374,6 +387,12 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void);
374void jffs2_free_node_frag(struct jffs2_node_frag *); 387void jffs2_free_node_frag(struct jffs2_node_frag *);
375struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); 388struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
376void jffs2_free_inode_cache(struct jffs2_inode_cache *); 389void jffs2_free_inode_cache(struct jffs2_inode_cache *);
390#ifdef CONFIG_JFFS2_FS_XATTR
391struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void);
392void jffs2_free_xattr_datum(struct jffs2_xattr_datum *);
393struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
394void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
395#endif
377 396
378/* gc.c */ 397/* gc.c */
379int jffs2_garbage_collect_pass(struct jffs2_sb_info *c); 398int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index d307cf548625..9936ae23f8dc 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -60,6 +60,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
60 f->target = NULL; 60 f->target = NULL;
61 f->flags = 0; 61 f->flags = 0;
62 f->usercompr = 0; 62 f->usercompr = 0;
63#ifdef CONFIG_JFFS2_FS_POSIX_ACL
64 f->i_acl_access = JFFS2_ACL_NOT_CACHED;
65 f->i_acl_default = JFFS2_ACL_NOT_CACHED;
66#endif
63} 67}
64 68
65 69
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index e1acce8fb2bf..61ccdf4f1042 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
902 f->inocache->ino = f->inocache->nlink = 1; 902 f->inocache->ino = f->inocache->nlink = 1;
903 f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; 903 f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
904 f->inocache->state = INO_STATE_READING; 904 f->inocache->state = INO_STATE_READING;
905 init_xattr_inode_cache(f->inocache);
905 jffs2_add_ino_cache(c, f->inocache); 906 jffs2_add_ino_cache(c, f->inocache);
906 } 907 }
907 if (!f->inocache) { 908 if (!f->inocache) {
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index cf55b221fc2b..f09689e320fe 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
306 return BLK_STATE_ALLDIRTY; 306 return BLK_STATE_ALLDIRTY;
307} 307}
308 308
309#ifdef CONFIG_JFFS2_FS_XATTR
310static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
311 struct jffs2_raw_xattr *rx, uint32_t ofs,
312 struct jffs2_summary *s)
313{
314 struct jffs2_xattr_datum *xd;
315 struct jffs2_raw_node_ref *raw;
316 uint32_t totlen, crc;
317
318 crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
319 if (crc != je32_to_cpu(rx->node_crc)) {
320 if (je32_to_cpu(rx->node_crc) != 0xffffffff)
321 JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
322 ofs, je32_to_cpu(rx->node_crc), crc);
323 DIRTY_SPACE(je32_to_cpu(rx->totlen));
324 return 0;
325 }
326
327 totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
328 if (totlen != je32_to_cpu(rx->totlen)) {
329 JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
330 ofs, je32_to_cpu(rx->totlen), totlen);
331 DIRTY_SPACE(je32_to_cpu(rx->totlen));
332 return 0;
333 }
334
335 raw = jffs2_alloc_raw_node_ref();
336 if (!raw)
337 return -ENOMEM;
338
339 xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
340 if (IS_ERR(xd)) {
341 jffs2_free_raw_node_ref(raw);
342 if (PTR_ERR(xd) == -EEXIST) {
343 DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
344 return 0;
345 }
346 return PTR_ERR(xd);
347 }
348 xd->xprefix = rx->xprefix;
349 xd->name_len = rx->name_len;
350 xd->value_len = je16_to_cpu(rx->value_len);
351 xd->data_crc = je32_to_cpu(rx->data_crc);
352 xd->node = raw;
353
354 raw->__totlen = totlen;
355 raw->flash_offset = ofs | REF_PRISTINE;
356 raw->next_phys = NULL;
357 raw->next_in_ino = (void *)xd;
358 if (!jeb->first_node)
359 jeb->first_node = raw;
360 if (jeb->last_node)
361 jeb->last_node->next_phys = raw;
362 jeb->last_node = raw;
363
364 USED_SPACE(PAD(je32_to_cpu(rx->totlen)));
365 if (jffs2_sum_active())
366 jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
367 dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n",
368 ofs, xd->xid, xd->version);
369 return 0;
370}
371
372static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
373 struct jffs2_raw_xref *rr, uint32_t ofs,
374 struct jffs2_summary *s)
375{
376 struct jffs2_xattr_ref *ref;
377 struct jffs2_raw_node_ref *raw;
378 uint32_t crc;
379
380 crc = crc32(0, rr, sizeof(*rr) - 4);
381 if (crc != je32_to_cpu(rr->node_crc)) {
382 if (je32_to_cpu(rr->node_crc) != 0xffffffff)
383 JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
384 ofs, je32_to_cpu(rr->node_crc), crc);
385 DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen)));
386 return 0;
387 }
388
389 if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) {
390 JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
391 ofs, je32_to_cpu(rr->totlen),
392 PAD(sizeof(struct jffs2_raw_xref)));
393 DIRTY_SPACE(je32_to_cpu(rr->totlen));
394 return 0;
395 }
396
397 ref = jffs2_alloc_xattr_ref();
398 if (!ref)
399 return -ENOMEM;
400
401 raw = jffs2_alloc_raw_node_ref();
402 if (!raw) {
403 jffs2_free_xattr_ref(ref);
404 return -ENOMEM;
405 }
406
407 /* BEFORE jffs2_build_xattr_subsystem() called,
408 * ref->xid is used to store 32bit xid, xd is not used
409 * ref->ino is used to store 32bit inode-number, ic is not used
410 * Thoes variables are declared as union, thus using those
411 * are exclusive. In a similar way, ref->ilist is temporarily
412 * used to chain all xattr_ref object. It's re-chained to
413 * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly.
414 */
415 ref->node = raw;
416 ref->ino = je32_to_cpu(rr->ino);
417 ref->xid = je32_to_cpu(rr->xid);
418 list_add_tail(&ref->ilist, &c->xattr_temp);
419
420 raw->__totlen = PAD(je32_to_cpu(rr->totlen));
421 raw->flash_offset = ofs | REF_PRISTINE;
422 raw->next_phys = NULL;
423 raw->next_in_ino = (void *)ref;
424 if (!jeb->first_node)
425 jeb->first_node = raw;
426 if (jeb->last_node)
427 jeb->last_node->next_phys = raw;
428 jeb->last_node = raw;
429
430 USED_SPACE(PAD(je32_to_cpu(rr->totlen)));
431 if (jffs2_sum_active())
432 jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
433 dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n",
434 ofs, ref->xid, ref->ino);
435 return 0;
436}
437#endif
438
309static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 439static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
310 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { 440 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
311 struct jffs2_unknown_node *node; 441 struct jffs2_unknown_node *node;
@@ -614,6 +744,43 @@ scan_more:
614 ofs += PAD(je32_to_cpu(node->totlen)); 744 ofs += PAD(je32_to_cpu(node->totlen));
615 break; 745 break;
616 746
747#ifdef CONFIG_JFFS2_FS_XATTR
748 case JFFS2_NODETYPE_XATTR:
749 if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
750 buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
751 D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
752 " left to end of buf. Reading 0x%x at 0x%08x\n",
753 je32_to_cpu(node->totlen), buf_len, ofs));
754 err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
755 if (err)
756 return err;
757 buf_ofs = ofs;
758 node = (void *)buf;
759 }
760 err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
761 if (err)
762 return err;
763 ofs += PAD(je32_to_cpu(node->totlen));
764 break;
765 case JFFS2_NODETYPE_XREF:
766 if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
767 buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
768 D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
769 " left to end of buf. Reading 0x%x at 0x%08x\n",
770 je32_to_cpu(node->totlen), buf_len, ofs));
771 err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
772 if (err)
773 return err;
774 buf_ofs = ofs;
775 node = (void *)buf;
776 }
777 err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
778 if (err)
779 return err;
780 ofs += PAD(je32_to_cpu(node->totlen));
781 break;
782#endif /* CONFIG_JFFS2_FS_XATTR */
783
617 case JFFS2_NODETYPE_CLEANMARKER: 784 case JFFS2_NODETYPE_CLEANMARKER:
618 D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); 785 D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
619 if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { 786 if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
@@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
721 888
722 ic->ino = ino; 889 ic->ino = ino;
723 ic->nodes = (void *)ic; 890 ic->nodes = (void *)ic;
891 init_xattr_inode_cache(ic);
724 jffs2_add_ino_cache(c, ic); 892 jffs2_add_ino_cache(c, ic);
725 if (ino == 1) 893 if (ino == 1)
726 ic->nlink = 1; 894 ic->nlink = 1;
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
new file mode 100644
index 000000000000..4b6c3b22524f
--- /dev/null
+++ b/fs/jffs2/security.c
@@ -0,0 +1,82 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/security.c
3 * Security Labels support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/fs.h>
14#include <linux/time.h>
15#include <linux/pagemap.h>
16#include <linux/highmem.h>
17#include <linux/crc32.h>
18#include <linux/jffs2.h>
19#include <linux/xattr.h>
20#include <linux/mtd/mtd.h>
21#include <linux/security.h>
22#include "nodelist.h"
23
24/* ---- Initial Security Label Attachment -------------- */
25int jffs2_init_security(struct inode *inode, struct inode *dir)
26{
27 int rc;
28 size_t len;
29 void *value;
30 char *name;
31
32 rc = security_inode_init_security(inode, dir, &name, &value, &len);
33 if (rc) {
34 if (rc == -EOPNOTSUPP)
35 return 0;
36 return rc;
37 }
38 rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
39
40 kfree(name);
41 kfree(value);
42 return rc;
43}
44
45/* ---- XATTR Handler for "security.*" ----------------- */
46static int jffs2_security_getxattr(struct inode *inode, const char *name,
47 void *buffer, size_t size)
48{
49 if (!strcmp(name, ""))
50 return -EINVAL;
51
52 return do_jffs2_getxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size);
53}
54
55static int jffs2_security_setxattr(struct inode *inode, const char *name, const void *buffer,
56 size_t size, int flags)
57{
58 if (!strcmp(name, ""))
59 return -EINVAL;
60
61 return do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size, flags);
62}
63
64static size_t jffs2_security_listxattr(struct inode *inode, char *list, size_t list_size,
65 const char *name, size_t name_len)
66{
67 size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
68
69 if (list && retlen <= list_size) {
70 strcpy(list, XATTR_SECURITY_PREFIX);
71 strcpy(list + XATTR_SECURITY_PREFIX_LEN, name);
72 }
73
74 return retlen;
75}
76
77struct xattr_handler jffs2_security_xattr_handler = {
78 .prefix = XATTR_SECURITY_PREFIX,
79 .list = jffs2_security_listxattr,
80 .set = jffs2_security_setxattr,
81 .get = jffs2_security_getxattr
82};
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 7b0ed77a4c35..5d9ec8e36528 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -5,6 +5,7 @@
5 * Zoltan Sogor <weth@inf.u-szeged.hu>, 5 * Zoltan Sogor <weth@inf.u-szeged.hu>,
6 * Patrik Kluba <pajko@halom.u-szeged.hu>, 6 * Patrik Kluba <pajko@halom.u-szeged.hu>,
7 * University of Szeged, Hungary 7 * University of Szeged, Hungary
8 * 2005 KaiGai Kohei <kaigai@ak.jp.nec.com>
8 * 9 *
9 * For licensing information, see the file 'LICENCE' in this directory. 10 * For licensing information, see the file 'LICENCE' in this directory.
10 * 11 *
@@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
81 dbg_summary("dirent (%u) added to summary\n", 82 dbg_summary("dirent (%u) added to summary\n",
82 je32_to_cpu(item->d.ino)); 83 je32_to_cpu(item->d.ino));
83 break; 84 break;
85#ifdef CONFIG_JFFS2_FS_XATTR
86 case JFFS2_NODETYPE_XATTR:
87 s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
88 s->sum_num++;
89 dbg_summary("xattr (xid=%u, version=%u) added to summary\n",
90 je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version));
91 break;
92 case JFFS2_NODETYPE_XREF:
93 s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
94 s->sum_num++;
95 dbg_summary("xref added to summary\n");
96 break;
97#endif
84 default: 98 default:
85 JFFS2_WARNING("UNKNOWN node type %u\n", 99 JFFS2_WARNING("UNKNOWN node type %u\n",
86 je16_to_cpu(item->u.nodetype)); 100 je16_to_cpu(item->u.nodetype));
@@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r
141 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 155 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
142} 156}
143 157
158#ifdef CONFIG_JFFS2_FS_XATTR
159int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs)
160{
161 struct jffs2_sum_xattr_mem *temp;
162
163 temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
164 if (!temp)
165 return -ENOMEM;
166
167 temp->nodetype = rx->nodetype;
168 temp->xid = rx->xid;
169 temp->version = rx->version;
170 temp->offset = cpu_to_je32(ofs);
171 temp->totlen = rx->totlen;
172 temp->next = NULL;
173
174 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
175}
176
177int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs)
178{
179 struct jffs2_sum_xref_mem *temp;
180
181 temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
182 if (!temp)
183 return -ENOMEM;
184
185 temp->nodetype = rr->nodetype;
186 temp->offset = cpu_to_je32(ofs);
187 temp->next = NULL;
188
189 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
190}
191#endif
144/* Cleanup every collected summary information */ 192/* Cleanup every collected summary information */
145 193
146static void jffs2_sum_clean_collected(struct jffs2_summary *s) 194static void jffs2_sum_clean_collected(struct jffs2_summary *s)
@@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
259 307
260 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 308 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
261 } 309 }
310#ifdef CONFIG_JFFS2_FS_XATTR
311 case JFFS2_NODETYPE_XATTR: {
312 struct jffs2_sum_xattr_mem *temp;
313 if (je32_to_cpu(node->x.version) == 0xffffffff)
314 return 0;
315 temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
316 if (!temp)
317 goto no_mem;
262 318
319 temp->nodetype = node->x.nodetype;
320 temp->xid = node->x.xid;
321 temp->version = node->x.version;
322 temp->totlen = node->x.totlen;
323 temp->offset = cpu_to_je32(ofs);
324 temp->next = NULL;
325
326 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
327 }
328 case JFFS2_NODETYPE_XREF: {
329 struct jffs2_sum_xref_mem *temp;
330
331 if (je32_to_cpu(node->r.ino) == 0xffffffff
332 && je32_to_cpu(node->r.xid) == 0xffffffff)
333 return 0;
334 temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
335 if (!temp)
336 goto no_mem;
337 temp->nodetype = node->r.nodetype;
338 temp->offset = cpu_to_je32(ofs);
339 temp->next = NULL;
340
341 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
342 }
343#endif
263 case JFFS2_NODETYPE_PADDING: 344 case JFFS2_NODETYPE_PADDING:
264 dbg_summary("node PADDING\n"); 345 dbg_summary("node PADDING\n");
265 c->summary->sum_padded += je32_to_cpu(node->u.totlen); 346 c->summary->sum_padded += je32_to_cpu(node->u.totlen);
@@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
408 489
409 break; 490 break;
410 } 491 }
492#ifdef CONFIG_JFFS2_FS_XATTR
493 case JFFS2_NODETYPE_XATTR: {
494 struct jffs2_xattr_datum *xd;
495 struct jffs2_sum_xattr_flash *spx;
496 uint32_t ofs;
497
498 spx = (struct jffs2_sum_xattr_flash *)sp;
499 ofs = jeb->offset + je32_to_cpu(spx->offset);
500 dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs,
501 je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
502 raw = jffs2_alloc_raw_node_ref();
503 if (!raw) {
504 JFFS2_NOTICE("allocation of node reference failed\n");
505 kfree(summary);
506 return -ENOMEM;
507 }
508 xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
509 je32_to_cpu(spx->version));
510 if (IS_ERR(xd)) {
511 JFFS2_NOTICE("allocation of xattr_datum failed\n");
512 jffs2_free_raw_node_ref(raw);
513 kfree(summary);
514 return PTR_ERR(xd);
515 }
516 xd->node = raw;
411 517
518 raw->flash_offset = ofs | REF_UNCHECKED;
519 raw->__totlen = PAD(je32_to_cpu(spx->totlen));
520 raw->next_phys = NULL;
521 raw->next_in_ino = (void *)xd;
522 if (!jeb->first_node)
523 jeb->first_node = raw;
524 if (jeb->last_node)
525 jeb->last_node->next_phys = raw;
526 jeb->last_node = raw;
527
528 *pseudo_random += je32_to_cpu(spx->xid);
529 UNCHECKED_SPACE(je32_to_cpu(spx->totlen));
530 sp += JFFS2_SUMMARY_XATTR_SIZE;
531
532 break;
533 }
534 case JFFS2_NODETYPE_XREF: {
535 struct jffs2_xattr_ref *ref;
536 struct jffs2_sum_xref_flash *spr;
537 uint32_t ofs;
538
539 spr = (struct jffs2_sum_xref_flash *)sp;
540 ofs = jeb->offset + je32_to_cpu(spr->offset);
541 dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs,
542 je32_to_cpu(spr->xid), je32_to_cpu(spr->ino));
543 raw = jffs2_alloc_raw_node_ref();
544 if (!raw) {
545 JFFS2_NOTICE("allocation of node reference failed\n");
546 kfree(summary);
547 return -ENOMEM;
548 }
549 ref = jffs2_alloc_xattr_ref();
550 if (!ref) {
551 JFFS2_NOTICE("allocation of xattr_datum failed\n");
552 jffs2_free_raw_node_ref(raw);
553 kfree(summary);
554 return -ENOMEM;
555 }
556 ref->ino = 0xfffffffe;
557 ref->xid = 0xfffffffd;
558 ref->node = raw;
559 list_add_tail(&ref->ilist, &c->xattr_temp);
560
561 raw->__totlen = PAD(sizeof(struct jffs2_raw_xref));
562 raw->flash_offset = ofs | REF_UNCHECKED;
563 raw->next_phys = NULL;
564 raw->next_in_ino = (void *)ref;
565 if (!jeb->first_node)
566 jeb->first_node = raw;
567 if (jeb->last_node)
568 jeb->last_node->next_phys = raw;
569 jeb->last_node = raw;
570
571 UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref)));
572 *pseudo_random += ofs;
573 sp += JFFS2_SUMMARY_XREF_SIZE;
574
575 break;
576 }
577#endif
412 default : { 578 default : {
579printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
413 JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); 580 JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
414 kfree(summary); 581 kfree(summary);
415 return -EIO; 582 return -EIO;
@@ -617,7 +784,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
617 784
618 break; 785 break;
619 } 786 }
787#ifdef CONFIG_JFFS2_FS_XATTR
788 case JFFS2_NODETYPE_XATTR: {
789 struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
790
791 temp = c->summary->sum_list_head;
792 sxattr_ptr->nodetype = temp->x.nodetype;
793 sxattr_ptr->xid = temp->x.xid;
794 sxattr_ptr->version = temp->x.version;
795 sxattr_ptr->offset = temp->x.offset;
796 sxattr_ptr->totlen = temp->x.totlen;
797
798 wpage += JFFS2_SUMMARY_XATTR_SIZE;
799 break;
800 }
801 case JFFS2_NODETYPE_XREF: {
802 struct jffs2_sum_xref_flash *sxref_ptr = wpage;
803
804 temp = c->summary->sum_list_head;
805 sxref_ptr->nodetype = temp->r.nodetype;
806 sxref_ptr->offset = temp->r.offset;
620 807
808 wpage += JFFS2_SUMMARY_XREF_SIZE;
809 break;
810 }
811#endif
621 default : { 812 default : {
622 BUG(); /* unknown node in summary information */ 813 BUG(); /* unknown node in summary information */
623 } 814 }
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
index b7a678be1709..a3b66c18aae9 100644
--- a/fs/jffs2/summary.h
+++ b/fs/jffs2/summary.h
@@ -45,6 +45,8 @@
45#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff 45#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
46#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) 46#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
47#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) 47#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
48#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
49#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
48 50
49/* Summary structures used on flash */ 51/* Summary structures used on flash */
50 52
@@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash
75 uint8_t name[0]; /* dirent name */ 77 uint8_t name[0]; /* dirent name */
76} __attribute__((packed)); 78} __attribute__((packed));
77 79
80struct jffs2_sum_xattr_flash
81{
82 jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
83 jint32_t xid; /* xattr identifier */
84 jint32_t version; /* version number */
85 jint32_t offset; /* offset on jeb */
86 jint32_t totlen; /* node length */
87} __attribute__((packed));
88
89struct jffs2_sum_xref_flash
90{
91 jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
92 jint32_t offset; /* offset on jeb */
93} __attribute__((packed));
94
78union jffs2_sum_flash 95union jffs2_sum_flash
79{ 96{
80 struct jffs2_sum_unknown_flash u; 97 struct jffs2_sum_unknown_flash u;
81 struct jffs2_sum_inode_flash i; 98 struct jffs2_sum_inode_flash i;
82 struct jffs2_sum_dirent_flash d; 99 struct jffs2_sum_dirent_flash d;
100 struct jffs2_sum_xattr_flash x;
101 struct jffs2_sum_xref_flash r;
83}; 102};
84 103
85/* Summary structures used in the memory */ 104/* Summary structures used in the memory */
@@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem
114 uint8_t name[0]; /* dirent name */ 133 uint8_t name[0]; /* dirent name */
115} __attribute__((packed)); 134} __attribute__((packed));
116 135
136struct jffs2_sum_xattr_mem
137{
138 union jffs2_sum_mem *next;
139 jint16_t nodetype;
140 jint32_t xid;
141 jint32_t version;
142 jint32_t offset;
143 jint32_t totlen;
144} __attribute__((packed));
145
146struct jffs2_sum_xref_mem
147{
148 union jffs2_sum_mem *next;
149 jint16_t nodetype;
150 jint32_t offset;
151} __attribute__((packed));
152
117union jffs2_sum_mem 153union jffs2_sum_mem
118{ 154{
119 struct jffs2_sum_unknown_mem u; 155 struct jffs2_sum_unknown_mem u;
120 struct jffs2_sum_inode_mem i; 156 struct jffs2_sum_inode_mem i;
121 struct jffs2_sum_dirent_mem d; 157 struct jffs2_sum_dirent_mem d;
158 struct jffs2_sum_xattr_mem x;
159 struct jffs2_sum_xref_mem r;
122}; 160};
123 161
124/* Summary related information stored in superblock */ 162/* Summary related information stored in superblock */
@@ -159,6 +197,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
159int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); 197int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
160int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); 198int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
161int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); 199int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
200int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs);
201int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs);
162int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 202int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
163 uint32_t ofs, uint32_t *pseudo_random); 203 uint32_t ofs, uint32_t *pseudo_random);
164 204
@@ -176,6 +216,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
176#define jffs2_sum_add_padding_mem(a,b) 216#define jffs2_sum_add_padding_mem(a,b)
177#define jffs2_sum_add_inode_mem(a,b,c) 217#define jffs2_sum_add_inode_mem(a,b,c)
178#define jffs2_sum_add_dirent_mem(a,b,c) 218#define jffs2_sum_add_dirent_mem(a,b,c)
219#define jffs2_sum_add_xattr_mem(a,b,c)
220#define jffs2_sum_add_xref_mem(a,b,c)
179#define jffs2_sum_scan_sumnode(a,b,c,d) (0) 221#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
180 222
181#endif /* CONFIG_JFFS2_SUMMARY */ 223#endif /* CONFIG_JFFS2_SUMMARY */
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index ffd8e84b22cc..c8b539ee7d80 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -151,7 +151,10 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
151 151
152 sb->s_op = &jffs2_super_operations; 152 sb->s_op = &jffs2_super_operations;
153 sb->s_flags = flags | MS_NOATIME; 153 sb->s_flags = flags | MS_NOATIME;
154 154 sb->s_xattr = jffs2_xattr_handlers;
155#ifdef CONFIG_JFFS2_FS_POSIX_ACL
156 sb->s_flags |= MS_POSIXACL;
157#endif
155 ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); 158 ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
156 159
157 if (ret) { 160 if (ret) {
@@ -293,6 +296,7 @@ static void jffs2_put_super (struct super_block *sb)
293 kfree(c->blocks); 296 kfree(c->blocks);
294 jffs2_flash_cleanup(c); 297 jffs2_flash_cleanup(c);
295 kfree(c->inocache_list); 298 kfree(c->inocache_list);
299 jffs2_clear_xattr_subsystem(c);
296 if (c->mtd->sync) 300 if (c->mtd->sync)
297 c->mtd->sync(c->mtd); 301 c->mtd->sync(c->mtd);
298 302
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index d55754fe8925..fc211b6e9b03 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_inode_operations =
24{ 24{
25 .readlink = generic_readlink, 25 .readlink = generic_readlink,
26 .follow_link = jffs2_follow_link, 26 .follow_link = jffs2_follow_link,
27 .setattr = jffs2_setattr 27 .permission = jffs2_permission,
28 .setattr = jffs2_setattr,
29 .setxattr = jffs2_setxattr,
30 .getxattr = jffs2_getxattr,
31 .listxattr = jffs2_listxattr,
32 .removexattr = jffs2_removexattr
28}; 33};
29 34
30static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) 35static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 1342f0158e9b..d5c78195f3b8 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
36 f->inocache->nlink = 1; 36 f->inocache->nlink = 1;
37 f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; 37 f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
38 f->inocache->state = INO_STATE_PRESENT; 38 f->inocache->state = INO_STATE_PRESENT;
39 39 init_xattr_inode_cache(f->inocache);
40 40
41 jffs2_add_ino_cache(c, f->inocache); 41 jffs2_add_ino_cache(c, f->inocache);
42 D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); 42 D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
new file mode 100644
index 000000000000..c9a185c54ce7
--- /dev/null
+++ b/fs/jffs2/xattr.c
@@ -0,0 +1,1271 @@
1/* -------------------------------------------------------------------------
2 * File: fs/jffs2/xattr.c
3 * XATTR support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 * ------------------------------------------------------------------------- */
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/fs.h>
14#include <linux/time.h>
15#include <linux/pagemap.h>
16#include <linux/highmem.h>
17#include <linux/crc32.h>
18#include <linux/jffs2.h>
19#include <linux/xattr.h>
20#include <linux/mtd/mtd.h>
21#include "nodelist.h"
22/* -------- xdatum related functions ----------------
23 * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
24 * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
25 * the index of the xattr name/value pair cache (c->xattrindex).
26 * unload_xattr_datum(c, xd)
27 * is used to release xattr name/value pair and detach from c->xattrindex.
28 * reclaim_xattr_datum(c)
29 * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
30 * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold
31 * is hard coded as 32KiB.
32 * delete_xattr_datum_node(c, xd)
33 * is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is
34 * enabled, it overwrites the obsolete node by myself.
35 * delete_xattr_datum(c, xd)
36 * is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference
37 * counter. (It means how many jffs2_xattr_ref object refers this xdatum.)
38 * do_verify_xattr_datum(c, xd)
39 * is used to load the xdatum informations without name/value pair from the medium.
40 * It's necessary once, because those informations are not collected during mounting
41 * process when EBS is enabled.
42 * 0 will be returned, if success. An negative return value means recoverable error, and
43 * positive return value means unrecoverable error. Thus, caller must remove this xdatum
44 * and xref when it returned positive value.
45 * do_load_xattr_datum(c, xd)
46 * is used to load name/value pair from the medium.
47 * The meanings of return value is same as do_verify_xattr_datum().
48 * load_xattr_datum(c, xd)
49 * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum().
50 * If xd need to call do_verify_xattr_datum() at first, it's called before calling
51 * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum().
52 * save_xattr_datum(c, xd, phys_ofs)
53 * is used to write xdatum to medium. xd->version will be incremented.
54 * create_xattr_datum(c, xprefix, xname, xvalue, xsize, phys_ofs)
55 * is used to create new xdatum and write to medium.
56 * -------------------------------------------------- */
57
58static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
59{
60 int name_len = strlen(xname);
61
62 return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
63}
64
65static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
66{
67 /* must be called under down_write(xattr_sem) */
68 D1(dbg_xattr("%s: xid=%u, version=%u\n", __FUNCTION__, xd->xid, xd->version));
69 if (xd->xname) {
70 c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len);
71 kfree(xd->xname);
72 }
73
74 list_del_init(&xd->xindex);
75 xd->hashkey = 0;
76 xd->xname = NULL;
77 xd->xvalue = NULL;
78}
79
80static void reclaim_xattr_datum(struct jffs2_sb_info *c)
81{
82 /* must be called under down_write(xattr_sem) */
83 struct jffs2_xattr_datum *xd, *_xd;
84 uint32_t target, before;
85 static int index = 0;
86 int count;
87
88 if (c->xdatum_mem_threshold > c->xdatum_mem_usage)
89 return;
90
91 before = c->xdatum_mem_usage;
92 target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */
93 for (count = 0; count < XATTRINDEX_HASHSIZE; count++) {
94 list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) {
95 if (xd->flags & JFFS2_XFLAGS_HOT) {
96 xd->flags &= ~JFFS2_XFLAGS_HOT;
97 } else if (!(xd->flags & JFFS2_XFLAGS_BIND)) {
98 unload_xattr_datum(c, xd);
99 }
100 if (c->xdatum_mem_usage <= target)
101 goto out;
102 }
103 index = (index+1) % XATTRINDEX_HASHSIZE;
104 }
105 out:
106 JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n",
107 before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
108}
109
110static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
111{
112 /* must be called under down_write(xattr_sem) */
113 struct jffs2_raw_xattr rx;
114 uint32_t length;
115 int rc;
116
117 if (!xd->node) {
118 JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid);
119 return;
120 }
121 if (jffs2_sum_active()) {
122 memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr));
123 rc = jffs2_flash_read(c, ref_offset(xd->node),
124 sizeof(struct jffs2_unknown_node),
125 &length, (char *)&rx);
126 if (rc || length != sizeof(struct jffs2_unknown_node)) {
127 JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
128 rc, sizeof(struct jffs2_unknown_node),
129 length, ref_offset(xd->node));
130 }
131 rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx),
132 &length, (char *)&rx);
133 if (rc || length != sizeof(struct jffs2_raw_xattr)) {
134 JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u ar %#08x\n",
135 rc, sizeof(rx), length, ref_offset(xd->node));
136 }
137 }
138 spin_lock(&c->erase_completion_lock);
139 xd->node->next_in_ino = NULL;
140 spin_unlock(&c->erase_completion_lock);
141 jffs2_mark_node_obsolete(c, xd->node);
142 xd->node = NULL;
143}
144
145static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
146{
147 /* must be called under down_write(xattr_sem) */
148 BUG_ON(xd->refcnt);
149
150 unload_xattr_datum(c, xd);
151 if (xd->node) {
152 delete_xattr_datum_node(c, xd);
153 xd->node = NULL;
154 }
155 jffs2_free_xattr_datum(xd);
156}
157
158static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
159{
160 /* must be called under down_write(xattr_sem) */
161 struct jffs2_eraseblock *jeb;
162 struct jffs2_raw_xattr rx;
163 size_t readlen;
164 uint32_t crc, totlen;
165 int rc;
166
167 BUG_ON(!xd->node);
168 BUG_ON(ref_flags(xd->node) != REF_UNCHECKED);
169
170 rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx);
171 if (rc || readlen != sizeof(rx)) {
172 JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
173 rc, sizeof(rx), readlen, ref_offset(xd->node));
174 return rc ? rc : -EIO;
175 }
176 crc = crc32(0, &rx, sizeof(rx) - 4);
177 if (crc != je32_to_cpu(rx.node_crc)) {
178 if (je32_to_cpu(rx.node_crc) != 0xffffffff)
179 JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
180 ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc);
181 return EIO;
182 }
183 totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
184 if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
185 || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR
186 || je32_to_cpu(rx.totlen) != totlen
187 || je32_to_cpu(rx.xid) != xd->xid
188 || je32_to_cpu(rx.version) != xd->version) {
189 JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
190 "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
191 ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
192 je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
193 je32_to_cpu(rx.totlen), totlen,
194 je32_to_cpu(rx.xid), xd->xid,
195 je32_to_cpu(rx.version), xd->version);
196 return EIO;
197 }
198 xd->xprefix = rx.xprefix;
199 xd->name_len = rx.name_len;
200 xd->value_len = je16_to_cpu(rx.value_len);
201 xd->data_crc = je32_to_cpu(rx.data_crc);
202
203 /* This JFFS2_NODETYPE_XATTR node is checked */
204 jeb = &c->blocks[ref_offset(xd->node) / c->sector_size];
205 totlen = PAD(je32_to_cpu(rx.totlen));
206
207 spin_lock(&c->erase_completion_lock);
208 c->unchecked_size -= totlen; c->used_size += totlen;
209 jeb->unchecked_size -= totlen; jeb->used_size += totlen;
210 xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE;
211 spin_unlock(&c->erase_completion_lock);
212
213 /* unchecked xdatum is chained with c->xattr_unchecked */
214 list_del_init(&xd->xindex);
215
216 dbg_xattr("success on verfying xdatum (xid=%u, version=%u)\n",
217 xd->xid, xd->version);
218
219 return 0;
220}
221
222static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
223{
224 /* must be called under down_write(xattr_sem) */
225 char *data;
226 size_t readlen;
227 uint32_t crc, length;
228 int i, ret, retry = 0;
229
230 BUG_ON(!xd->node);
231 BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
232 BUG_ON(!list_empty(&xd->xindex));
233 retry:
234 length = xd->name_len + 1 + xd->value_len;
235 data = kmalloc(length, GFP_KERNEL);
236 if (!data)
237 return -ENOMEM;
238
239 ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr),
240 length, &readlen, data);
241
242 if (ret || length!=readlen) {
243 JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%d, at %#08x\n",
244 ret, length, readlen, ref_offset(xd->node));
245 kfree(data);
246 return ret ? ret : -EIO;
247 }
248
249 data[xd->name_len] = '\0';
250 crc = crc32(0, data, length);
251 if (crc != xd->data_crc) {
252 JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)"
253 " at %#08x, read: 0x%08x calculated: 0x%08x\n",
254 ref_offset(xd->node), xd->data_crc, crc);
255 kfree(data);
256 return EIO;
257 }
258
259 xd->flags |= JFFS2_XFLAGS_HOT;
260 xd->xname = data;
261 xd->xvalue = data + xd->name_len+1;
262
263 c->xdatum_mem_usage += length;
264
265 xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len);
266 i = xd->hashkey % XATTRINDEX_HASHSIZE;
267 list_add(&xd->xindex, &c->xattrindex[i]);
268 if (!retry) {
269 retry = 1;
270 reclaim_xattr_datum(c);
271 if (!xd->xname)
272 goto retry;
273 }
274
275 dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n",
276 xd->xid, xd->xprefix, xd->xname);
277
278 return 0;
279}
280
281static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
282{
283 /* must be called under down_write(xattr_sem);
284 * rc < 0 : recoverable error, try again
285 * rc = 0 : success
286 * rc > 0 : Unrecoverable error, this node should be deleted.
287 */
288 int rc = 0;
289 BUG_ON(xd->xname);
290 if (!xd->node)
291 return EIO;
292 if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) {
293 rc = do_verify_xattr_datum(c, xd);
294 if (rc > 0) {
295 list_del_init(&xd->xindex);
296 delete_xattr_datum_node(c, xd);
297 }
298 }
299 if (!rc)
300 rc = do_load_xattr_datum(c, xd);
301 return rc;
302}
303
304static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, uint32_t phys_ofs)
305{
306 /* must be called under down_write(xattr_sem) */
307 struct jffs2_raw_xattr rx;
308 struct jffs2_raw_node_ref *raw;
309 struct kvec vecs[2];
310 uint32_t length;
311 int rc, totlen;
312
313 BUG_ON(!xd->xname);
314
315 vecs[0].iov_base = &rx;
316 vecs[0].iov_len = PAD(sizeof(rx));
317 vecs[1].iov_base = xd->xname;
318 vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
319 totlen = vecs[0].iov_len + vecs[1].iov_len;
320
321 raw = jffs2_alloc_raw_node_ref();
322 if (!raw)
323 return -ENOMEM;
324 raw->flash_offset = phys_ofs;
325 raw->__totlen = PAD(totlen);
326 raw->next_phys = NULL;
327 raw->next_in_ino = (void *)xd;
328
329 /* Setup raw-xattr */
330 rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
331 rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
332 rx.totlen = cpu_to_je32(PAD(totlen));
333 rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
334
335 rx.xid = cpu_to_je32(xd->xid);
336 rx.version = cpu_to_je32(++xd->version);
337 rx.xprefix = xd->xprefix;
338 rx.name_len = xd->name_len;
339 rx.value_len = cpu_to_je16(xd->value_len);
340 rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
341 rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));
342
343 rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);
344 if (rc || totlen != length) {
345 JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n",
346 rc, totlen, length, phys_ofs);
347 rc = rc ? rc : -EIO;
348 if (length) {
349 raw->flash_offset |= REF_OBSOLETE;
350 raw->next_in_ino = NULL;
351 jffs2_add_physical_node_ref(c, raw);
352 jffs2_mark_node_obsolete(c, raw);
353 } else {
354 jffs2_free_raw_node_ref(raw);
355 }
356 return rc;
357 }
358 BUG_ON(raw->__totlen < sizeof(struct jffs2_raw_xattr));
359 /* success */
360 raw->flash_offset |= REF_PRISTINE;
361 jffs2_add_physical_node_ref(c, raw);
362 if (xd->node)
363 delete_xattr_datum_node(c, xd);
364 xd->node = raw;
365
366 dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
367 xd->xid, xd->version, xd->xprefix, xd->xname);
368
369 return 0;
370}
371
372static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
373 int xprefix, const char *xname,
374 const char *xvalue, int xsize,
375 uint32_t phys_ofs)
376{
377 /* must be called under down_write(xattr_sem) */
378 struct jffs2_xattr_datum *xd;
379 uint32_t hashkey, name_len;
380 char *data;
381 int i, rc;
382
383 /* Search xattr_datum has same xname/xvalue by index */
384 hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize);
385 i = hashkey % XATTRINDEX_HASHSIZE;
386 list_for_each_entry(xd, &c->xattrindex[i], xindex) {
387 if (xd->hashkey==hashkey
388 && xd->xprefix==xprefix
389 && xd->value_len==xsize
390 && !strcmp(xd->xname, xname)
391 && !memcmp(xd->xvalue, xvalue, xsize)) {
392 xd->refcnt++;
393 return xd;
394 }
395 }
396
397 /* Not found, Create NEW XATTR-Cache */
398 name_len = strlen(xname);
399
400 xd = jffs2_alloc_xattr_datum();
401 if (!xd)
402 return ERR_PTR(-ENOMEM);
403
404 data = kmalloc(name_len + 1 + xsize, GFP_KERNEL);
405 if (!data) {
406 jffs2_free_xattr_datum(xd);
407 return ERR_PTR(-ENOMEM);
408 }
409 strcpy(data, xname);
410 memcpy(data + name_len + 1, xvalue, xsize);
411
412 xd->refcnt = 1;
413 xd->xid = ++c->highest_xid;
414 xd->flags |= JFFS2_XFLAGS_HOT;
415 xd->xprefix = xprefix;
416
417 xd->hashkey = hashkey;
418 xd->xname = data;
419 xd->xvalue = data + name_len + 1;
420 xd->name_len = name_len;
421 xd->value_len = xsize;
422 xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len);
423
424 rc = save_xattr_datum(c, xd, phys_ofs);
425 if (rc) {
426 kfree(xd->xname);
427 jffs2_free_xattr_datum(xd);
428 return ERR_PTR(rc);
429 }
430
431 /* Insert Hash Index */
432 i = hashkey % XATTRINDEX_HASHSIZE;
433 list_add(&xd->xindex, &c->xattrindex[i]);
434
435 c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len);
436 reclaim_xattr_datum(c);
437
438 return xd;
439}
440
441/* -------- xdatum related functions ----------------
442 * verify_xattr_ref(c, ref)
443 * is used to load xref information from medium. Because summary data does not
444 * contain xid/ino, it's necessary to verify once while mounting process.
445 * delete_xattr_ref_node(c, ref)
446 * is used to delete a jffs2 node is dominated by xref. When EBS is enabled,
447 * it overwrites the obsolete node by myself.
448 * delete_xattr_ref(c, ref)
449 * is used to delete jffs2_xattr_ref object. If the reference counter of xdatum
450 * is refered by this xref become 0, delete_xattr_datum() is called later.
451 * save_xattr_ref(c, ref, phys_ofs)
452 * is used to write xref to medium.
453 * create_xattr_ref(c, ic, xd, phys_ofs)
454 * is used to create a new xref and write to medium.
455 * jffs2_xattr_delete_inode(c, ic)
456 * is called to remove xrefs related to obsolete inode when inode is unlinked.
457 * jffs2_xattr_free_inode(c, ic)
458 * is called to release xattr related objects when unmounting.
459 * check_xattr_ref_ilist(c, ic)
460 * is used to confirm inode does not have duplicate xattr name/value pair.
461 * -------------------------------------------------- */
462static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
463{
464 struct jffs2_eraseblock *jeb;
465 struct jffs2_raw_xref rr;
466 size_t readlen;
467 uint32_t crc, totlen;
468 int rc;
469
470 BUG_ON(ref_flags(ref->node) != REF_UNCHECKED);
471
472 rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr);
473 if (rc || sizeof(rr) != readlen) {
474 JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u, at %#08x\n",
475 rc, sizeof(rr), readlen, ref_offset(ref->node));
476 return rc ? rc : -EIO;
477 }
478 /* obsolete node */
479 crc = crc32(0, &rr, sizeof(rr) - 4);
480 if (crc != je32_to_cpu(rr.node_crc)) {
481 if (je32_to_cpu(rr.node_crc) != 0xffffffff)
482 JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
483 ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc);
484 return EIO;
485 }
486 if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
487 || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
488 || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
489 JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
490 "nodetype=%#04x/%#04x, totlen=%u/%u\n",
491 ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
492 je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
493 je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
494 return EIO;
495 }
496 ref->ino = je32_to_cpu(rr.ino);
497 ref->xid = je32_to_cpu(rr.xid);
498
499 /* fixup superblock/eraseblock info */
500 jeb = &c->blocks[ref_offset(ref->node) / c->sector_size];
501 totlen = PAD(sizeof(rr));
502
503 spin_lock(&c->erase_completion_lock);
504 c->unchecked_size -= totlen; c->used_size += totlen;
505 jeb->unchecked_size -= totlen; jeb->used_size += totlen;
506 ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE;
507 spin_unlock(&c->erase_completion_lock);
508
509 dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
510 ref->ino, ref->xid, ref_offset(ref->node));
511 return 0;
512}
513
514static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
515{
516 struct jffs2_raw_xref rr;
517 uint32_t length;
518 int rc;
519
520 if (jffs2_sum_active()) {
521 memset(&rr, 0xff, sizeof(rr));
522 rc = jffs2_flash_read(c, ref_offset(ref->node),
523 sizeof(struct jffs2_unknown_node),
524 &length, (char *)&rr);
525 if (rc || length != sizeof(struct jffs2_unknown_node)) {
526 JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
527 rc, sizeof(struct jffs2_unknown_node),
528 length, ref_offset(ref->node));
529 }
530 rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr),
531 &length, (char *)&rr);
532 if (rc || length != sizeof(struct jffs2_raw_xref)) {
533 JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u at %#08x\n",
534 rc, sizeof(rr), length, ref_offset(ref->node));
535 }
536 }
537 spin_lock(&c->erase_completion_lock);
538 ref->node->next_in_ino = NULL;
539 spin_unlock(&c->erase_completion_lock);
540 jffs2_mark_node_obsolete(c, ref->node);
541 ref->node = NULL;
542}
543
544static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
545{
546 /* must be called under down_write(xattr_sem) */
547 struct jffs2_xattr_datum *xd;
548
549 BUG_ON(!ref->node);
550 delete_xattr_ref_node(c, ref);
551
552 list_del(&ref->ilist);
553 xd = ref->xd;
554 xd->refcnt--;
555 if (!xd->refcnt)
556 delete_xattr_datum(c, xd);
557 jffs2_free_xattr_ref(ref);
558}
559
560static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, uint32_t phys_ofs)
561{
562 /* must be called under down_write(xattr_sem) */
563 struct jffs2_raw_node_ref *raw;
564 struct jffs2_raw_xref rr;
565 uint32_t length;
566 int ret;
567
568 raw = jffs2_alloc_raw_node_ref();
569 if (!raw)
570 return -ENOMEM;
571 raw->flash_offset = phys_ofs;
572 raw->__totlen = PAD(sizeof(rr));
573 raw->next_phys = NULL;
574 raw->next_in_ino = (void *)ref;
575
576 rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
577 rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
578 rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
579 rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
580
581 rr.ino = cpu_to_je32(ref->ic->ino);
582 rr.xid = cpu_to_je32(ref->xd->xid);
583 rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
584
585 ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
586 if (ret || sizeof(rr) != length) {
587 JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n",
588 ret, sizeof(rr), length, phys_ofs);
589 ret = ret ? ret : -EIO;
590 if (length) {
591 raw->flash_offset |= REF_OBSOLETE;
592 raw->next_in_ino = NULL;
593 jffs2_add_physical_node_ref(c, raw);
594 jffs2_mark_node_obsolete(c, raw);
595 } else {
596 jffs2_free_raw_node_ref(raw);
597 }
598 return ret;
599 }
600 raw->flash_offset |= REF_PRISTINE;
601
602 jffs2_add_physical_node_ref(c, raw);
603 if (ref->node)
604 delete_xattr_ref_node(c, ref);
605 ref->node = raw;
606
607 dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
608
609 return 0;
610}
611
612static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic,
613 struct jffs2_xattr_datum *xd, uint32_t phys_ofs)
614{
615 /* must be called under down_write(xattr_sem) */
616 struct jffs2_xattr_ref *ref;
617 int ret;
618
619 ref = jffs2_alloc_xattr_ref();
620 if (!ref)
621 return ERR_PTR(-ENOMEM);
622 ref->ic = ic;
623 ref->xd = xd;
624
625 ret = save_xattr_ref(c, ref, phys_ofs);
626 if (ret) {
627 jffs2_free_xattr_ref(ref);
628 return ERR_PTR(ret);
629 }
630
631 /* Chain to inode */
632 list_add(&ref->ilist, &ic->ilist);
633
634 return ref; /* success */
635}
636
637void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
638{
639 /* It's called from jffs2_clear_inode() on inode removing.
640 When an inode with XATTR is removed, those XATTRs must be removed. */
641 struct jffs2_xattr_ref *ref, *_ref;
642
643 if (!ic || ic->nlink > 0)
644 return;
645
646 down_write(&c->xattr_sem);
647 list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist)
648 delete_xattr_ref(c, ref);
649 up_write(&c->xattr_sem);
650}
651
652void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
653{
654 /* It's called from jffs2_free_ino_caches() until unmounting FS. */
655 struct jffs2_xattr_datum *xd;
656 struct jffs2_xattr_ref *ref, *_ref;
657
658 down_write(&c->xattr_sem);
659 list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) {
660 list_del(&ref->ilist);
661 xd = ref->xd;
662 xd->refcnt--;
663 if (!xd->refcnt) {
664 unload_xattr_datum(c, xd);
665 jffs2_free_xattr_datum(xd);
666 }
667 jffs2_free_xattr_ref(ref);
668 }
669 up_write(&c->xattr_sem);
670}
671
672static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
673{
674 /* success of check_xattr_ref_ilist() means taht inode (ic) dose not have
675 * duplicate name/value pairs. If duplicate name/value pair would be found,
676 * one will be removed.
677 */
678 struct jffs2_xattr_ref *ref, *cmp;
679 int rc = 0;
680
681 if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
682 return 0;
683 down_write(&c->xattr_sem);
684 retry:
685 rc = 0;
686 list_for_each_entry(ref, &ic->ilist, ilist) {
687 if (!ref->xd->xname) {
688 rc = load_xattr_datum(c, ref->xd);
689 if (unlikely(rc > 0)) {
690 delete_xattr_ref(c, ref);
691 goto retry;
692 } else if (unlikely(rc < 0))
693 goto out;
694 }
695 cmp = ref;
696 list_for_each_entry_continue(cmp, &ic->ilist, ilist) {
697 if (!cmp->xd->xname) {
698 ref->xd->flags |= JFFS2_XFLAGS_BIND;
699 rc = load_xattr_datum(c, cmp->xd);
700 ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
701 if (unlikely(rc > 0)) {
702 delete_xattr_ref(c, cmp);
703 goto retry;
704 } else if (unlikely(rc < 0))
705 goto out;
706 }
707 if (ref->xd->xprefix == cmp->xd->xprefix
708 && !strcmp(ref->xd->xname, cmp->xd->xname)) {
709 delete_xattr_ref(c, cmp);
710 goto retry;
711 }
712 }
713 }
714 ic->flags |= INO_FLAGS_XATTR_CHECKED;
715 out:
716 up_write(&c->xattr_sem);
717
718 return rc;
719}
720
721/* -------- xattr subsystem functions ---------------
722 * jffs2_init_xattr_subsystem(c)
723 * is used to initialize semaphore and list_head, and some variables.
724 * jffs2_find_xattr_datum(c, xid)
725 * is used to lookup xdatum while scanning process.
726 * jffs2_clear_xattr_subsystem(c)
727 * is used to release any xattr related objects.
728 * jffs2_build_xattr_subsystem(c)
729 * is used to associate xdatum and xref while super block building process.
730 * jffs2_setup_xattr_datum(c, xid, version)
731 * is used to insert xdatum while scanning process.
732 * -------------------------------------------------- */
733void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
734{
735 int i;
736
737 for (i=0; i < XATTRINDEX_HASHSIZE; i++)
738 INIT_LIST_HEAD(&c->xattrindex[i]);
739 INIT_LIST_HEAD(&c->xattr_temp);
740 INIT_LIST_HEAD(&c->xattr_unchecked);
741
742 init_rwsem(&c->xattr_sem);
743 c->xdatum_mem_usage = 0;
744 c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */
745}
746
747static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid)
748{
749 struct jffs2_xattr_datum *xd;
750 int i = xid % XATTRINDEX_HASHSIZE;
751
752 /* It's only used in scanning/building process. */
753 BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING)));
754
755 list_for_each_entry(xd, &c->xattrindex[i], xindex) {
756 if (xd->xid==xid)
757 return xd;
758 }
759 return NULL;
760}
761
762void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
763{
764 struct jffs2_xattr_datum *xd, *_xd;
765 struct jffs2_xattr_ref *ref, *_ref;
766 int i;
767
768 list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist)
769 jffs2_free_xattr_ref(ref);
770
771 for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
772 list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
773 list_del(&xd->xindex);
774 if (xd->xname)
775 kfree(xd->xname);
776 jffs2_free_xattr_datum(xd);
777 }
778 }
779}
780
781void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
782{
783 struct jffs2_xattr_ref *ref, *_ref;
784 struct jffs2_xattr_datum *xd, *_xd;
785 struct jffs2_inode_cache *ic;
786 int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
787
788 BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
789
790 /* Phase.1 */
791 list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) {
792 list_del_init(&ref->ilist);
793 /* checking REF_UNCHECKED nodes */
794 if (ref_flags(ref->node) != REF_PRISTINE) {
795 if (verify_xattr_ref(c, ref)) {
796 delete_xattr_ref_node(c, ref);
797 jffs2_free_xattr_ref(ref);
798 continue;
799 }
800 }
801 /* At this point, ref->xid and ref->ino contain XID and inode number.
802 ref->xd and ref->ic are not valid yet. */
803 xd = jffs2_find_xattr_datum(c, ref->xid);
804 ic = jffs2_get_ino_cache(c, ref->ino);
805 if (!xd || !ic) {
806 if (ref_flags(ref->node) != REF_UNCHECKED)
807 JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
808 ref->ino, ref->xid);
809 delete_xattr_ref_node(c, ref);
810 jffs2_free_xattr_ref(ref);
811 continue;
812 }
813 ref->xd = xd;
814 ref->ic = ic;
815 xd->refcnt++;
816 list_add_tail(&ref->ilist, &ic->ilist);
817 xref_count++;
818 }
819 /* After this, ref->xid/ino are NEVER used. */
820
821 /* Phase.2 */
822 for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
823 list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
824 list_del_init(&xd->xindex);
825 if (!xd->refcnt) {
826 if (ref_flags(xd->node) != REF_UNCHECKED)
827 JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
828 xd->xid, xd->version, ref_offset(xd->node));
829 delete_xattr_datum(c, xd);
830 continue;
831 }
832 if (ref_flags(xd->node) != REF_PRISTINE) {
833 dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
834 xd->xid, ref_offset(xd->node));
835 list_add(&xd->xindex, &c->xattr_unchecked);
836 xdatum_unchecked_count++;
837 }
838 xdatum_count++;
839 }
840 }
841 /* build complete */
842 JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
843 "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
844}
845
846struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
847 uint32_t xid, uint32_t version)
848{
849 struct jffs2_xattr_datum *xd, *_xd;
850
851 _xd = jffs2_find_xattr_datum(c, xid);
852 if (_xd) {
853 dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
854 xid, version, _xd->version, ref_offset(_xd->node));
855 if (version < _xd->version)
856 return ERR_PTR(-EEXIST);
857 }
858 xd = jffs2_alloc_xattr_datum();
859 if (!xd)
860 return ERR_PTR(-ENOMEM);
861 xd->xid = xid;
862 xd->version = version;
863 if (xd->xid > c->highest_xid)
864 c->highest_xid = xd->xid;
865 list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
866
867 if (_xd) {
868 list_del_init(&_xd->xindex);
869 delete_xattr_datum_node(c, _xd);
870 jffs2_free_xattr_datum(_xd);
871 }
872 return xd;
873}
874
875/* -------- xattr subsystem functions ---------------
876 * xprefix_to_handler(xprefix)
877 * is used to translate xprefix into xattr_handler.
878 * jffs2_listxattr(dentry, buffer, size)
879 * is an implementation of listxattr handler on jffs2.
880 * do_jffs2_getxattr(inode, xprefix, xname, buffer, size)
881 * is an implementation of getxattr handler on jffs2.
882 * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags)
883 * is an implementation of setxattr handler on jffs2.
884 * -------------------------------------------------- */
885struct xattr_handler *jffs2_xattr_handlers[] = {
886 &jffs2_user_xattr_handler,
887#ifdef CONFIG_JFFS2_FS_SECURITY
888 &jffs2_security_xattr_handler,
889#endif
890#ifdef CONFIG_JFFS2_FS_POSIX_ACL
891 &jffs2_acl_access_xattr_handler,
892 &jffs2_acl_default_xattr_handler,
893#endif
894 &jffs2_trusted_xattr_handler,
895 NULL
896};
897
898static struct xattr_handler *xprefix_to_handler(int xprefix) {
899 struct xattr_handler *ret;
900
901 switch (xprefix) {
902 case JFFS2_XPREFIX_USER:
903 ret = &jffs2_user_xattr_handler;
904 break;
905#ifdef CONFIG_JFFS2_FS_SECURITY
906 case JFFS2_XPREFIX_SECURITY:
907 ret = &jffs2_security_xattr_handler;
908 break;
909#endif
910#ifdef CONFIG_JFFS2_FS_POSIX_ACL
911 case JFFS2_XPREFIX_ACL_ACCESS:
912 ret = &jffs2_acl_access_xattr_handler;
913 break;
914 case JFFS2_XPREFIX_ACL_DEFAULT:
915 ret = &jffs2_acl_default_xattr_handler;
916 break;
917#endif
918 case JFFS2_XPREFIX_TRUSTED:
919 ret = &jffs2_trusted_xattr_handler;
920 break;
921 default:
922 ret = NULL;
923 break;
924 }
925 return ret;
926}
927
928ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
929{
930 struct inode *inode = dentry->d_inode;
931 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
932 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
933 struct jffs2_inode_cache *ic = f->inocache;
934 struct jffs2_xattr_ref *ref;
935 struct jffs2_xattr_datum *xd;
936 struct xattr_handler *xhandle;
937 ssize_t len, rc;
938 int retry = 0;
939
940 rc = check_xattr_ref_ilist(c, ic);
941 if (unlikely(rc))
942 return rc;
943
944 down_read(&c->xattr_sem);
945 retry:
946 len = 0;
947 list_for_each_entry(ref, &ic->ilist, ilist) {
948 BUG_ON(ref->ic != ic);
949 xd = ref->xd;
950 if (!xd->xname) {
951 /* xdatum is unchached */
952 if (!retry) {
953 retry = 1;
954 up_read(&c->xattr_sem);
955 down_write(&c->xattr_sem);
956 goto retry;
957 } else {
958 rc = load_xattr_datum(c, xd);
959 if (unlikely(rc > 0)) {
960 delete_xattr_ref(c, ref);
961 goto retry;
962 } else if (unlikely(rc < 0))
963 goto out;
964 }
965 }
966 xhandle = xprefix_to_handler(xd->xprefix);
967 if (!xhandle)
968 continue;
969 if (buffer) {
970 rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len);
971 } else {
972 rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len);
973 }
974 if (rc < 0)
975 goto out;
976 len += rc;
977 }
978 rc = len;
979 out:
980 if (!retry) {
981 up_read(&c->xattr_sem);
982 } else {
983 up_write(&c->xattr_sem);
984 }
985 return rc;
986}
987
988int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
989 char *buffer, size_t size)
990{
991 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
992 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
993 struct jffs2_inode_cache *ic = f->inocache;
994 struct jffs2_xattr_datum *xd;
995 struct jffs2_xattr_ref *ref;
996 int rc, retry = 0;
997
998 rc = check_xattr_ref_ilist(c, ic);
999 if (unlikely(rc))
1000 return rc;
1001
1002 down_read(&c->xattr_sem);
1003 retry:
1004 list_for_each_entry(ref, &ic->ilist, ilist) {
1005 BUG_ON(ref->ic!=ic);
1006
1007 xd = ref->xd;
1008 if (xd->xprefix != xprefix)
1009 continue;
1010 if (!xd->xname) {
1011 /* xdatum is unchached */
1012 if (!retry) {
1013 retry = 1;
1014 up_read(&c->xattr_sem);
1015 down_write(&c->xattr_sem);
1016 goto retry;
1017 } else {
1018 rc = load_xattr_datum(c, xd);
1019 if (unlikely(rc > 0)) {
1020 delete_xattr_ref(c, ref);
1021 goto retry;
1022 } else if (unlikely(rc < 0)) {
1023 goto out;
1024 }
1025 }
1026 }
1027 if (!strcmp(xname, xd->xname)) {
1028 rc = xd->value_len;
1029 if (buffer) {
1030 if (size < rc) {
1031 rc = -ERANGE;
1032 } else {
1033 memcpy(buffer, xd->xvalue, rc);
1034 }
1035 }
1036 goto out;
1037 }
1038 }
1039 rc = -ENODATA;
1040 out:
1041 if (!retry) {
1042 up_read(&c->xattr_sem);
1043 } else {
1044 up_write(&c->xattr_sem);
1045 }
1046 return rc;
1047}
1048
1049int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
1050 const char *buffer, size_t size, int flags)
1051{
1052 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1053 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1054 struct jffs2_inode_cache *ic = f->inocache;
1055 struct jffs2_xattr_datum *xd;
1056 struct jffs2_xattr_ref *ref, *newref;
1057 uint32_t phys_ofs, length, request;
1058 int rc;
1059
1060 rc = check_xattr_ref_ilist(c, ic);
1061 if (unlikely(rc))
1062 return rc;
1063
1064 request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size);
1065 rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
1066 ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE);
1067 if (rc) {
1068 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1069 return rc;
1070 }
1071
1072 /* Find existing xattr */
1073 down_write(&c->xattr_sem);
1074 retry:
1075 list_for_each_entry(ref, &ic->ilist, ilist) {
1076 xd = ref->xd;
1077 if (xd->xprefix != xprefix)
1078 continue;
1079 if (!xd->xname) {
1080 rc = load_xattr_datum(c, xd);
1081 if (unlikely(rc > 0)) {
1082 delete_xattr_ref(c, ref);
1083 goto retry;
1084 } else if (unlikely(rc < 0))
1085 goto out;
1086 }
1087 if (!strcmp(xd->xname, xname)) {
1088 if (flags & XATTR_CREATE) {
1089 rc = -EEXIST;
1090 goto out;
1091 }
1092 if (!buffer) {
1093 delete_xattr_ref(c, ref);
1094 rc = 0;
1095 goto out;
1096 }
1097 goto found;
1098 }
1099 }
1100 /* not found */
1101 ref = NULL;
1102 if (flags & XATTR_REPLACE) {
1103 rc = -ENODATA;
1104 goto out;
1105 }
1106 if (!buffer) {
1107 rc = -EINVAL;
1108 goto out;
1109 }
1110 found:
1111 xd = create_xattr_datum(c, xprefix, xname, buffer, size, phys_ofs);
1112 if (IS_ERR(xd)) {
1113 rc = PTR_ERR(xd);
1114 goto out;
1115 }
1116 up_write(&c->xattr_sem);
1117 jffs2_complete_reservation(c);
1118
1119 /* create xattr_ref */
1120 request = PAD(sizeof(struct jffs2_raw_xref));
1121 rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
1122 ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
1123 if (rc) {
1124 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1125 down_write(&c->xattr_sem);
1126 xd->refcnt--;
1127 if (!xd->refcnt)
1128 delete_xattr_datum(c, xd);
1129 up_write(&c->xattr_sem);
1130 return rc;
1131 }
1132 down_write(&c->xattr_sem);
1133 newref = create_xattr_ref(c, ic, xd, phys_ofs);
1134 if (IS_ERR(newref)) {
1135 rc = PTR_ERR(newref);
1136 xd->refcnt--;
1137 if (!xd->refcnt)
1138 delete_xattr_datum(c, xd);
1139 } else if (ref) {
1140 /* If replaced xattr_ref exists */
1141 delete_xattr_ref(c, ref);
1142 }
1143 out:
1144 up_write(&c->xattr_sem);
1145 jffs2_complete_reservation(c);
1146 return rc;
1147}
1148
1149/* -------- garbage collector functions -------------
1150 * jffs2_garbage_collect_xattr_datum(c, xd)
1151 * is used to move xdatum into new node.
1152 * jffs2_garbage_collect_xattr_ref(c, ref)
1153 * is used to move xref into new node.
1154 * jffs2_garbage_collect_xattr(c, ic)
1155 * is used to call appropriate garbage collector function, if argument
1156 * pointer (ic) is the reference of xdatum/xref.
1157 * jffs2_verify_xattr(c)
1158 * is used to call do_verify_xattr_datum() before garbage collecting.
1159 * -------------------------------------------------- */
1160static int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c,
1161 struct jffs2_xattr_datum *xd)
1162{
1163 /* must be called under down_write(xattr_sem), and called from GC thread */
1164 uint32_t phys_ofs, totlen, length, old_ofs;
1165 int rc;
1166
1167 BUG_ON(!xd->node);
1168
1169 old_ofs = ref_offset(xd->node);
1170 totlen = ref_totlen(c, c->gcblock, xd->node);
1171 if (totlen < sizeof(struct jffs2_raw_xattr))
1172 return -EINVAL;
1173
1174 if (!xd->xname) {
1175 rc = load_xattr_datum(c, xd);
1176 if (unlikely(rc > 0)) {
1177 delete_xattr_datum_node(c, xd);
1178 return 0;
1179 } else if (unlikely(rc < 0))
1180 return -EINVAL;
1181 }
1182 rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XATTR_SIZE);
1183 if (rc || length < totlen) {
1184 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
1185 return rc ? rc : -EBADFD;
1186 }
1187 rc = save_xattr_datum(c, xd, phys_ofs);
1188 if (!rc)
1189 dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
1190 xd->xid, xd->version, old_ofs, ref_offset(xd->node));
1191 return rc;
1192}
1193
1194
1195static int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c,
1196 struct jffs2_xattr_ref *ref)
1197{
1198 /* must be called under down(alloc_sem) */
1199 uint32_t phys_ofs, totlen, length, old_ofs;
1200 int rc;
1201
1202 BUG_ON(!ref->node);
1203
1204 old_ofs = ref_offset(ref->node);
1205 totlen = ref_totlen(c, c->gcblock, ref->node);
1206 if (totlen != sizeof(struct jffs2_raw_xref))
1207 return -EINVAL;
1208 rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XREF_SIZE);
1209 if (rc || length < totlen) {
1210 JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
1211 __FUNCTION__, rc, totlen);
1212 return rc ? rc : -EBADFD;
1213 }
1214 rc = save_xattr_ref(c, ref, phys_ofs);
1215 if (!rc)
1216 dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
1217 ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
1218 return rc;
1219}
1220
1221int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
1222{
1223 struct jffs2_xattr_datum *xd;
1224 struct jffs2_xattr_ref *ref;
1225 int ret;
1226
1227 switch (ic->class) {
1228 case RAWNODE_CLASS_XATTR_DATUM:
1229 spin_unlock(&c->erase_completion_lock);
1230
1231 down_write(&c->xattr_sem);
1232 xd = (struct jffs2_xattr_datum *)ic;
1233 ret = xd ? jffs2_garbage_collect_xattr_datum(c, xd) : 0;
1234 up_write(&c->xattr_sem);
1235 break;
1236 case RAWNODE_CLASS_XATTR_REF:
1237 spin_unlock(&c->erase_completion_lock);
1238
1239 down_write(&c->xattr_sem);
1240 ref = (struct jffs2_xattr_ref *)ic;
1241 ret = ref ? jffs2_garbage_collect_xattr_ref(c, ref) : 0;
1242 up_write(&c->xattr_sem);
1243 break;
1244 default:
1245 /* This node is not xattr_datum/xattr_ref */
1246 ret = 1;
1247 break;
1248 }
1249 return ret;
1250}
1251
1252int jffs2_verify_xattr(struct jffs2_sb_info *c)
1253{
1254 struct jffs2_xattr_datum *xd, *_xd;
1255 int rc;
1256
1257 down_write(&c->xattr_sem);
1258 list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
1259 rc = do_verify_xattr_datum(c, xd);
1260 if (rc == 0) {
1261 list_del_init(&xd->xindex);
1262 break;
1263 } else if (rc > 0) {
1264 list_del_init(&xd->xindex);
1265 delete_xattr_datum_node(c, xd);
1266 }
1267 }
1268 up_write(&c->xattr_sem);
1269
1270 return list_empty(&c->xattr_unchecked) ? 1 : 0;
1271}
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
new file mode 100644
index 000000000000..d157ad641ed4
--- /dev/null
+++ b/fs/jffs2/xattr.h
@@ -0,0 +1,120 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/xattr.c
3 * XATTR support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10
11#ifndef _JFFS2_FS_XATTR_H_
12#define _JFFS2_FS_XATTR_H_
13
14#include <linux/xattr.h>
15
16#define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */
17#define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */
18
19struct jffs2_xattr_datum
20{
21 void *always_null;
22 u8 class;
23 u8 flags;
24 u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
25
26 struct jffs2_raw_node_ref *node;
27 struct list_head xindex; /* chained from c->xattrindex[n] */
28 uint32_t refcnt; /* # of xattr_ref refers this */
29 uint32_t xid;
30 uint32_t version;
31
32 uint32_t data_crc;
33 uint32_t hashkey;
34 char *xname; /* XATTR name without prefix */
35 uint32_t name_len; /* length of xname */
36 char *xvalue; /* XATTR value */
37 uint32_t value_len; /* length of xvalue */
38};
39
40struct jffs2_inode_cache; /* forward refence */
41struct jffs2_xattr_ref
42{
43 void *always_null;
44 u8 class;
45 u8 flags; /* Currently unused */
46 u16 unused;
47
48 struct jffs2_raw_node_ref *node;
49 union {
50 struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */
51 uint32_t ino; /* only used in scanning/building */
52 };
53 union {
54 struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */
55 uint32_t xid; /* only used in sccanning/building */
56 };
57 struct list_head ilist; /* chained from ic->ilist */
58};
59
60#ifdef CONFIG_JFFS2_FS_XATTR
61
62extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
63extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c);
64extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
65
66extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
67 uint32_t xid, uint32_t version);
68
69extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
70extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
71
72extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
73extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
74
75extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
76 char *buffer, size_t size);
77extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
78 const char *buffer, size_t size, int flags);
79
80extern struct xattr_handler *jffs2_xattr_handlers[];
81extern struct xattr_handler jffs2_user_xattr_handler;
82extern struct xattr_handler jffs2_trusted_xattr_handler;
83
84extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
85#define jffs2_getxattr generic_getxattr
86#define jffs2_setxattr generic_setxattr
87#define jffs2_removexattr generic_removexattr
88
89/*---- Any inline initialize functions ----*/
90#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
91
92#else
93
94#define jffs2_init_xattr_subsystem(c)
95#define jffs2_build_xattr_subsystem(c)
96#define jffs2_clear_xattr_subsystem(c)
97
98#define jffs2_xattr_delete_inode(c, ic)
99#define jffs2_xattr_free_inode(c, ic)
100#define jffs2_garbage_collect_xattr(c, ic) (1)
101#define jffs2_verify_xattr(c) (1)
102
103#define jffs2_xattr_handlers NULL
104#define jffs2_listxattr NULL
105#define jffs2_getxattr NULL
106#define jffs2_setxattr NULL
107#define jffs2_removexattr NULL
108
109#define init_xattr_inode_cache(x)
110
111#endif /* CONFIG_JFFS2_FS_XATTR */
112
113#ifdef CONFIG_JFFS2_FS_SECURITY
114extern int jffs2_init_security(struct inode *inode, struct inode *dir);
115extern struct xattr_handler jffs2_security_xattr_handler;
116#else
117#define jffs2_init_security(inode,dir) (0)
118#endif /* CONFIG_JFFS2_FS_SECURITY */
119
120#endif /* _JFFS2_FS_XATTR_H_ */
diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c
new file mode 100644
index 000000000000..a018c9c31a60
--- /dev/null
+++ b/fs/jffs2/xattr_trusted.c
@@ -0,0 +1,51 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/xattr_trusted.c
3 * XATTR support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10#include <linux/kernel.h>
11#include <linux/fs.h>
12#include <linux/jffs2.h>
13#include <linux/xattr.h>
14#include <linux/mtd/mtd.h>
15#include "nodelist.h"
16
17static int jffs2_trusted_getxattr(struct inode *inode, const char *name,
18 void *buffer, size_t size)
19{
20 if (!strcmp(name, ""))
21 return -EINVAL;
22 return do_jffs2_getxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size);
23}
24
25static int jffs2_trusted_setxattr(struct inode *inode, const char *name, const void *buffer,
26 size_t size, int flags)
27{
28 if (!strcmp(name, ""))
29 return -EINVAL;
30 return do_jffs2_setxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags);
31}
32
33static size_t jffs2_trusted_listxattr(struct inode *inode, char *list, size_t list_size,
34 const char *name, size_t name_len)
35{
36 size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
37
38 if (list && retlen<=list_size) {
39 strcpy(list, XATTR_TRUSTED_PREFIX);
40 strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
41 }
42
43 return retlen;
44}
45
46struct xattr_handler jffs2_trusted_xattr_handler = {
47 .prefix = XATTR_TRUSTED_PREFIX,
48 .list = jffs2_trusted_listxattr,
49 .set = jffs2_trusted_setxattr,
50 .get = jffs2_trusted_getxattr
51};
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c
new file mode 100644
index 000000000000..d8c13636ea4c
--- /dev/null
+++ b/fs/jffs2/xattr_user.c
@@ -0,0 +1,51 @@
1/*-------------------------------------------------------------------------*
2 * File: fs/jffs2/xattr_user.c
3 * XATTR support on JFFS2 FileSystem
4 *
5 * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
6 * Copyright (C) 2006 NEC Corporation
7 *
8 * For licensing information, see the file 'LICENCE' in the jffs2 directory.
9 *-------------------------------------------------------------------------*/
10#include <linux/kernel.h>
11#include <linux/fs.h>
12#include <linux/jffs2.h>
13#include <linux/xattr.h>
14#include <linux/mtd/mtd.h>
15#include "nodelist.h"
16
17static int jffs2_user_getxattr(struct inode *inode, const char *name,
18 void *buffer, size_t size)
19{
20 if (!strcmp(name, ""))
21 return -EINVAL;
22 return do_jffs2_getxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size);
23}
24
25static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
26 size_t size, int flags)
27{
28 if (!strcmp(name, ""))
29 return -EINVAL;
30 return do_jffs2_setxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size, flags);
31}
32
33static size_t jffs2_user_listxattr(struct inode *inode, char *list, size_t list_size,
34 const char *name, size_t name_len)
35{
36 size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
37
38 if (list && retlen <= list_size) {
39 strcpy(list, XATTR_USER_PREFIX);
40 strcpy(list + XATTR_USER_PREFIX_LEN, name);
41 }
42
43 return retlen;
44}
45
46struct xattr_handler jffs2_user_xattr_handler = {
47 .prefix = XATTR_USER_PREFIX,
48 .list = jffs2_user_listxattr,
49 .set = jffs2_user_setxattr,
50 .get = jffs2_user_getxattr
51};