aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig38
-rw-r--r--fs/jffs2/Makefile3
-rw-r--r--fs/jffs2/README.Locking21
-rw-r--r--fs/jffs2/acl.c485
-rw-r--r--fs/jffs2/acl.h45
-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.c23
-rw-r--r--fs/jffs2/jffs2_fs_i.h5
-rw-r--r--fs/jffs2/jffs2_fs_sb.h10
-rw-r--r--fs/jffs2/malloc.c67
-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/scan.c168
-rw-r--r--fs/jffs2/security.c82
-rw-r--r--fs/jffs2/summary.c198
-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.c1
-rw-r--r--fs/jffs2/xattr.c1262
-rw-r--r--fs/jffs2/xattr.h116
-rw-r--r--fs/jffs2/xattr_trusted.c52
-rw-r--r--fs/jffs2/xattr_user.c52
28 files changed, 2782 insertions, 15 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index f9b5842c8d2d..2496ccbe2604 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1075,6 +1075,44 @@ config JFFS2_FS_DEBUG
1075 If reporting bugs, please try to have available a full dump of the 1075 If reporting bugs, please try to have available a full dump of the
1076 messages at debug level 1 while the misbehaviour was occurring. 1076 messages at debug level 1 while the misbehaviour was occurring.
1077 1077
1078config JFFS2_FS_XATTR
1079 bool "JFFS2 XATTR support"
1080 depends on JFFS2_FS
1081 default n
1082 help
1083 Extended attributes are name:value pairs associated with inodes by
1084 the kernel or by users (see the attr(5) manual page, or visit
1085 <http://acl.bestbits.at/> for details).
1086
1087 If unsure, say N.
1088
1089config JFFS2_FS_POSIX_ACL
1090 bool "JFFS2 POSIX Access Control Lists"
1091 depends on JFFS2_FS_XATTR
1092 default y
1093 select FS_POSIX_ACL
1094 help
1095 Posix Access Control Lists (ACLs) support permissions for users and
1096 groups beyond the owner/group/world scheme.
1097
1098 To learn more about Access Control Lists, visit the Posix ACLs for
1099 Linux website <http://acl.bestbits.at/>.
1100
1101 If you don't know what Access Control Lists are, say N
1102
1103config JFFS2_FS_SECURITY
1104 bool "JFFS2 Security Labels"
1105 depends on JFFS2_FS_XATTR
1106 default y
1107 help
1108 Security labels support alternative access control models
1109 implemented by security modules like SELinux. This option
1110 enables an extended attribute handler for file security
1111 labels in the jffs2 filesystem.
1112
1113 If you are not using a security module that requires using
1114 extended attributes for file security labels, say N.
1115
1078config JFFS2_FS_WRITEBUFFER 1116config JFFS2_FS_WRITEBUFFER
1079 bool "JFFS2 write-buffering support" 1117 bool "JFFS2 write-buffering support"
1080 depends on JFFS2_FS 1118 depends on JFFS2_FS
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/README.Locking b/fs/jffs2/README.Locking
index b7943439b6ec..c8f0bd64e53e 100644
--- a/fs/jffs2/README.Locking
+++ b/fs/jffs2/README.Locking
@@ -150,3 +150,24 @@ the buffer.
150 150
151Ordering constraints: 151Ordering constraints:
152 Lock wbuf_sem last, after the alloc_sem or and f->sem. 152 Lock wbuf_sem last, after the alloc_sem or and f->sem.
153
154
155 c->xattr_sem
156 ------------
157
158This read/write semaphore protects against concurrent access to the
159xattr related objects which include stuff in superblock and ic->xref.
160In read-only path, write-semaphore is too much exclusion. It's enough
161by read-semaphore. But you must hold write-semaphore when updating,
162creating or deleting any xattr related object.
163
164Once xattr_sem released, there would be no assurance for the existence
165of those objects. Thus, a series of processes is often required to retry,
166when updating such a object is necessary under holding read semaphore.
167For example, do_jffs2_getxattr() holds read-semaphore to scan xref and
168xdatum at first. But it retries this process with holding write-semaphore
169after release read-semaphore, if it's necessary to load name/value pair
170from medium.
171
172Ordering constraints:
173 Lock xattr_sem last, after the alloc_sem.
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
new file mode 100644
index 000000000000..320dd48b834e
--- /dev/null
+++ b/fs/jffs2/acl.c
@@ -0,0 +1,485 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this 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/crc32.h>
16#include <linux/jffs2.h>
17#include <linux/xattr.h>
18#include <linux/posix_acl_xattr.h>
19#include <linux/mtd/mtd.h>
20#include "nodelist.h"
21
22static size_t jffs2_acl_size(int count)
23{
24 if (count <= 4) {
25 return sizeof(struct jffs2_acl_header)
26 + count * sizeof(struct jffs2_acl_entry_short);
27 } else {
28 return sizeof(struct jffs2_acl_header)
29 + 4 * sizeof(struct jffs2_acl_entry_short)
30 + (count - 4) * sizeof(struct jffs2_acl_entry);
31 }
32}
33
34static int jffs2_acl_count(size_t size)
35{
36 size_t s;
37
38 size -= sizeof(struct jffs2_acl_header);
39 s = size - 4 * sizeof(struct jffs2_acl_entry_short);
40 if (s < 0) {
41 if (size % sizeof(struct jffs2_acl_entry_short))
42 return -1;
43 return size / sizeof(struct jffs2_acl_entry_short);
44 } else {
45 if (s % sizeof(struct jffs2_acl_entry))
46 return -1;
47 return s / sizeof(struct jffs2_acl_entry) + 4;
48 }
49}
50
51static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
52{
53 void *end = value + size;
54 struct jffs2_acl_header *header = value;
55 struct jffs2_acl_entry *entry;
56 struct posix_acl *acl;
57 uint32_t ver;
58 int i, count;
59
60 if (!value)
61 return NULL;
62 if (size < sizeof(struct jffs2_acl_header))
63 return ERR_PTR(-EINVAL);
64 ver = je32_to_cpu(header->a_version);
65 if (ver != JFFS2_ACL_VERSION) {
66 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
67 return ERR_PTR(-EINVAL);
68 }
69
70 value += sizeof(struct jffs2_acl_header);
71 count = jffs2_acl_count(size);
72 if (count < 0)
73 return ERR_PTR(-EINVAL);
74 if (count == 0)
75 return NULL;
76
77 acl = posix_acl_alloc(count, GFP_KERNEL);
78 if (!acl)
79 return ERR_PTR(-ENOMEM);
80
81 for (i=0; i < count; i++) {
82 entry = value;
83 if (value + sizeof(struct jffs2_acl_entry_short) > end)
84 goto fail;
85 acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
86 acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
87 switch (acl->a_entries[i].e_tag) {
88 case ACL_USER_OBJ:
89 case ACL_GROUP_OBJ:
90 case ACL_MASK:
91 case ACL_OTHER:
92 value += sizeof(struct jffs2_acl_entry_short);
93 acl->a_entries[i].e_id = ACL_UNDEFINED_ID;
94 break;
95
96 case ACL_USER:
97 case ACL_GROUP:
98 value += sizeof(struct jffs2_acl_entry);
99 if (value > end)
100 goto fail;
101 acl->a_entries[i].e_id = je32_to_cpu(entry->e_id);
102 break;
103
104 default:
105 goto fail;
106 }
107 }
108 if (value != end)
109 goto fail;
110 return acl;
111 fail:
112 posix_acl_release(acl);
113 return ERR_PTR(-EINVAL);
114}
115
116static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
117{
118 struct jffs2_acl_header *header;
119 struct jffs2_acl_entry *entry;
120 void *e;
121 size_t i;
122
123 *size = jffs2_acl_size(acl->a_count);
124 header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL);
125 if (!header)
126 return ERR_PTR(-ENOMEM);
127 header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
128 e = header + 1;
129 for (i=0; i < acl->a_count; i++) {
130 entry = e;
131 entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag);
132 entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm);
133 switch(acl->a_entries[i].e_tag) {
134 case ACL_USER:
135 case ACL_GROUP:
136 entry->e_id = cpu_to_je32(acl->a_entries[i].e_id);
137 e += sizeof(struct jffs2_acl_entry);
138 break;
139
140 case ACL_USER_OBJ:
141 case ACL_GROUP_OBJ:
142 case ACL_MASK:
143 case ACL_OTHER:
144 e += sizeof(struct jffs2_acl_entry_short);
145 break;
146
147 default:
148 goto fail;
149 }
150 }
151 return header;
152 fail:
153 kfree(header);
154 return ERR_PTR(-EINVAL);
155}
156
157static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
158{
159 struct posix_acl *acl = JFFS2_ACL_NOT_CACHED;
160
161 spin_lock(&inode->i_lock);
162 if (*i_acl != JFFS2_ACL_NOT_CACHED)
163 acl = posix_acl_dup(*i_acl);
164 spin_unlock(&inode->i_lock);
165 return acl;
166}
167
168static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl)
169{
170 spin_lock(&inode->i_lock);
171 if (*i_acl != JFFS2_ACL_NOT_CACHED)
172 posix_acl_release(*i_acl);
173 *i_acl = posix_acl_dup(acl);
174 spin_unlock(&inode->i_lock);
175}
176
177static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
178{
179 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
180 struct posix_acl *acl;
181 char *value = NULL;
182 int rc, xprefix;
183
184 switch (type) {
185 case ACL_TYPE_ACCESS:
186 acl = jffs2_iget_acl(inode, &f->i_acl_access);
187 if (acl != JFFS2_ACL_NOT_CACHED)
188 return acl;
189 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
190 break;
191 case ACL_TYPE_DEFAULT:
192 acl = jffs2_iget_acl(inode, &f->i_acl_default);
193 if (acl != JFFS2_ACL_NOT_CACHED)
194 return acl;
195 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
196 break;
197 default:
198 return ERR_PTR(-EINVAL);
199 }
200 rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
201 if (rc > 0) {
202 value = kmalloc(rc, GFP_KERNEL);
203 if (!value)
204 return ERR_PTR(-ENOMEM);
205 rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
206 }
207 if (rc > 0) {
208 acl = jffs2_acl_from_medium(value, rc);
209 } else if (rc == -ENODATA || rc == -ENOSYS) {
210 acl = NULL;
211 } else {
212 acl = ERR_PTR(rc);
213 }
214 if (value)
215 kfree(value);
216 if (!IS_ERR(acl)) {
217 switch (type) {
218 case ACL_TYPE_ACCESS:
219 jffs2_iset_acl(inode, &f->i_acl_access, acl);
220 break;
221 case ACL_TYPE_DEFAULT:
222 jffs2_iset_acl(inode, &f->i_acl_default, acl);
223 break;
224 }
225 }
226 return acl;
227}
228
229static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
230{
231 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
232 size_t size = 0;
233 char *value = NULL;
234 int rc, xprefix;
235
236 if (S_ISLNK(inode->i_mode))
237 return -EOPNOTSUPP;
238
239 switch (type) {
240 case ACL_TYPE_ACCESS:
241 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
242 if (acl) {
243 mode_t mode = inode->i_mode;
244 rc = posix_acl_equiv_mode(acl, &mode);
245 if (rc < 0)
246 return rc;
247 if (inode->i_mode != mode) {
248 inode->i_mode = mode;
249 jffs2_dirty_inode(inode);
250 }
251 if (rc == 0)
252 acl = NULL;
253 }
254 break;
255 case ACL_TYPE_DEFAULT:
256 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
257 if (!S_ISDIR(inode->i_mode))
258 return acl ? -EACCES : 0;
259 break;
260 default:
261 return -EINVAL;
262 }
263 if (acl) {
264 value = jffs2_acl_to_medium(acl, &size);
265 if (IS_ERR(value))
266 return PTR_ERR(value);
267 }
268
269 rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
270 if (value)
271 kfree(value);
272 if (!rc) {
273 switch(type) {
274 case ACL_TYPE_ACCESS:
275 jffs2_iset_acl(inode, &f->i_acl_access, acl);
276 break;
277 case ACL_TYPE_DEFAULT:
278 jffs2_iset_acl(inode, &f->i_acl_default, acl);
279 break;
280 }
281 }
282 return rc;
283}
284
285static int jffs2_check_acl(struct inode *inode, int mask)
286{
287 struct posix_acl *acl;
288 int rc;
289
290 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
291 if (IS_ERR(acl))
292 return PTR_ERR(acl);
293 if (acl) {
294 rc = posix_acl_permission(inode, acl, mask);
295 posix_acl_release(acl);
296 return rc;
297 }
298 return -EAGAIN;
299}
300
301int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
302{
303 return generic_permission(inode, mask, jffs2_check_acl);
304}
305
306int jffs2_init_acl(struct inode *inode, struct inode *dir)
307{
308 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
309 struct posix_acl *acl = NULL, *clone;
310 mode_t mode;
311 int rc = 0;
312
313 f->i_acl_access = JFFS2_ACL_NOT_CACHED;
314 f->i_acl_default = JFFS2_ACL_NOT_CACHED;
315 if (!S_ISLNK(inode->i_mode)) {
316 acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT);
317 if (IS_ERR(acl))
318 return PTR_ERR(acl);
319 if (!acl)
320 inode->i_mode &= ~current->fs->umask;
321 }
322 if (acl) {
323 if (S_ISDIR(inode->i_mode)) {
324 rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
325 if (rc)
326 goto cleanup;
327 }
328 clone = posix_acl_clone(acl, GFP_KERNEL);
329 rc = -ENOMEM;
330 if (!clone)
331 goto cleanup;
332 mode = inode->i_mode;
333 rc = posix_acl_create_masq(clone, &mode);
334 if (rc >= 0) {
335 inode->i_mode = mode;
336 if (rc > 0)
337 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
338 }
339 posix_acl_release(clone);
340 }
341 cleanup:
342 posix_acl_release(acl);
343 return rc;
344}
345
346void jffs2_clear_acl(struct inode *inode)
347{
348 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
349
350 if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) {
351 posix_acl_release(f->i_acl_access);
352 f->i_acl_access = JFFS2_ACL_NOT_CACHED;
353 }
354 if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) {
355 posix_acl_release(f->i_acl_default);
356 f->i_acl_default = JFFS2_ACL_NOT_CACHED;
357 }
358}
359
360int jffs2_acl_chmod(struct inode *inode)
361{
362 struct posix_acl *acl, *clone;
363 int rc;
364
365 if (S_ISLNK(inode->i_mode))
366 return -EOPNOTSUPP;
367 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
368 if (IS_ERR(acl) || !acl)
369 return PTR_ERR(acl);
370 clone = posix_acl_clone(acl, GFP_KERNEL);
371 posix_acl_release(acl);
372 if (!clone)
373 return -ENOMEM;
374 rc = posix_acl_chmod_masq(clone, inode->i_mode);
375 if (!rc)
376 rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
377 posix_acl_release(clone);
378 return rc;
379}
380
381static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size,
382 const char *name, size_t name_len)
383{
384 const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);
385
386 if (list && retlen <= list_size)
387 strcpy(list, POSIX_ACL_XATTR_ACCESS);
388 return retlen;
389}
390
391static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size,
392 const char *name, size_t name_len)
393{
394 const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);
395
396 if (list && retlen <= list_size)
397 strcpy(list, POSIX_ACL_XATTR_DEFAULT);
398 return retlen;
399}
400
401static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size)
402{
403 struct posix_acl *acl;
404 int rc;
405
406 acl = jffs2_get_acl(inode, type);
407 if (IS_ERR(acl))
408 return PTR_ERR(acl);
409 if (!acl)
410 return -ENODATA;
411 rc = posix_acl_to_xattr(acl, buffer, size);
412 posix_acl_release(acl);
413
414 return rc;
415}
416
417static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
418{
419 if (name[0] != '\0')
420 return -EINVAL;
421 return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size);
422}
423
424static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
425{
426 if (name[0] != '\0')
427 return -EINVAL;
428 return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
429}
430
431static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size)
432{
433 struct posix_acl *acl;
434 int rc;
435
436 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
437 return -EPERM;
438
439 if (value) {
440 acl = posix_acl_from_xattr(value, size);
441 if (IS_ERR(acl))
442 return PTR_ERR(acl);
443 if (acl) {
444 rc = posix_acl_valid(acl);
445 if (rc)
446 goto out;
447 }
448 } else {
449 acl = NULL;
450 }
451 rc = jffs2_set_acl(inode, type, acl);
452 out:
453 posix_acl_release(acl);
454 return rc;
455}
456
457static int jffs2_acl_access_setxattr(struct inode *inode, const char *name,
458 const void *buffer, size_t size, int flags)
459{
460 if (name[0] != '\0')
461 return -EINVAL;
462 return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size);
463}
464
465static int jffs2_acl_default_setxattr(struct inode *inode, const char *name,
466 const void *buffer, size_t size, int flags)
467{
468 if (name[0] != '\0')
469 return -EINVAL;
470 return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
471}
472
473struct xattr_handler jffs2_acl_access_xattr_handler = {
474 .prefix = POSIX_ACL_XATTR_ACCESS,
475 .list = jffs2_acl_access_listxattr,
476 .get = jffs2_acl_access_getxattr,
477 .set = jffs2_acl_access_setxattr,
478};
479
480struct xattr_handler jffs2_acl_default_xattr_handler = {
481 .prefix = POSIX_ACL_XATTR_DEFAULT,
482 .list = jffs2_acl_default_listxattr,
483 .get = jffs2_acl_default_getxattr,
484 .set = jffs2_acl_default_setxattr,
485};
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
new file mode 100644
index 000000000000..8893bd1a6ba7
--- /dev/null
+++ b/fs/jffs2/acl.h
@@ -0,0 +1,45 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
10 */
11struct jffs2_acl_entry {
12 jint16_t e_tag;
13 jint16_t e_perm;
14 jint32_t e_id;
15};
16
17struct jffs2_acl_entry_short {
18 jint16_t e_tag;
19 jint16_t e_perm;
20};
21
22struct jffs2_acl_header {
23 jint32_t a_version;
24};
25
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 */
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 3349db0a7863..e18c9437d58f 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..a5ef9814f165 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,23 @@ 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#ifdef CONFIG_JFFS2_FS_XATTR
270 /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr.
271 * We can decide whether this node is inode or xattr by ic->class. */
272 if (ic->class == RAWNODE_CLASS_XATTR_DATUM
273 || ic->class == RAWNODE_CLASS_XATTR_REF) {
274 BUG_ON(raw->next_in_ino != (void *)ic);
275 spin_unlock(&c->erase_completion_lock);
276
277 if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
278 ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
279 } else {
280 ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
281 }
282 goto release_sem;
283 }
284#endif
285
265 /* We need to hold the inocache. Either the erase_completion_lock or 286 /* 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 287 the inocache_lock are sufficient; we trade down since the inocache_lock
267 causes less contention. */ 288 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..272fbea55192 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_unchecked;
123 struct jffs2_xattr_ref *xref_temp;
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..f2473fa2fd16 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,40 @@ 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 return ref;
263}
264
265void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref)
266{
267 dbg_memalloc("%p\n", ref);
268 kmem_cache_free(xattr_ref_cache, ref);
269}
270#endif
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 7d71593d7fd3..4973cd648ba8 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..351d947c9375 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 jffs2_xattr_ref *xref;
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/scan.c b/fs/jffs2/scan.c
index eca0996def60..5847e76ce16c 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -306,6 +306,137 @@ 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->next 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 ref->next = c->xref_temp;
419 c->xref_temp = ref;
420
421 raw->__totlen = PAD(je32_to_cpu(rr->totlen));
422 raw->flash_offset = ofs | REF_PRISTINE;
423 raw->next_phys = NULL;
424 raw->next_in_ino = (void *)ref;
425 if (!jeb->first_node)
426 jeb->first_node = raw;
427 if (jeb->last_node)
428 jeb->last_node->next_phys = raw;
429 jeb->last_node = raw;
430
431 USED_SPACE(PAD(je32_to_cpu(rr->totlen)));
432 if (jffs2_sum_active())
433 jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
434 dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n",
435 ofs, ref->xid, ref->ino);
436 return 0;
437}
438#endif
439
309static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 440static 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) { 441 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
311 struct jffs2_unknown_node *node; 442 struct jffs2_unknown_node *node;
@@ -614,6 +745,43 @@ scan_more:
614 ofs += PAD(je32_to_cpu(node->totlen)); 745 ofs += PAD(je32_to_cpu(node->totlen));
615 break; 746 break;
616 747
748#ifdef CONFIG_JFFS2_FS_XATTR
749 case JFFS2_NODETYPE_XATTR:
750 if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
751 buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
752 D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
753 " left to end of buf. Reading 0x%x at 0x%08x\n",
754 je32_to_cpu(node->totlen), buf_len, ofs));
755 err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
756 if (err)
757 return err;
758 buf_ofs = ofs;
759 node = (void *)buf;
760 }
761 err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
762 if (err)
763 return err;
764 ofs += PAD(je32_to_cpu(node->totlen));
765 break;
766 case JFFS2_NODETYPE_XREF:
767 if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
768 buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
769 D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
770 " left to end of buf. Reading 0x%x at 0x%08x\n",
771 je32_to_cpu(node->totlen), buf_len, ofs));
772 err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
773 if (err)
774 return err;
775 buf_ofs = ofs;
776 node = (void *)buf;
777 }
778 err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
779 if (err)
780 return err;
781 ofs += PAD(je32_to_cpu(node->totlen));
782 break;
783#endif /* CONFIG_JFFS2_FS_XATTR */
784
617 case JFFS2_NODETYPE_CLEANMARKER: 785 case JFFS2_NODETYPE_CLEANMARKER:
618 D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); 786 D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
619 if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { 787 if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
new file mode 100644
index 000000000000..52a9894a6364
--- /dev/null
+++ b/fs/jffs2/security.c
@@ -0,0 +1,82 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this 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 48293c197f13..439b9f6d5837 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;
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;
262 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,101 @@ 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_free_raw_node_ref(raw);
512 if (PTR_ERR(xd) == -EEXIST) {
513 /* a newer version of xd exists */
514 DIRTY_SPACE(je32_to_cpu(spx->totlen));
515 sp += JFFS2_SUMMARY_XATTR_SIZE;
516 break;
517 }
518 JFFS2_NOTICE("allocation of xattr_datum failed\n");
519 kfree(summary);
520 return PTR_ERR(xd);
521 }
522 xd->node = raw;
523
524 raw->flash_offset = ofs | REF_UNCHECKED;
525 raw->__totlen = PAD(je32_to_cpu(spx->totlen));
526 raw->next_phys = NULL;
527 raw->next_in_ino = (void *)xd;
528 if (!jeb->first_node)
529 jeb->first_node = raw;
530 if (jeb->last_node)
531 jeb->last_node->next_phys = raw;
532 jeb->last_node = raw;
533
534 *pseudo_random += je32_to_cpu(spx->xid);
535 UNCHECKED_SPACE(je32_to_cpu(spx->totlen));
536 sp += JFFS2_SUMMARY_XATTR_SIZE;
537
538 break;
539 }
540 case JFFS2_NODETYPE_XREF: {
541 struct jffs2_xattr_ref *ref;
542 struct jffs2_sum_xref_flash *spr;
543 uint32_t ofs;
544
545 spr = (struct jffs2_sum_xref_flash *)sp;
546 ofs = jeb->offset + je32_to_cpu(spr->offset);
547 dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs,
548 je32_to_cpu(spr->xid), je32_to_cpu(spr->ino));
549 raw = jffs2_alloc_raw_node_ref();
550 if (!raw) {
551 JFFS2_NOTICE("allocation of node reference failed\n");
552 kfree(summary);
553 return -ENOMEM;
554 }
555 ref = jffs2_alloc_xattr_ref();
556 if (!ref) {
557 JFFS2_NOTICE("allocation of xattr_datum failed\n");
558 jffs2_free_raw_node_ref(raw);
559 kfree(summary);
560 return -ENOMEM;
561 }
562 ref->ino = 0xfffffffe;
563 ref->xid = 0xfffffffd;
564 ref->node = raw;
565 ref->next = c->xref_temp;
566 c->xref_temp = ref;
567
568 raw->__totlen = PAD(sizeof(struct jffs2_raw_xref));
569 raw->flash_offset = ofs | REF_UNCHECKED;
570 raw->next_phys = NULL;
571 raw->next_in_ino = (void *)ref;
572 if (!jeb->first_node)
573 jeb->first_node = raw;
574 if (jeb->last_node)
575 jeb->last_node->next_phys = raw;
576 jeb->last_node = raw;
577
578 UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref)));
579 *pseudo_random += ofs;
580 sp += JFFS2_SUMMARY_XREF_SIZE;
411 581
582 break;
583 }
584#endif
412 default : { 585 default : {
586printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
413 JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); 587 JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
414 kfree(summary); 588 kfree(summary);
415 return -EIO; 589 return -EIO;
@@ -617,7 +791,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
617 791
618 break; 792 break;
619 } 793 }
794#ifdef CONFIG_JFFS2_FS_XATTR
795 case JFFS2_NODETYPE_XATTR: {
796 struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
797
798 temp = c->summary->sum_list_head;
799 sxattr_ptr->nodetype = temp->x.nodetype;
800 sxattr_ptr->xid = temp->x.xid;
801 sxattr_ptr->version = temp->x.version;
802 sxattr_ptr->offset = temp->x.offset;
803 sxattr_ptr->totlen = temp->x.totlen;
804
805 wpage += JFFS2_SUMMARY_XATTR_SIZE;
806 break;
807 }
808 case JFFS2_NODETYPE_XREF: {
809 struct jffs2_sum_xref_flash *sxref_ptr = wpage;
810
811 temp = c->summary->sum_list_head;
812 sxref_ptr->nodetype = temp->r.nodetype;
813 sxref_ptr->offset = temp->r.offset;
620 814
815 wpage += JFFS2_SUMMARY_XREF_SIZE;
816 break;
817 }
818#endif
621 default : { 819 default : {
622 BUG(); /* unknown node in summary information */ 820 BUG(); /* unknown node in summary information */
623 } 821 }
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 5f73de586928..9d0521451f59 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..ff2b00b604ec 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -37,7 +37,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
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
40
41 jffs2_add_ino_cache(c, f->inocache); 40 jffs2_add_ino_cache(c, f->inocache);
42 D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); 41 D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
43 ri->ino = cpu_to_je32(f->inocache->ino); 42 ri->ino = cpu_to_je32(f->inocache->ino);
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
new file mode 100644
index 000000000000..057bd4dcf665
--- /dev/null
+++ b/fs/jffs2/xattr.c
@@ -0,0 +1,1262 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this 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/* -------- xref 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_inode(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 xd = ref->xd;
553 xd->refcnt--;
554 if (!xd->refcnt)
555 delete_xattr_datum(c, xd);
556 jffs2_free_xattr_ref(ref);
557}
558
559static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, uint32_t phys_ofs)
560{
561 /* must be called under down_write(xattr_sem) */
562 struct jffs2_raw_node_ref *raw;
563 struct jffs2_raw_xref rr;
564 uint32_t length;
565 int ret;
566
567 raw = jffs2_alloc_raw_node_ref();
568 if (!raw)
569 return -ENOMEM;
570 raw->flash_offset = phys_ofs;
571 raw->__totlen = PAD(sizeof(rr));
572 raw->next_phys = NULL;
573 raw->next_in_ino = (void *)ref;
574
575 rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
576 rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
577 rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
578 rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
579
580 rr.ino = cpu_to_je32(ref->ic->ino);
581 rr.xid = cpu_to_je32(ref->xd->xid);
582 rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
583
584 ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
585 if (ret || sizeof(rr) != length) {
586 JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n",
587 ret, sizeof(rr), length, phys_ofs);
588 ret = ret ? ret : -EIO;
589 if (length) {
590 raw->flash_offset |= REF_OBSOLETE;
591 raw->next_in_ino = NULL;
592 jffs2_add_physical_node_ref(c, raw);
593 jffs2_mark_node_obsolete(c, raw);
594 } else {
595 jffs2_free_raw_node_ref(raw);
596 }
597 return ret;
598 }
599 raw->flash_offset |= REF_PRISTINE;
600
601 jffs2_add_physical_node_ref(c, raw);
602 if (ref->node)
603 delete_xattr_ref_node(c, ref);
604 ref->node = raw;
605
606 dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
607
608 return 0;
609}
610
611static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic,
612 struct jffs2_xattr_datum *xd, uint32_t phys_ofs)
613{
614 /* must be called under down_write(xattr_sem) */
615 struct jffs2_xattr_ref *ref;
616 int ret;
617
618 ref = jffs2_alloc_xattr_ref();
619 if (!ref)
620 return ERR_PTR(-ENOMEM);
621 ref->ic = ic;
622 ref->xd = xd;
623
624 ret = save_xattr_ref(c, ref, phys_ofs);
625 if (ret) {
626 jffs2_free_xattr_ref(ref);
627 return ERR_PTR(ret);
628 }
629
630 /* Chain to inode */
631 ref->next = ic->xref;
632 ic->xref = ref;
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 for (ref = ic->xref; ref; ref = _ref) {
648 _ref = ref->next;
649 delete_xattr_ref(c, ref);
650 }
651 ic->xref = NULL;
652 up_write(&c->xattr_sem);
653}
654
655void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
656{
657 /* It's called from jffs2_free_ino_caches() until unmounting FS. */
658 struct jffs2_xattr_datum *xd;
659 struct jffs2_xattr_ref *ref, *_ref;
660
661 down_write(&c->xattr_sem);
662 for (ref = ic->xref; ref; ref = _ref) {
663 _ref = ref->next;
664 xd = ref->xd;
665 xd->refcnt--;
666 if (!xd->refcnt) {
667 unload_xattr_datum(c, xd);
668 jffs2_free_xattr_datum(xd);
669 }
670 jffs2_free_xattr_ref(ref);
671 }
672 ic->xref = NULL;
673 up_write(&c->xattr_sem);
674}
675
676static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
677{
678 /* success of check_xattr_ref_inode() means taht inode (ic) dose not have
679 * duplicate name/value pairs. If duplicate name/value pair would be found,
680 * one will be removed.
681 */
682 struct jffs2_xattr_ref *ref, *cmp, **pref;
683 int rc = 0;
684
685 if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
686 return 0;
687 down_write(&c->xattr_sem);
688 retry:
689 rc = 0;
690 for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
691 if (!ref->xd->xname) {
692 rc = load_xattr_datum(c, ref->xd);
693 if (unlikely(rc > 0)) {
694 *pref = ref->next;
695 delete_xattr_ref(c, ref);
696 goto retry;
697 } else if (unlikely(rc < 0))
698 goto out;
699 }
700 for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) {
701 if (!cmp->xd->xname) {
702 ref->xd->flags |= JFFS2_XFLAGS_BIND;
703 rc = load_xattr_datum(c, cmp->xd);
704 ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
705 if (unlikely(rc > 0)) {
706 *pref = cmp->next;
707 delete_xattr_ref(c, cmp);
708 goto retry;
709 } else if (unlikely(rc < 0))
710 goto out;
711 }
712 if (ref->xd->xprefix == cmp->xd->xprefix
713 && !strcmp(ref->xd->xname, cmp->xd->xname)) {
714 *pref = cmp->next;
715 delete_xattr_ref(c, cmp);
716 goto retry;
717 }
718 }
719 }
720 ic->flags |= INO_FLAGS_XATTR_CHECKED;
721 out:
722 up_write(&c->xattr_sem);
723
724 return rc;
725}
726
727/* -------- xattr subsystem functions ---------------
728 * jffs2_init_xattr_subsystem(c)
729 * is used to initialize semaphore and list_head, and some variables.
730 * jffs2_find_xattr_datum(c, xid)
731 * is used to lookup xdatum while scanning process.
732 * jffs2_clear_xattr_subsystem(c)
733 * is used to release any xattr related objects.
734 * jffs2_build_xattr_subsystem(c)
735 * is used to associate xdatum and xref while super block building process.
736 * jffs2_setup_xattr_datum(c, xid, version)
737 * is used to insert xdatum while scanning process.
738 * -------------------------------------------------- */
739void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
740{
741 int i;
742
743 for (i=0; i < XATTRINDEX_HASHSIZE; i++)
744 INIT_LIST_HEAD(&c->xattrindex[i]);
745 INIT_LIST_HEAD(&c->xattr_unchecked);
746 c->xref_temp = NULL;
747
748 init_rwsem(&c->xattr_sem);
749 c->xdatum_mem_usage = 0;
750 c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */
751}
752
753static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid)
754{
755 struct jffs2_xattr_datum *xd;
756 int i = xid % XATTRINDEX_HASHSIZE;
757
758 /* It's only used in scanning/building process. */
759 BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING)));
760
761 list_for_each_entry(xd, &c->xattrindex[i], xindex) {
762 if (xd->xid==xid)
763 return xd;
764 }
765 return NULL;
766}
767
768void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
769{
770 struct jffs2_xattr_datum *xd, *_xd;
771 struct jffs2_xattr_ref *ref, *_ref;
772 int i;
773
774 for (ref=c->xref_temp; ref; ref = _ref) {
775 _ref = ref->next;
776 jffs2_free_xattr_ref(ref);
777 }
778 c->xref_temp = NULL;
779
780 for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
781 list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
782 list_del(&xd->xindex);
783 if (xd->xname)
784 kfree(xd->xname);
785 jffs2_free_xattr_datum(xd);
786 }
787 }
788}
789
790void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
791{
792 struct jffs2_xattr_ref *ref, *_ref;
793 struct jffs2_xattr_datum *xd, *_xd;
794 struct jffs2_inode_cache *ic;
795 int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
796
797 BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
798
799 /* Phase.1 */
800 for (ref=c->xref_temp; ref; ref=_ref) {
801 _ref = ref->next;
802 /* checking REF_UNCHECKED nodes */
803 if (ref_flags(ref->node) != REF_PRISTINE) {
804 if (verify_xattr_ref(c, ref)) {
805 delete_xattr_ref_node(c, ref);
806 jffs2_free_xattr_ref(ref);
807 continue;
808 }
809 }
810 /* At this point, ref->xid and ref->ino contain XID and inode number.
811 ref->xd and ref->ic are not valid yet. */
812 xd = jffs2_find_xattr_datum(c, ref->xid);
813 ic = jffs2_get_ino_cache(c, ref->ino);
814 if (!xd || !ic) {
815 if (ref_flags(ref->node) != REF_UNCHECKED)
816 JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
817 ref->ino, ref->xid);
818 delete_xattr_ref_node(c, ref);
819 jffs2_free_xattr_ref(ref);
820 continue;
821 }
822 ref->xd = xd;
823 ref->ic = ic;
824 xd->refcnt++;
825 ref->next = ic->xref;
826 ic->xref = ref;
827 xref_count++;
828 }
829 c->xref_temp = NULL;
830 /* After this, ref->xid/ino are NEVER used. */
831
832 /* Phase.2 */
833 for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
834 list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
835 list_del_init(&xd->xindex);
836 if (!xd->refcnt) {
837 if (ref_flags(xd->node) != REF_UNCHECKED)
838 JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
839 xd->xid, xd->version, ref_offset(xd->node));
840 delete_xattr_datum(c, xd);
841 continue;
842 }
843 if (ref_flags(xd->node) != REF_PRISTINE) {
844 dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
845 xd->xid, ref_offset(xd->node));
846 list_add(&xd->xindex, &c->xattr_unchecked);
847 xdatum_unchecked_count++;
848 }
849 xdatum_count++;
850 }
851 }
852 /* build complete */
853 JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
854 "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
855}
856
857struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
858 uint32_t xid, uint32_t version)
859{
860 struct jffs2_xattr_datum *xd, *_xd;
861
862 _xd = jffs2_find_xattr_datum(c, xid);
863 if (_xd) {
864 dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
865 xid, version, _xd->version, ref_offset(_xd->node));
866 if (version < _xd->version)
867 return ERR_PTR(-EEXIST);
868 }
869 xd = jffs2_alloc_xattr_datum();
870 if (!xd)
871 return ERR_PTR(-ENOMEM);
872 xd->xid = xid;
873 xd->version = version;
874 if (xd->xid > c->highest_xid)
875 c->highest_xid = xd->xid;
876 list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
877
878 if (_xd) {
879 list_del_init(&_xd->xindex);
880 delete_xattr_datum_node(c, _xd);
881 jffs2_free_xattr_datum(_xd);
882 }
883 return xd;
884}
885
886/* -------- xattr subsystem functions ---------------
887 * xprefix_to_handler(xprefix)
888 * is used to translate xprefix into xattr_handler.
889 * jffs2_listxattr(dentry, buffer, size)
890 * is an implementation of listxattr handler on jffs2.
891 * do_jffs2_getxattr(inode, xprefix, xname, buffer, size)
892 * is an implementation of getxattr handler on jffs2.
893 * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags)
894 * is an implementation of setxattr handler on jffs2.
895 * -------------------------------------------------- */
896struct xattr_handler *jffs2_xattr_handlers[] = {
897 &jffs2_user_xattr_handler,
898#ifdef CONFIG_JFFS2_FS_SECURITY
899 &jffs2_security_xattr_handler,
900#endif
901#ifdef CONFIG_JFFS2_FS_POSIX_ACL
902 &jffs2_acl_access_xattr_handler,
903 &jffs2_acl_default_xattr_handler,
904#endif
905 &jffs2_trusted_xattr_handler,
906 NULL
907};
908
909static struct xattr_handler *xprefix_to_handler(int xprefix) {
910 struct xattr_handler *ret;
911
912 switch (xprefix) {
913 case JFFS2_XPREFIX_USER:
914 ret = &jffs2_user_xattr_handler;
915 break;
916#ifdef CONFIG_JFFS2_FS_SECURITY
917 case JFFS2_XPREFIX_SECURITY:
918 ret = &jffs2_security_xattr_handler;
919 break;
920#endif
921#ifdef CONFIG_JFFS2_FS_POSIX_ACL
922 case JFFS2_XPREFIX_ACL_ACCESS:
923 ret = &jffs2_acl_access_xattr_handler;
924 break;
925 case JFFS2_XPREFIX_ACL_DEFAULT:
926 ret = &jffs2_acl_default_xattr_handler;
927 break;
928#endif
929 case JFFS2_XPREFIX_TRUSTED:
930 ret = &jffs2_trusted_xattr_handler;
931 break;
932 default:
933 ret = NULL;
934 break;
935 }
936 return ret;
937}
938
939ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
940{
941 struct inode *inode = dentry->d_inode;
942 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
943 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
944 struct jffs2_inode_cache *ic = f->inocache;
945 struct jffs2_xattr_ref *ref, **pref;
946 struct jffs2_xattr_datum *xd;
947 struct xattr_handler *xhandle;
948 ssize_t len, rc;
949 int retry = 0;
950
951 rc = check_xattr_ref_inode(c, ic);
952 if (unlikely(rc))
953 return rc;
954
955 down_read(&c->xattr_sem);
956 retry:
957 len = 0;
958 for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
959 BUG_ON(ref->ic != ic);
960 xd = ref->xd;
961 if (!xd->xname) {
962 /* xdatum is unchached */
963 if (!retry) {
964 retry = 1;
965 up_read(&c->xattr_sem);
966 down_write(&c->xattr_sem);
967 goto retry;
968 } else {
969 rc = load_xattr_datum(c, xd);
970 if (unlikely(rc > 0)) {
971 *pref = ref->next;
972 delete_xattr_ref(c, ref);
973 goto retry;
974 } else if (unlikely(rc < 0))
975 goto out;
976 }
977 }
978 xhandle = xprefix_to_handler(xd->xprefix);
979 if (!xhandle)
980 continue;
981 if (buffer) {
982 rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len);
983 } else {
984 rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len);
985 }
986 if (rc < 0)
987 goto out;
988 len += rc;
989 }
990 rc = len;
991 out:
992 if (!retry) {
993 up_read(&c->xattr_sem);
994 } else {
995 up_write(&c->xattr_sem);
996 }
997 return rc;
998}
999
1000int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
1001 char *buffer, size_t size)
1002{
1003 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1004 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1005 struct jffs2_inode_cache *ic = f->inocache;
1006 struct jffs2_xattr_datum *xd;
1007 struct jffs2_xattr_ref *ref, **pref;
1008 int rc, retry = 0;
1009
1010 rc = check_xattr_ref_inode(c, ic);
1011 if (unlikely(rc))
1012 return rc;
1013
1014 down_read(&c->xattr_sem);
1015 retry:
1016 for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
1017 BUG_ON(ref->ic!=ic);
1018
1019 xd = ref->xd;
1020 if (xd->xprefix != xprefix)
1021 continue;
1022 if (!xd->xname) {
1023 /* xdatum is unchached */
1024 if (!retry) {
1025 retry = 1;
1026 up_read(&c->xattr_sem);
1027 down_write(&c->xattr_sem);
1028 goto retry;
1029 } else {
1030 rc = load_xattr_datum(c, xd);
1031 if (unlikely(rc > 0)) {
1032 *pref = ref->next;
1033 delete_xattr_ref(c, ref);
1034 goto retry;
1035 } else if (unlikely(rc < 0)) {
1036 goto out;
1037 }
1038 }
1039 }
1040 if (!strcmp(xname, xd->xname)) {
1041 rc = xd->value_len;
1042 if (buffer) {
1043 if (size < rc) {
1044 rc = -ERANGE;
1045 } else {
1046 memcpy(buffer, xd->xvalue, rc);
1047 }
1048 }
1049 goto out;
1050 }
1051 }
1052 rc = -ENODATA;
1053 out:
1054 if (!retry) {
1055 up_read(&c->xattr_sem);
1056 } else {
1057 up_write(&c->xattr_sem);
1058 }
1059 return rc;
1060}
1061
1062int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
1063 const char *buffer, size_t size, int flags)
1064{
1065 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1066 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1067 struct jffs2_inode_cache *ic = f->inocache;
1068 struct jffs2_xattr_datum *xd;
1069 struct jffs2_xattr_ref *ref, *newref, **pref;
1070 uint32_t phys_ofs, length, request;
1071 int rc;
1072
1073 rc = check_xattr_ref_inode(c, ic);
1074 if (unlikely(rc))
1075 return rc;
1076
1077 request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size);
1078 rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
1079 ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE);
1080 if (rc) {
1081 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1082 return rc;
1083 }
1084
1085 /* Find existing xattr */
1086 down_write(&c->xattr_sem);
1087 retry:
1088 for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
1089 xd = ref->xd;
1090 if (xd->xprefix != xprefix)
1091 continue;
1092 if (!xd->xname) {
1093 rc = load_xattr_datum(c, xd);
1094 if (unlikely(rc > 0)) {
1095 *pref = ref->next;
1096 delete_xattr_ref(c, ref);
1097 goto retry;
1098 } else if (unlikely(rc < 0))
1099 goto out;
1100 }
1101 if (!strcmp(xd->xname, xname)) {
1102 if (flags & XATTR_CREATE) {
1103 rc = -EEXIST;
1104 goto out;
1105 }
1106 if (!buffer) {
1107 *pref = ref->next;
1108 delete_xattr_ref(c, ref);
1109 rc = 0;
1110 goto out;
1111 }
1112 goto found;
1113 }
1114 }
1115 /* not found */
1116 if (flags & XATTR_REPLACE) {
1117 rc = -ENODATA;
1118 goto out;
1119 }
1120 if (!buffer) {
1121 rc = -EINVAL;
1122 goto out;
1123 }
1124 found:
1125 xd = create_xattr_datum(c, xprefix, xname, buffer, size, phys_ofs);
1126 if (IS_ERR(xd)) {
1127 rc = PTR_ERR(xd);
1128 goto out;
1129 }
1130 up_write(&c->xattr_sem);
1131 jffs2_complete_reservation(c);
1132
1133 /* create xattr_ref */
1134 request = PAD(sizeof(struct jffs2_raw_xref));
1135 rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
1136 ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
1137 if (rc) {
1138 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1139 down_write(&c->xattr_sem);
1140 xd->refcnt--;
1141 if (!xd->refcnt)
1142 delete_xattr_datum(c, xd);
1143 up_write(&c->xattr_sem);
1144 return rc;
1145 }
1146 down_write(&c->xattr_sem);
1147 if (ref)
1148 *pref = ref->next;
1149 newref = create_xattr_ref(c, ic, xd, phys_ofs);
1150 if (IS_ERR(newref)) {
1151 if (ref) {
1152 ref->next = ic->xref;
1153 ic->xref = ref;
1154 }
1155 rc = PTR_ERR(newref);
1156 xd->refcnt--;
1157 if (!xd->refcnt)
1158 delete_xattr_datum(c, xd);
1159 } else if (ref) {
1160 delete_xattr_ref(c, ref);
1161 }
1162 out:
1163 up_write(&c->xattr_sem);
1164 jffs2_complete_reservation(c);
1165 return rc;
1166}
1167
1168/* -------- garbage collector functions -------------
1169 * jffs2_garbage_collect_xattr_datum(c, xd)
1170 * is used to move xdatum into new node.
1171 * jffs2_garbage_collect_xattr_ref(c, ref)
1172 * is used to move xref into new node.
1173 * jffs2_verify_xattr(c)
1174 * is used to call do_verify_xattr_datum() before garbage collecting.
1175 * -------------------------------------------------- */
1176int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
1177{
1178 uint32_t phys_ofs, totlen, length, old_ofs;
1179 int rc = -EINVAL;
1180
1181 down_write(&c->xattr_sem);
1182 BUG_ON(!xd->node);
1183
1184 old_ofs = ref_offset(xd->node);
1185 totlen = ref_totlen(c, c->gcblock, xd->node);
1186 if (totlen < sizeof(struct jffs2_raw_xattr))
1187 goto out;
1188
1189 if (!xd->xname) {
1190 rc = load_xattr_datum(c, xd);
1191 if (unlikely(rc > 0)) {
1192 delete_xattr_datum_node(c, xd);
1193 rc = 0;
1194 goto out;
1195 } else if (unlikely(rc < 0))
1196 goto out;
1197 }
1198 rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XATTR_SIZE);
1199 if (rc || length < totlen) {
1200 JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
1201 rc = rc ? rc : -EBADFD;
1202 goto out;
1203 }
1204 rc = save_xattr_datum(c, xd, phys_ofs);
1205 if (!rc)
1206 dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
1207 xd->xid, xd->version, old_ofs, ref_offset(xd->node));
1208 out:
1209 up_write(&c->xattr_sem);
1210 return rc;
1211}
1212
1213
1214int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
1215{
1216 uint32_t phys_ofs, totlen, length, old_ofs;
1217 int rc = -EINVAL;
1218
1219 down_write(&c->xattr_sem);
1220 BUG_ON(!ref->node);
1221
1222 old_ofs = ref_offset(ref->node);
1223 totlen = ref_totlen(c, c->gcblock, ref->node);
1224 if (totlen != sizeof(struct jffs2_raw_xref))
1225 goto out;
1226
1227 rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XREF_SIZE);
1228 if (rc || length < totlen) {
1229 JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
1230 __FUNCTION__, rc, totlen);
1231 rc = rc ? rc : -EBADFD;
1232 goto out;
1233 }
1234 rc = save_xattr_ref(c, ref, phys_ofs);
1235 if (!rc)
1236 dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
1237 ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
1238 out:
1239 up_write(&c->xattr_sem);
1240 return rc;
1241}
1242
1243int jffs2_verify_xattr(struct jffs2_sb_info *c)
1244{
1245 struct jffs2_xattr_datum *xd, *_xd;
1246 int rc;
1247
1248 down_write(&c->xattr_sem);
1249 list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
1250 rc = do_verify_xattr_datum(c, xd);
1251 if (rc == 0) {
1252 list_del_init(&xd->xindex);
1253 break;
1254 } else if (rc > 0) {
1255 list_del_init(&xd->xindex);
1256 delete_xattr_datum_node(c, xd);
1257 }
1258 }
1259 up_write(&c->xattr_sem);
1260
1261 return list_empty(&c->xattr_unchecked) ? 1 : 0;
1262}
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
new file mode 100644
index 000000000000..e2aa2394ab64
--- /dev/null
+++ b/fs/jffs2/xattr.h
@@ -0,0 +1,116 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
10 */
11#ifndef _JFFS2_FS_XATTR_H_
12#define _JFFS2_FS_XATTR_H_
13
14#include <linux/xattr.h>
15#include <linux/list.h>
16
17#define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */
18#define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */
19
20struct jffs2_xattr_datum
21{
22 void *always_null;
23 u8 class;
24 u8 flags;
25 u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
26
27 struct jffs2_raw_node_ref *node;
28 struct list_head xindex; /* chained from c->xattrindex[n] */
29 uint32_t refcnt; /* # of xattr_ref refers this */
30 uint32_t xid;
31 uint32_t version;
32
33 uint32_t data_crc;
34 uint32_t hashkey;
35 char *xname; /* XATTR name without prefix */
36 uint32_t name_len; /* length of xname */
37 char *xvalue; /* XATTR value */
38 uint32_t value_len; /* length of xvalue */
39};
40
41struct jffs2_inode_cache;
42struct jffs2_xattr_ref
43{
44 void *always_null;
45 u8 class;
46 u8 flags; /* Currently unused */
47 u16 unused;
48
49 struct jffs2_raw_node_ref *node;
50 union {
51 struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */
52 uint32_t ino; /* only used in scanning/building */
53 };
54 union {
55 struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */
56 uint32_t xid; /* only used in sccanning/building */
57 };
58 struct jffs2_xattr_ref *next; /* chained from ic->xref_list */
59};
60
61#ifdef CONFIG_JFFS2_FS_XATTR
62
63extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
64extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c);
65extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
66
67extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
68 uint32_t xid, uint32_t version);
69
70extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
71extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
72
73extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
74extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
75extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
76
77extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
78 char *buffer, size_t size);
79extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
80 const char *buffer, size_t size, int flags);
81
82extern struct xattr_handler *jffs2_xattr_handlers[];
83extern struct xattr_handler jffs2_user_xattr_handler;
84extern struct xattr_handler jffs2_trusted_xattr_handler;
85
86extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
87#define jffs2_getxattr generic_getxattr
88#define jffs2_setxattr generic_setxattr
89#define jffs2_removexattr generic_removexattr
90
91#else
92
93#define jffs2_init_xattr_subsystem(c)
94#define jffs2_build_xattr_subsystem(c)
95#define jffs2_clear_xattr_subsystem(c)
96
97#define jffs2_xattr_delete_inode(c, ic)
98#define jffs2_xattr_free_inode(c, ic)
99#define jffs2_verify_xattr(c) (1)
100
101#define jffs2_xattr_handlers NULL
102#define jffs2_listxattr NULL
103#define jffs2_getxattr NULL
104#define jffs2_setxattr NULL
105#define jffs2_removexattr NULL
106
107#endif /* CONFIG_JFFS2_FS_XATTR */
108
109#ifdef CONFIG_JFFS2_FS_SECURITY
110extern int jffs2_init_security(struct inode *inode, struct inode *dir);
111extern struct xattr_handler jffs2_security_xattr_handler;
112#else
113#define jffs2_init_security(inode,dir) (0)
114#endif /* CONFIG_JFFS2_FS_SECURITY */
115
116#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..ed046e19dbfa
--- /dev/null
+++ b/fs/jffs2/xattr_trusted.c
@@ -0,0 +1,52 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
10 */
11#include <linux/kernel.h>
12#include <linux/fs.h>
13#include <linux/jffs2.h>
14#include <linux/xattr.h>
15#include <linux/mtd/mtd.h>
16#include "nodelist.h"
17
18static int jffs2_trusted_getxattr(struct inode *inode, const char *name,
19 void *buffer, size_t size)
20{
21 if (!strcmp(name, ""))
22 return -EINVAL;
23 return do_jffs2_getxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size);
24}
25
26static int jffs2_trusted_setxattr(struct inode *inode, const char *name, const void *buffer,
27 size_t size, int flags)
28{
29 if (!strcmp(name, ""))
30 return -EINVAL;
31 return do_jffs2_setxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags);
32}
33
34static size_t jffs2_trusted_listxattr(struct inode *inode, char *list, size_t list_size,
35 const char *name, size_t name_len)
36{
37 size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
38
39 if (list && retlen<=list_size) {
40 strcpy(list, XATTR_TRUSTED_PREFIX);
41 strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
42 }
43
44 return retlen;
45}
46
47struct xattr_handler jffs2_trusted_xattr_handler = {
48 .prefix = XATTR_TRUSTED_PREFIX,
49 .list = jffs2_trusted_listxattr,
50 .set = jffs2_trusted_setxattr,
51 .get = jffs2_trusted_getxattr
52};
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c
new file mode 100644
index 000000000000..2f8e9aa01ea0
--- /dev/null
+++ b/fs/jffs2/xattr_user.c
@@ -0,0 +1,52 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2006 NEC Corporation
5 *
6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 *
8 * For licensing information, see the file 'LICENCE' in this directory.
9 *
10 */
11#include <linux/kernel.h>
12#include <linux/fs.h>
13#include <linux/jffs2.h>
14#include <linux/xattr.h>
15#include <linux/mtd/mtd.h>
16#include "nodelist.h"
17
18static int jffs2_user_getxattr(struct inode *inode, const char *name,
19 void *buffer, size_t size)
20{
21 if (!strcmp(name, ""))
22 return -EINVAL;
23 return do_jffs2_getxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size);
24}
25
26static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
27 size_t size, int flags)
28{
29 if (!strcmp(name, ""))
30 return -EINVAL;
31 return do_jffs2_setxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size, flags);
32}
33
34static size_t jffs2_user_listxattr(struct inode *inode, char *list, size_t list_size,
35 const char *name, size_t name_len)
36{
37 size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
38
39 if (list && retlen <= list_size) {
40 strcpy(list, XATTR_USER_PREFIX);
41 strcpy(list + XATTR_USER_PREFIX_LEN, name);
42 }
43
44 return retlen;
45}
46
47struct xattr_handler jffs2_user_xattr_handler = {
48 .prefix = XATTR_USER_PREFIX,
49 .list = jffs2_user_listxattr,
50 .set = jffs2_user_setxattr,
51 .get = jffs2_user_getxattr
52};