Branch data Line data Source code
1 : : /*
2 : : * JFFS2 -- Journalling Flash File System, Version 2.
3 : : *
4 : : * Copyright © 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 : :
12 : : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 : :
14 : : #define JFFS2_XATTR_IS_CORRUPTED 1
15 : :
16 : : #include <linux/kernel.h>
17 : : #include <linux/slab.h>
18 : : #include <linux/fs.h>
19 : : #include <linux/time.h>
20 : : #include <linux/pagemap.h>
21 : : #include <linux/highmem.h>
22 : : #include <linux/crc32.h>
23 : : #include <linux/jffs2.h>
24 : : #include <linux/xattr.h>
25 : : #include <linux/posix_acl_xattr.h>
26 : : #include <linux/mtd/mtd.h>
27 : : #include "nodelist.h"
28 : : /* -------- xdatum related functions ----------------
29 : : * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
30 : : * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
31 : : * the index of the xattr name/value pair cache (c->xattrindex).
32 : : * is_xattr_datum_unchecked(c, xd)
33 : : * returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not
34 : : * unchecked, it returns 0.
35 : : * unload_xattr_datum(c, xd)
36 : : * is used to release xattr name/value pair and detach from c->xattrindex.
37 : : * reclaim_xattr_datum(c)
38 : : * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
39 : : * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold
40 : : * is hard coded as 32KiB.
41 : : * do_verify_xattr_datum(c, xd)
42 : : * is used to load the xdatum informations without name/value pair from the medium.
43 : : * It's necessary once, because those informations are not collected during mounting
44 : : * process when EBS is enabled.
45 : : * 0 will be returned, if success. An negative return value means recoverable error, and
46 : : * positive return value means unrecoverable error. Thus, caller must remove this xdatum
47 : : * and xref when it returned positive value.
48 : : * do_load_xattr_datum(c, xd)
49 : : * is used to load name/value pair from the medium.
50 : : * The meanings of return value is same as do_verify_xattr_datum().
51 : : * load_xattr_datum(c, xd)
52 : : * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum().
53 : : * If xd need to call do_verify_xattr_datum() at first, it's called before calling
54 : : * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum().
55 : : * save_xattr_datum(c, xd)
56 : : * is used to write xdatum to medium. xd->version will be incremented.
57 : : * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
58 : : * is used to create new xdatum and write to medium.
59 : : * unrefer_xattr_datum(c, xd)
60 : : * is used to delete a xdatum. When nobody refers this xdatum, JFFS2_XFLAGS_DEAD
61 : : * is set on xd->flags and chained xattr_dead_list or release it immediately.
62 : : * In the first case, the garbage collector release it later.
63 : : * -------------------------------------------------- */
64 : 0 : static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
65 : : {
66 : 0 : int name_len = strlen(xname);
67 : :
68 : 0 : return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
69 : : }
70 : :
71 : 0 : static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
72 : : {
73 : : struct jffs2_raw_node_ref *raw;
74 : : int rc = 0;
75 : :
76 : : spin_lock(&c->erase_completion_lock);
77 [ # # ]: 0 : for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
78 [ # # ]: 0 : if (ref_flags(raw) == REF_UNCHECKED) {
79 : : rc = 1;
80 : : break;
81 : : }
82 : : }
83 : : spin_unlock(&c->erase_completion_lock);
84 : 0 : return rc;
85 : : }
86 : :
87 : 0 : static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
88 : : {
89 : : /* must be called under down_write(xattr_sem) */
90 : : D1(dbg_xattr("%s: xid=%u, version=%u\n", __func__, xd->xid, xd->version));
91 [ # # ]: 0 : if (xd->xname) {
92 : 0 : c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len);
93 : 0 : kfree(xd->xname);
94 : : }
95 : :
96 : 0 : list_del_init(&xd->xindex);
97 : 0 : xd->hashkey = 0;
98 : 0 : xd->xname = NULL;
99 : 0 : xd->xvalue = NULL;
100 : 0 : }
101 : :
102 : 0 : static void reclaim_xattr_datum(struct jffs2_sb_info *c)
103 : : {
104 : : /* must be called under down_write(xattr_sem) */
105 : : struct jffs2_xattr_datum *xd, *_xd;
106 : : uint32_t target, before;
107 : : static int index = 0;
108 : : int count;
109 : :
110 [ # # ]: 0 : if (c->xdatum_mem_threshold > c->xdatum_mem_usage)
111 : 0 : return;
112 : :
113 : : before = c->xdatum_mem_usage;
114 : 0 : target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */
115 [ # # ]: 0 : for (count = 0; count < XATTRINDEX_HASHSIZE; count++) {
116 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) {
117 [ # # ]: 0 : if (xd->flags & JFFS2_XFLAGS_HOT) {
118 : 0 : xd->flags &= ~JFFS2_XFLAGS_HOT;
119 [ # # ]: 0 : } else if (!(xd->flags & JFFS2_XFLAGS_BIND)) {
120 : 0 : unload_xattr_datum(c, xd);
121 : : }
122 [ # # ]: 0 : if (c->xdatum_mem_usage <= target)
123 : : goto out;
124 : : }
125 : 0 : index = (index+1) % XATTRINDEX_HASHSIZE;
126 : : }
127 : : out:
128 : 0 : JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n",
129 : : before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
130 : : }
131 : :
132 : 0 : static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
133 : : {
134 : : /* must be called under down_write(xattr_sem) */
135 : : struct jffs2_eraseblock *jeb;
136 : : struct jffs2_raw_node_ref *raw;
137 : : struct jffs2_raw_xattr rx;
138 : : size_t readlen;
139 : : uint32_t crc, offset, totlen;
140 : : int rc;
141 : :
142 : : spin_lock(&c->erase_completion_lock);
143 : 0 : offset = ref_offset(xd->node);
144 [ # # ]: 0 : if (ref_flags(xd->node) == REF_PRISTINE)
145 : : goto complete;
146 : : spin_unlock(&c->erase_completion_lock);
147 : :
148 : 0 : rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx);
149 [ # # ][ # # ]: 0 : if (rc || readlen != sizeof(rx)) {
150 : 0 : JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
151 : : rc, sizeof(rx), readlen, offset);
152 [ # # ]: 0 : return rc ? rc : -EIO;
153 : : }
154 : 0 : crc = crc32(0, &rx, sizeof(rx) - 4);
155 [ # # ]: 0 : if (crc != je32_to_cpu(rx.node_crc)) {
156 : 0 : JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
157 : : offset, je32_to_cpu(rx.hdr_crc), crc);
158 : 0 : xd->flags |= JFFS2_XFLAGS_INVALID;
159 : 0 : return JFFS2_XATTR_IS_CORRUPTED;
160 : : }
161 : 0 : totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
162 [ # # ]: 0 : if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
163 [ # # ]: 0 : || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR
164 [ # # ]: 0 : || je32_to_cpu(rx.totlen) != totlen
165 [ # # ]: 0 : || je32_to_cpu(rx.xid) != xd->xid
166 [ # # ]: 0 : || je32_to_cpu(rx.version) != xd->version) {
167 : 0 : JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
168 : : "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
169 : : offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
170 : : je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
171 : : je32_to_cpu(rx.totlen), totlen,
172 : : je32_to_cpu(rx.xid), xd->xid,
173 : : je32_to_cpu(rx.version), xd->version);
174 : 0 : xd->flags |= JFFS2_XFLAGS_INVALID;
175 : 0 : return JFFS2_XATTR_IS_CORRUPTED;
176 : : }
177 : 0 : xd->xprefix = rx.xprefix;
178 : 0 : xd->name_len = rx.name_len;
179 : 0 : xd->value_len = je16_to_cpu(rx.value_len);
180 : 0 : xd->data_crc = je32_to_cpu(rx.data_crc);
181 : :
182 : : spin_lock(&c->erase_completion_lock);
183 : : complete:
184 [ # # ]: 0 : for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
185 : 0 : jeb = &c->blocks[ref_offset(raw) / c->sector_size];
186 : 0 : totlen = PAD(ref_totlen(c, jeb, raw));
187 [ # # ]: 0 : if (ref_flags(raw) == REF_UNCHECKED) {
188 : 0 : c->unchecked_size -= totlen; c->used_size += totlen;
189 : 0 : jeb->unchecked_size -= totlen; jeb->used_size += totlen;
190 : : }
191 [ # # ]: 0 : raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL);
192 : : }
193 : : spin_unlock(&c->erase_completion_lock);
194 : :
195 : : /* unchecked xdatum is chained with c->xattr_unchecked */
196 : 0 : list_del_init(&xd->xindex);
197 : :
198 : : dbg_xattr("success on verfying xdatum (xid=%u, version=%u)\n",
199 : : xd->xid, xd->version);
200 : :
201 : 0 : return 0;
202 : : }
203 : :
204 : 0 : static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
205 : : {
206 : : /* must be called under down_write(xattr_sem) */
207 : : char *data;
208 : : size_t readlen;
209 : : uint32_t crc, length;
210 : : int i, ret, retry = 0;
211 : :
212 [ # # ]: 0 : BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
213 [ # # ]: 0 : BUG_ON(!list_empty(&xd->xindex));
214 : : retry:
215 : 0 : length = xd->name_len + 1 + xd->value_len;
216 : : data = kmalloc(length, GFP_KERNEL);
217 [ # # ]: 0 : if (!data)
218 : : return -ENOMEM;
219 : :
220 : 0 : ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr),
221 : : length, &readlen, data);
222 : :
223 [ # # ][ # # ]: 0 : if (ret || length!=readlen) {
224 : 0 : JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%zu, at %#08x\n",
225 : : ret, length, readlen, ref_offset(xd->node));
226 : 0 : kfree(data);
227 [ # # ]: 0 : return ret ? ret : -EIO;
228 : : }
229 : :
230 : 0 : data[xd->name_len] = '\0';
231 : 0 : crc = crc32(0, data, length);
232 [ # # ]: 0 : if (crc != xd->data_crc) {
233 : 0 : JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XATTR)"
234 : : " at %#08x, read: 0x%08x calculated: 0x%08x\n",
235 : : ref_offset(xd->node), xd->data_crc, crc);
236 : 0 : kfree(data);
237 : 0 : xd->flags |= JFFS2_XFLAGS_INVALID;
238 : 0 : return JFFS2_XATTR_IS_CORRUPTED;
239 : : }
240 : :
241 : 0 : xd->flags |= JFFS2_XFLAGS_HOT;
242 : 0 : xd->xname = data;
243 : 0 : xd->xvalue = data + xd->name_len+1;
244 : :
245 : 0 : c->xdatum_mem_usage += length;
246 : :
247 : 0 : xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len);
248 : 0 : i = xd->hashkey % XATTRINDEX_HASHSIZE;
249 : 0 : list_add(&xd->xindex, &c->xattrindex[i]);
250 [ # # ]: 0 : if (!retry) {
251 : : retry = 1;
252 : 0 : reclaim_xattr_datum(c);
253 [ # # ]: 0 : if (!xd->xname)
254 : : goto retry;
255 : : }
256 : :
257 : : dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n",
258 : : xd->xid, xd->xprefix, xd->xname);
259 : :
260 : : return 0;
261 : : }
262 : :
263 : 0 : static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
264 : : {
265 : : /* must be called under down_write(xattr_sem);
266 : : * rc < 0 : recoverable error, try again
267 : : * rc = 0 : success
268 : : * rc > 0 : Unrecoverable error, this node should be deleted.
269 : : */
270 : : int rc = 0;
271 : :
272 [ # # ]: 0 : BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD);
273 [ # # ]: 0 : if (xd->xname)
274 : : return 0;
275 [ # # ]: 0 : if (xd->flags & JFFS2_XFLAGS_INVALID)
276 : : return JFFS2_XATTR_IS_CORRUPTED;
277 [ # # ]: 0 : if (unlikely(is_xattr_datum_unchecked(c, xd)))
278 : 0 : rc = do_verify_xattr_datum(c, xd);
279 [ # # ]: 0 : if (!rc)
280 : 0 : rc = do_load_xattr_datum(c, xd);
281 : 0 : return rc;
282 : : }
283 : :
284 : 0 : static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
285 : : {
286 : : /* must be called under down_write(xattr_sem) */
287 : : struct jffs2_raw_xattr rx;
288 : : struct kvec vecs[2];
289 : : size_t length;
290 : : int rc, totlen;
291 : 0 : uint32_t phys_ofs = write_ofs(c);
292 : :
293 [ # # ]: 0 : BUG_ON(!xd->xname);
294 [ # # ]: 0 : BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID));
295 : :
296 : 0 : vecs[0].iov_base = ℞
297 : 0 : vecs[0].iov_len = sizeof(rx);
298 : 0 : vecs[1].iov_base = xd->xname;
299 : 0 : vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
300 : 0 : totlen = vecs[0].iov_len + vecs[1].iov_len;
301 : :
302 : : /* Setup raw-xattr */
303 : 0 : memset(&rx, 0, sizeof(rx));
304 : 0 : rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
305 : 0 : rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
306 : 0 : rx.totlen = cpu_to_je32(PAD(totlen));
307 : 0 : rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
308 : :
309 : 0 : rx.xid = cpu_to_je32(xd->xid);
310 : 0 : rx.version = cpu_to_je32(++xd->version);
311 : 0 : rx.xprefix = xd->xprefix;
312 : 0 : rx.name_len = xd->name_len;
313 : 0 : rx.value_len = cpu_to_je16(xd->value_len);
314 : 0 : rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
315 : 0 : rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));
316 : :
317 : 0 : rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);
318 [ # # ][ # # ]: 0 : if (rc || totlen != length) {
319 : 0 : JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n",
320 : : rc, totlen, length, phys_ofs);
321 [ # # ]: 0 : rc = rc ? rc : -EIO;
322 [ # # ]: 0 : if (length)
323 : 0 : jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL);
324 : :
325 : 0 : return rc;
326 : : }
327 : : /* success */
328 : 0 : jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd);
329 : :
330 : : dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
331 : : xd->xid, xd->version, xd->xprefix, xd->xname);
332 : :
333 : 0 : return 0;
334 : : }
335 : :
336 : 0 : static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
337 : : int xprefix, const char *xname,
338 : : const char *xvalue, int xsize)
339 : : {
340 : : /* must be called under down_write(xattr_sem) */
341 : : struct jffs2_xattr_datum *xd;
342 : : uint32_t hashkey, name_len;
343 : : char *data;
344 : : int i, rc;
345 : :
346 : : /* Search xattr_datum has same xname/xvalue by index */
347 : 0 : hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize);
348 : 0 : i = hashkey % XATTRINDEX_HASHSIZE;
349 [ # # ]: 0 : list_for_each_entry(xd, &c->xattrindex[i], xindex) {
350 [ # # ]: 0 : if (xd->hashkey==hashkey
351 [ # # ]: 0 : && xd->xprefix==xprefix
352 [ # # ]: 0 : && xd->value_len==xsize
353 [ # # ]: 0 : && !strcmp(xd->xname, xname)
354 [ # # ]: 0 : && !memcmp(xd->xvalue, xvalue, xsize)) {
355 : 0 : atomic_inc(&xd->refcnt);
356 : 0 : return xd;
357 : : }
358 : : }
359 : :
360 : : /* Not found, Create NEW XATTR-Cache */
361 : 0 : name_len = strlen(xname);
362 : :
363 : 0 : xd = jffs2_alloc_xattr_datum();
364 [ # # ]: 0 : if (!xd)
365 : : return ERR_PTR(-ENOMEM);
366 : :
367 : 0 : data = kmalloc(name_len + 1 + xsize, GFP_KERNEL);
368 [ # # ]: 0 : if (!data) {
369 : 0 : jffs2_free_xattr_datum(xd);
370 : 0 : return ERR_PTR(-ENOMEM);
371 : : }
372 : 0 : strcpy(data, xname);
373 : 0 : memcpy(data + name_len + 1, xvalue, xsize);
374 : :
375 : 0 : atomic_set(&xd->refcnt, 1);
376 : 0 : xd->xid = ++c->highest_xid;
377 : 0 : xd->flags |= JFFS2_XFLAGS_HOT;
378 : 0 : xd->xprefix = xprefix;
379 : :
380 : 0 : xd->hashkey = hashkey;
381 : 0 : xd->xname = data;
382 : 0 : xd->xvalue = data + name_len + 1;
383 : 0 : xd->name_len = name_len;
384 : 0 : xd->value_len = xsize;
385 : 0 : xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len);
386 : :
387 : 0 : rc = save_xattr_datum(c, xd);
388 [ # # ]: 0 : if (rc) {
389 : 0 : kfree(xd->xname);
390 : 0 : jffs2_free_xattr_datum(xd);
391 : 0 : return ERR_PTR(rc);
392 : : }
393 : :
394 : : /* Insert Hash Index */
395 : : i = hashkey % XATTRINDEX_HASHSIZE;
396 : 0 : list_add(&xd->xindex, &c->xattrindex[i]);
397 : :
398 : 0 : c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len);
399 : 0 : reclaim_xattr_datum(c);
400 : :
401 : 0 : return xd;
402 : : }
403 : :
404 : 0 : static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
405 : : {
406 : : /* must be called under down_write(xattr_sem) */
407 [ # # ]: 0 : if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
408 : 0 : unload_xattr_datum(c, xd);
409 : 0 : xd->flags |= JFFS2_XFLAGS_DEAD;
410 [ # # ]: 0 : if (xd->node == (void *)xd) {
411 [ # # ]: 0 : BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
412 : 0 : jffs2_free_xattr_datum(xd);
413 : : } else {
414 : 0 : list_add(&xd->xindex, &c->xattr_dead_list);
415 : : }
416 : : spin_unlock(&c->erase_completion_lock);
417 : :
418 : : dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n",
419 : : xd->xid, xd->version);
420 : : }
421 : 0 : }
422 : :
423 : : /* -------- xref related functions ------------------
424 : : * verify_xattr_ref(c, ref)
425 : : * is used to load xref information from medium. Because summary data does not
426 : : * contain xid/ino, it's necessary to verify once while mounting process.
427 : : * save_xattr_ref(c, ref)
428 : : * is used to write xref to medium. If delete marker is marked, it write
429 : : * a delete marker of xref into medium.
430 : : * create_xattr_ref(c, ic, xd)
431 : : * is used to create a new xref and write to medium.
432 : : * delete_xattr_ref(c, ref)
433 : : * is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER,
434 : : * and allows GC to reclaim those physical nodes.
435 : : * jffs2_xattr_delete_inode(c, ic)
436 : : * is called to remove xrefs related to obsolete inode when inode is unlinked.
437 : : * jffs2_xattr_free_inode(c, ic)
438 : : * is called to release xattr related objects when unmounting.
439 : : * check_xattr_ref_inode(c, ic)
440 : : * is used to confirm inode does not have duplicate xattr name/value pair.
441 : : * jffs2_xattr_do_crccheck_inode(c, ic)
442 : : * is used to force xattr data integrity check during the initial gc scan.
443 : : * -------------------------------------------------- */
444 : 0 : static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
445 : : {
446 : : struct jffs2_eraseblock *jeb;
447 : : struct jffs2_raw_node_ref *raw;
448 : : struct jffs2_raw_xref rr;
449 : : size_t readlen;
450 : : uint32_t crc, offset, totlen;
451 : : int rc;
452 : :
453 : : spin_lock(&c->erase_completion_lock);
454 [ # # ]: 0 : if (ref_flags(ref->node) != REF_UNCHECKED)
455 : : goto complete;
456 : 0 : offset = ref_offset(ref->node);
457 : : spin_unlock(&c->erase_completion_lock);
458 : :
459 : 0 : rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr);
460 [ # # ][ # # ]: 0 : if (rc || sizeof(rr) != readlen) {
461 : 0 : JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n",
462 : : rc, sizeof(rr), readlen, offset);
463 [ # # ]: 0 : return rc ? rc : -EIO;
464 : : }
465 : : /* obsolete node */
466 : 0 : crc = crc32(0, &rr, sizeof(rr) - 4);
467 [ # # ]: 0 : if (crc != je32_to_cpu(rr.node_crc)) {
468 : 0 : JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
469 : : offset, je32_to_cpu(rr.node_crc), crc);
470 : 0 : return JFFS2_XATTR_IS_CORRUPTED;
471 : : }
472 [ # # ]: 0 : if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
473 [ # # ]: 0 : || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
474 [ # # ]: 0 : || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
475 : 0 : JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
476 : : "nodetype=%#04x/%#04x, totlen=%u/%zu\n",
477 : : offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
478 : : je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
479 : : je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
480 : 0 : return JFFS2_XATTR_IS_CORRUPTED;
481 : : }
482 : 0 : ref->ino = je32_to_cpu(rr.ino);
483 : 0 : ref->xid = je32_to_cpu(rr.xid);
484 : 0 : ref->xseqno = je32_to_cpu(rr.xseqno);
485 [ # # ]: 0 : if (ref->xseqno > c->highest_xseqno)
486 : 0 : c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
487 : :
488 : : spin_lock(&c->erase_completion_lock);
489 : : complete:
490 [ # # ]: 0 : for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) {
491 : 0 : jeb = &c->blocks[ref_offset(raw) / c->sector_size];
492 : 0 : totlen = PAD(ref_totlen(c, jeb, raw));
493 [ # # ]: 0 : if (ref_flags(raw) == REF_UNCHECKED) {
494 : 0 : c->unchecked_size -= totlen; c->used_size += totlen;
495 : 0 : jeb->unchecked_size -= totlen; jeb->used_size += totlen;
496 : : }
497 [ # # ]: 0 : raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL);
498 : : }
499 : : spin_unlock(&c->erase_completion_lock);
500 : :
501 : : dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
502 : : ref->ino, ref->xid, ref_offset(ref->node));
503 : 0 : return 0;
504 : : }
505 : :
506 : 0 : static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
507 : : {
508 : : /* must be called under down_write(xattr_sem) */
509 : : struct jffs2_raw_xref rr;
510 : : size_t length;
511 : 0 : uint32_t xseqno, phys_ofs = write_ofs(c);
512 : : int ret;
513 : :
514 : 0 : rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
515 : 0 : rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
516 : 0 : rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
517 : 0 : rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
518 : :
519 : 0 : xseqno = (c->highest_xseqno += 2);
520 [ # # ]: 0 : if (is_xattr_ref_dead(ref)) {
521 : 0 : xseqno |= XREF_DELETE_MARKER;
522 : 0 : rr.ino = cpu_to_je32(ref->ino);
523 : 0 : rr.xid = cpu_to_je32(ref->xid);
524 : : } else {
525 : 0 : rr.ino = cpu_to_je32(ref->ic->ino);
526 : 0 : rr.xid = cpu_to_je32(ref->xd->xid);
527 : : }
528 : 0 : rr.xseqno = cpu_to_je32(xseqno);
529 : 0 : rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
530 : :
531 : 0 : ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
532 [ # # ][ # # ]: 0 : if (ret || sizeof(rr) != length) {
533 : 0 : JFFS2_WARNING("jffs2_flash_write() returned %d, request=%zu, retlen=%zu, at %#08x\n",
534 : : ret, sizeof(rr), length, phys_ofs);
535 [ # # ]: 0 : ret = ret ? ret : -EIO;
536 [ # # ]: 0 : if (length)
537 : 0 : jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL);
538 : :
539 : 0 : return ret;
540 : : }
541 : : /* success */
542 : 0 : ref->xseqno = xseqno;
543 : 0 : jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref);
544 : :
545 : : dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
546 : :
547 : 0 : return 0;
548 : : }
549 : :
550 : 0 : static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic,
551 : : struct jffs2_xattr_datum *xd)
552 : : {
553 : : /* must be called under down_write(xattr_sem) */
554 : : struct jffs2_xattr_ref *ref;
555 : : int ret;
556 : :
557 : 0 : ref = jffs2_alloc_xattr_ref();
558 [ # # ]: 0 : if (!ref)
559 : : return ERR_PTR(-ENOMEM);
560 : 0 : ref->ic = ic;
561 : 0 : ref->xd = xd;
562 : :
563 : 0 : ret = save_xattr_ref(c, ref);
564 [ # # ]: 0 : if (ret) {
565 : 0 : jffs2_free_xattr_ref(ref);
566 : 0 : return ERR_PTR(ret);
567 : : }
568 : :
569 : : /* Chain to inode */
570 : 0 : ref->next = ic->xref;
571 : 0 : ic->xref = ref;
572 : :
573 : 0 : return ref; /* success */
574 : : }
575 : :
576 : 0 : static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
577 : : {
578 : : /* must be called under down_write(xattr_sem) */
579 : : struct jffs2_xattr_datum *xd;
580 : :
581 : 0 : xd = ref->xd;
582 : 0 : ref->xseqno |= XREF_DELETE_MARKER;
583 : 0 : ref->ino = ref->ic->ino;
584 : 0 : ref->xid = ref->xd->xid;
585 : : spin_lock(&c->erase_completion_lock);
586 : 0 : ref->next = c->xref_dead_list;
587 : 0 : c->xref_dead_list = ref;
588 : : spin_unlock(&c->erase_completion_lock);
589 : :
590 : : dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
591 : : ref->ino, ref->xid, ref->xseqno);
592 : :
593 : 0 : unrefer_xattr_datum(c, xd);
594 : 0 : }
595 : :
596 : 0 : void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
597 : : {
598 : : /* It's called from jffs2_evict_inode() on inode removing.
599 : : When an inode with XATTR is removed, those XATTRs must be removed. */
600 : : struct jffs2_xattr_ref *ref, *_ref;
601 : :
602 [ # # ][ # # ]: 0 : if (!ic || ic->pino_nlink > 0)
603 : 0 : return;
604 : :
605 : 0 : down_write(&c->xattr_sem);
606 [ # # ]: 0 : for (ref = ic->xref; ref; ref = _ref) {
607 : 0 : _ref = ref->next;
608 : 0 : delete_xattr_ref(c, ref);
609 : : }
610 : 0 : ic->xref = NULL;
611 : 0 : up_write(&c->xattr_sem);
612 : : }
613 : :
614 : 0 : void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
615 : : {
616 : : /* It's called from jffs2_free_ino_caches() until unmounting FS. */
617 : : struct jffs2_xattr_datum *xd;
618 : : struct jffs2_xattr_ref *ref, *_ref;
619 : :
620 : 0 : down_write(&c->xattr_sem);
621 [ # # ]: 0 : for (ref = ic->xref; ref; ref = _ref) {
622 : 0 : _ref = ref->next;
623 : 0 : xd = ref->xd;
624 [ # # ]: 0 : if (atomic_dec_and_test(&xd->refcnt)) {
625 : 0 : unload_xattr_datum(c, xd);
626 : 0 : jffs2_free_xattr_datum(xd);
627 : : }
628 : 0 : jffs2_free_xattr_ref(ref);
629 : : }
630 : 0 : ic->xref = NULL;
631 : 0 : up_write(&c->xattr_sem);
632 : 0 : }
633 : :
634 : 0 : static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
635 : : {
636 : : /* success of check_xattr_ref_inode() means that inode (ic) dose not have
637 : : * duplicate name/value pairs. If duplicate name/value pair would be found,
638 : : * one will be removed.
639 : : */
640 : : struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp;
641 : : int rc = 0;
642 : :
643 [ # # ]: 0 : if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
644 : : return 0;
645 : 0 : down_write(&c->xattr_sem);
646 : : retry:
647 : : rc = 0;
648 [ # # ]: 0 : for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
649 [ # # ]: 0 : if (!ref->xd->xname) {
650 : 0 : rc = load_xattr_datum(c, ref->xd);
651 [ # # ]: 0 : if (unlikely(rc > 0)) {
652 : 0 : *pref = ref->next;
653 : 0 : delete_xattr_ref(c, ref);
654 : 0 : goto retry;
655 [ # # ]: 0 : } else if (unlikely(rc < 0))
656 : : goto out;
657 : : }
658 [ # # ]: 0 : for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) {
659 [ # # ]: 0 : if (!cmp->xd->xname) {
660 : 0 : ref->xd->flags |= JFFS2_XFLAGS_BIND;
661 : 0 : rc = load_xattr_datum(c, cmp->xd);
662 : 0 : ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
663 [ # # ]: 0 : if (unlikely(rc > 0)) {
664 : 0 : *pcmp = cmp->next;
665 : 0 : delete_xattr_ref(c, cmp);
666 : 0 : goto retry;
667 [ # # ]: 0 : } else if (unlikely(rc < 0))
668 : : goto out;
669 : : }
670 [ # # ]: 0 : if (ref->xd->xprefix == cmp->xd->xprefix
671 [ # # ]: 0 : && !strcmp(ref->xd->xname, cmp->xd->xname)) {
672 [ # # ]: 0 : if (ref->xseqno > cmp->xseqno) {
673 : 0 : *pcmp = cmp->next;
674 : 0 : delete_xattr_ref(c, cmp);
675 : : } else {
676 : 0 : *pref = ref->next;
677 : 0 : delete_xattr_ref(c, ref);
678 : : }
679 : : goto retry;
680 : : }
681 : : }
682 : : }
683 : 0 : ic->flags |= INO_FLAGS_XATTR_CHECKED;
684 : : out:
685 : 0 : up_write(&c->xattr_sem);
686 : :
687 : 0 : return rc;
688 : : }
689 : :
690 : 0 : void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
691 : : {
692 : 0 : check_xattr_ref_inode(c, ic);
693 : 0 : }
694 : :
695 : : /* -------- xattr subsystem functions ---------------
696 : : * jffs2_init_xattr_subsystem(c)
697 : : * is used to initialize semaphore and list_head, and some variables.
698 : : * jffs2_find_xattr_datum(c, xid)
699 : : * is used to lookup xdatum while scanning process.
700 : : * jffs2_clear_xattr_subsystem(c)
701 : : * is used to release any xattr related objects.
702 : : * jffs2_build_xattr_subsystem(c)
703 : : * is used to associate xdatum and xref while super block building process.
704 : : * jffs2_setup_xattr_datum(c, xid, version)
705 : : * is used to insert xdatum while scanning process.
706 : : * -------------------------------------------------- */
707 : 0 : void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
708 : : {
709 : : int i;
710 : :
711 [ # # ]: 0 : for (i=0; i < XATTRINDEX_HASHSIZE; i++)
712 : 0 : INIT_LIST_HEAD(&c->xattrindex[i]);
713 : 0 : INIT_LIST_HEAD(&c->xattr_unchecked);
714 : 0 : INIT_LIST_HEAD(&c->xattr_dead_list);
715 : 0 : c->xref_dead_list = NULL;
716 : 0 : c->xref_temp = NULL;
717 : :
718 : 0 : init_rwsem(&c->xattr_sem);
719 : 0 : c->highest_xid = 0;
720 : 0 : c->highest_xseqno = 0;
721 : 0 : c->xdatum_mem_usage = 0;
722 : 0 : c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */
723 : 0 : }
724 : :
725 : 0 : static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid)
726 : : {
727 : : struct jffs2_xattr_datum *xd;
728 : 0 : int i = xid % XATTRINDEX_HASHSIZE;
729 : :
730 : : /* It's only used in scanning/building process. */
731 [ # # ]: 0 : BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING)));
732 : :
733 [ # # ]: 0 : list_for_each_entry(xd, &c->xattrindex[i], xindex) {
734 [ # # ]: 0 : if (xd->xid==xid)
735 : : return xd;
736 : : }
737 : : return NULL;
738 : : }
739 : :
740 : 0 : void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
741 : : {
742 : : struct jffs2_xattr_datum *xd, *_xd;
743 : : struct jffs2_xattr_ref *ref, *_ref;
744 : : int i;
745 : :
746 [ # # ]: 0 : for (ref=c->xref_temp; ref; ref = _ref) {
747 : 0 : _ref = ref->next;
748 : 0 : jffs2_free_xattr_ref(ref);
749 : : }
750 : :
751 [ # # ]: 0 : for (ref=c->xref_dead_list; ref; ref = _ref) {
752 : 0 : _ref = ref->next;
753 : 0 : jffs2_free_xattr_ref(ref);
754 : : }
755 : :
756 [ # # ]: 0 : for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
757 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
758 : : list_del(&xd->xindex);
759 [ # # ]: 0 : if (xd->xname)
760 : 0 : kfree(xd->xname);
761 : 0 : jffs2_free_xattr_datum(xd);
762 : : }
763 : : }
764 : :
765 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) {
766 : : list_del(&xd->xindex);
767 : 0 : jffs2_free_xattr_datum(xd);
768 : : }
769 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
770 : : list_del(&xd->xindex);
771 : 0 : jffs2_free_xattr_datum(xd);
772 : : }
773 : 0 : }
774 : :
775 : : #define XREF_TMPHASH_SIZE (128)
776 : 0 : void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
777 : : {
778 : 0 : struct jffs2_xattr_ref *ref, *_ref;
779 : : struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE];
780 : : struct jffs2_xattr_datum *xd, *_xd;
781 : : struct jffs2_inode_cache *ic;
782 : : struct jffs2_raw_node_ref *raw;
783 : : int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0;
784 : : int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0;
785 : :
786 [ # # ]: 0 : BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
787 : :
788 : : /* Phase.1 : Merge same xref */
789 [ # # ]: 0 : for (i=0; i < XREF_TMPHASH_SIZE; i++)
790 : 0 : xref_tmphash[i] = NULL;
791 [ # # ]: 0 : for (ref=c->xref_temp; ref; ref=_ref) {
792 : : struct jffs2_xattr_ref *tmp;
793 : :
794 : 0 : _ref = ref->next;
795 [ # # ]: 0 : if (ref_flags(ref->node) != REF_PRISTINE) {
796 [ # # ]: 0 : if (verify_xattr_ref(c, ref)) {
797 [ # # ]: 0 : BUG_ON(ref->node->next_in_ino != (void *)ref);
798 : 0 : ref->node->next_in_ino = NULL;
799 : 0 : jffs2_mark_node_obsolete(c, ref->node);
800 : 0 : jffs2_free_xattr_ref(ref);
801 : 0 : continue;
802 : : }
803 : : }
804 : :
805 : 0 : i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE;
806 [ # # ]: 0 : for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) {
807 [ # # ][ # # ]: 0 : if (tmp->ino == ref->ino && tmp->xid == ref->xid)
808 : : break;
809 : : }
810 [ # # ]: 0 : if (tmp) {
811 : 0 : raw = ref->node;
812 [ # # ]: 0 : if (ref->xseqno > tmp->xseqno) {
813 : 0 : tmp->xseqno = ref->xseqno;
814 : 0 : raw->next_in_ino = tmp->node;
815 : 0 : tmp->node = raw;
816 : : } else {
817 : 0 : raw->next_in_ino = tmp->node->next_in_ino;
818 : 0 : tmp->node->next_in_ino = raw;
819 : : }
820 : 0 : jffs2_free_xattr_ref(ref);
821 : 0 : continue;
822 : : } else {
823 : 0 : ref->next = xref_tmphash[i];
824 : 0 : xref_tmphash[i] = ref;
825 : : }
826 : : }
827 : 0 : c->xref_temp = NULL;
828 : :
829 : : /* Phase.2 : Bind xref with inode_cache and xattr_datum */
830 [ # # ]: 0 : for (i=0; i < XREF_TMPHASH_SIZE; i++) {
831 [ # # ]: 0 : for (ref=xref_tmphash[i]; ref; ref=_ref) {
832 : 0 : xref_count++;
833 : 0 : _ref = ref->next;
834 [ # # ]: 0 : if (is_xattr_ref_dead(ref)) {
835 : 0 : ref->next = c->xref_dead_list;
836 : 0 : c->xref_dead_list = ref;
837 : 0 : xref_dead_count++;
838 : 0 : continue;
839 : : }
840 : : /* At this point, ref->xid and ref->ino contain XID and inode number.
841 : : ref->xd and ref->ic are not valid yet. */
842 : 0 : xd = jffs2_find_xattr_datum(c, ref->xid);
843 : 0 : ic = jffs2_get_ino_cache(c, ref->ino);
844 [ # # ][ # # ]: 0 : if (!xd || !ic || !ic->pino_nlink) {
845 : : dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
846 : : ref->ino, ref->xid, ref->xseqno);
847 : 0 : ref->xseqno |= XREF_DELETE_MARKER;
848 : 0 : ref->next = c->xref_dead_list;
849 : 0 : c->xref_dead_list = ref;
850 : 0 : xref_orphan_count++;
851 : 0 : continue;
852 : : }
853 : 0 : ref->xd = xd;
854 : 0 : ref->ic = ic;
855 : 0 : atomic_inc(&xd->refcnt);
856 : 0 : ref->next = ic->xref;
857 : 0 : ic->xref = ref;
858 : : }
859 : : }
860 : :
861 : : /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */
862 [ # # ]: 0 : for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
863 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
864 : 0 : xdatum_count++;
865 : : list_del_init(&xd->xindex);
866 [ # # ]: 0 : if (!atomic_read(&xd->refcnt)) {
867 : : dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n",
868 : : xd->xid, xd->version);
869 : 0 : xd->flags |= JFFS2_XFLAGS_DEAD;
870 : 0 : list_add(&xd->xindex, &c->xattr_unchecked);
871 : 0 : xdatum_orphan_count++;
872 : 0 : continue;
873 : : }
874 [ # # ]: 0 : if (is_xattr_datum_unchecked(c, xd)) {
875 : : dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n",
876 : : xd->xid, xd->version);
877 : 0 : list_add(&xd->xindex, &c->xattr_unchecked);
878 : 0 : xdatum_unchecked_count++;
879 : : }
880 : : }
881 : : }
882 : : /* build complete */
883 : 0 : JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum"
884 : : " (%u unchecked, %u orphan) and "
885 : : "%u of xref (%u dead, %u orphan) found.\n",
886 : : xdatum_count, xdatum_unchecked_count, xdatum_orphan_count,
887 : : xref_count, xref_dead_count, xref_orphan_count);
888 : 0 : }
889 : :
890 : 0 : struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
891 : : uint32_t xid, uint32_t version)
892 : : {
893 : : struct jffs2_xattr_datum *xd;
894 : :
895 : 0 : xd = jffs2_find_xattr_datum(c, xid);
896 [ # # ]: 0 : if (!xd) {
897 : 0 : xd = jffs2_alloc_xattr_datum();
898 [ # # ]: 0 : if (!xd)
899 : : return ERR_PTR(-ENOMEM);
900 : 0 : xd->xid = xid;
901 : 0 : xd->version = version;
902 [ # # ]: 0 : if (xd->xid > c->highest_xid)
903 : 0 : c->highest_xid = xd->xid;
904 : 0 : list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
905 : : }
906 : 0 : return xd;
907 : : }
908 : :
909 : : /* -------- xattr subsystem functions ---------------
910 : : * xprefix_to_handler(xprefix)
911 : : * is used to translate xprefix into xattr_handler.
912 : : * jffs2_listxattr(dentry, buffer, size)
913 : : * is an implementation of listxattr handler on jffs2.
914 : : * do_jffs2_getxattr(inode, xprefix, xname, buffer, size)
915 : : * is an implementation of getxattr handler on jffs2.
916 : : * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags)
917 : : * is an implementation of setxattr handler on jffs2.
918 : : * -------------------------------------------------- */
919 : : const struct xattr_handler *jffs2_xattr_handlers[] = {
920 : : &jffs2_user_xattr_handler,
921 : : #ifdef CONFIG_JFFS2_FS_SECURITY
922 : : &jffs2_security_xattr_handler,
923 : : #endif
924 : : #ifdef CONFIG_JFFS2_FS_POSIX_ACL
925 : : &posix_acl_access_xattr_handler,
926 : : &posix_acl_default_xattr_handler,
927 : : #endif
928 : : &jffs2_trusted_xattr_handler,
929 : : NULL
930 : : };
931 : :
932 : : static const struct xattr_handler *xprefix_to_handler(int xprefix) {
933 : : const struct xattr_handler *ret;
934 : :
935 [ # # ]: 0 : switch (xprefix) {
936 : : case JFFS2_XPREFIX_USER:
937 : : ret = &jffs2_user_xattr_handler;
938 : : break;
939 : : #ifdef CONFIG_JFFS2_FS_SECURITY
940 : : case JFFS2_XPREFIX_SECURITY:
941 : : ret = &jffs2_security_xattr_handler;
942 : : break;
943 : : #endif
944 : : #ifdef CONFIG_JFFS2_FS_POSIX_ACL
945 : : case JFFS2_XPREFIX_ACL_ACCESS:
946 : : ret = &posix_acl_access_xattr_handler;
947 : : break;
948 : : case JFFS2_XPREFIX_ACL_DEFAULT:
949 : : ret = &posix_acl_default_xattr_handler;
950 : : break;
951 : : #endif
952 : : case JFFS2_XPREFIX_TRUSTED:
953 : : ret = &jffs2_trusted_xattr_handler;
954 : : break;
955 : : default:
956 : : ret = NULL;
957 : : break;
958 : : }
959 : : return ret;
960 : : }
961 : :
962 : 0 : ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
963 : : {
964 : 0 : struct inode *inode = dentry->d_inode;
965 : : struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
966 : 0 : struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
967 : 0 : struct jffs2_inode_cache *ic = f->inocache;
968 : : struct jffs2_xattr_ref *ref, **pref;
969 : : struct jffs2_xattr_datum *xd;
970 : : const struct xattr_handler *xhandle;
971 : : ssize_t len, rc;
972 : : int retry = 0;
973 : :
974 : 0 : rc = check_xattr_ref_inode(c, ic);
975 [ # # ]: 0 : if (unlikely(rc))
976 : : return rc;
977 : :
978 : 0 : down_read(&c->xattr_sem);
979 : : retry:
980 : : len = 0;
981 [ # # ]: 0 : for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
982 [ # # ]: 0 : BUG_ON(ref->ic != ic);
983 : 0 : xd = ref->xd;
984 [ # # ]: 0 : if (!xd->xname) {
985 : : /* xdatum is unchached */
986 [ # # ]: 0 : if (!retry) {
987 : : retry = 1;
988 : 0 : up_read(&c->xattr_sem);
989 : 0 : down_write(&c->xattr_sem);
990 : 0 : goto retry;
991 : : } else {
992 : 0 : rc = load_xattr_datum(c, xd);
993 [ # # ]: 0 : if (unlikely(rc > 0)) {
994 : 0 : *pref = ref->next;
995 : 0 : delete_xattr_ref(c, ref);
996 : 0 : goto retry;
997 [ # # ]: 0 : } else if (unlikely(rc < 0))
998 : : goto out;
999 : : }
1000 : : }
1001 : 0 : xhandle = xprefix_to_handler(xd->xprefix);
1002 [ # # ]: 0 : if (!xhandle)
1003 : 0 : continue;
1004 [ # # ]: 0 : if (buffer) {
1005 : 0 : rc = xhandle->list(dentry, buffer+len, size-len,
1006 : 0 : xd->xname, xd->name_len, xd->flags);
1007 : : } else {
1008 : 0 : rc = xhandle->list(dentry, NULL, 0, xd->xname,
1009 : 0 : xd->name_len, xd->flags);
1010 : : }
1011 [ # # ]: 0 : if (rc < 0)
1012 : : goto out;
1013 : 0 : len += rc;
1014 : : }
1015 : : rc = len;
1016 : : out:
1017 [ # # ]: 0 : if (!retry) {
1018 : 0 : up_read(&c->xattr_sem);
1019 : : } else {
1020 : 0 : up_write(&c->xattr_sem);
1021 : : }
1022 : 0 : return rc;
1023 : : }
1024 : :
1025 : 0 : int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
1026 : : char *buffer, size_t size)
1027 : : {
1028 : : struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1029 : 0 : struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1030 : 0 : struct jffs2_inode_cache *ic = f->inocache;
1031 : : struct jffs2_xattr_datum *xd;
1032 : : struct jffs2_xattr_ref *ref, **pref;
1033 : : int rc, retry = 0;
1034 : :
1035 : 0 : rc = check_xattr_ref_inode(c, ic);
1036 [ # # ]: 0 : if (unlikely(rc))
1037 : : return rc;
1038 : :
1039 : 0 : down_read(&c->xattr_sem);
1040 : : retry:
1041 [ # # ]: 0 : for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
1042 [ # # ]: 0 : BUG_ON(ref->ic!=ic);
1043 : :
1044 : 0 : xd = ref->xd;
1045 [ # # ]: 0 : if (xd->xprefix != xprefix)
1046 : 0 : continue;
1047 [ # # ]: 0 : if (!xd->xname) {
1048 : : /* xdatum is unchached */
1049 [ # # ]: 0 : if (!retry) {
1050 : : retry = 1;
1051 : 0 : up_read(&c->xattr_sem);
1052 : 0 : down_write(&c->xattr_sem);
1053 : 0 : goto retry;
1054 : : } else {
1055 : 0 : rc = load_xattr_datum(c, xd);
1056 [ # # ]: 0 : if (unlikely(rc > 0)) {
1057 : 0 : *pref = ref->next;
1058 : 0 : delete_xattr_ref(c, ref);
1059 : 0 : goto retry;
1060 [ # # ]: 0 : } else if (unlikely(rc < 0)) {
1061 : : goto out;
1062 : : }
1063 : : }
1064 : : }
1065 [ # # ]: 0 : if (!strcmp(xname, xd->xname)) {
1066 : 0 : rc = xd->value_len;
1067 [ # # ]: 0 : if (buffer) {
1068 [ # # ]: 0 : if (size < rc) {
1069 : : rc = -ERANGE;
1070 : : } else {
1071 : 0 : memcpy(buffer, xd->xvalue, rc);
1072 : : }
1073 : : }
1074 : : goto out;
1075 : : }
1076 : : }
1077 : : rc = -ENODATA;
1078 : : out:
1079 [ # # ]: 0 : if (!retry) {
1080 : 0 : up_read(&c->xattr_sem);
1081 : : } else {
1082 : 0 : up_write(&c->xattr_sem);
1083 : : }
1084 : 0 : return rc;
1085 : : }
1086 : :
1087 : 0 : int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
1088 : : const char *buffer, size_t size, int flags)
1089 : : {
1090 : : struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1091 : 0 : struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1092 : 0 : struct jffs2_inode_cache *ic = f->inocache;
1093 : : struct jffs2_xattr_datum *xd;
1094 : : struct jffs2_xattr_ref *ref, *newref, **pref;
1095 : : uint32_t length, request;
1096 : : int rc;
1097 : :
1098 : 0 : rc = check_xattr_ref_inode(c, ic);
1099 [ # # ]: 0 : if (unlikely(rc))
1100 : : return rc;
1101 : :
1102 : 0 : request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size);
1103 : 0 : rc = jffs2_reserve_space(c, request, &length,
1104 : : ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE);
1105 [ # # ]: 0 : if (rc) {
1106 : 0 : JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1107 : 0 : return rc;
1108 : : }
1109 : :
1110 : : /* Find existing xattr */
1111 : 0 : down_write(&c->xattr_sem);
1112 : : retry:
1113 [ # # ]: 0 : for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) {
1114 : 0 : xd = ref->xd;
1115 [ # # ]: 0 : if (xd->xprefix != xprefix)
1116 : 0 : continue;
1117 [ # # ]: 0 : if (!xd->xname) {
1118 : 0 : rc = load_xattr_datum(c, xd);
1119 [ # # ]: 0 : if (unlikely(rc > 0)) {
1120 : 0 : *pref = ref->next;
1121 : 0 : delete_xattr_ref(c, ref);
1122 : 0 : goto retry;
1123 [ # # ]: 0 : } else if (unlikely(rc < 0))
1124 : : goto out;
1125 : : }
1126 [ # # ]: 0 : if (!strcmp(xd->xname, xname)) {
1127 [ # # ]: 0 : if (flags & XATTR_CREATE) {
1128 : : rc = -EEXIST;
1129 : : goto out;
1130 : : }
1131 [ # # ]: 0 : if (!buffer) {
1132 : 0 : ref->ino = ic->ino;
1133 : 0 : ref->xid = xd->xid;
1134 : 0 : ref->xseqno |= XREF_DELETE_MARKER;
1135 : 0 : rc = save_xattr_ref(c, ref);
1136 [ # # ]: 0 : if (!rc) {
1137 : 0 : *pref = ref->next;
1138 : : spin_lock(&c->erase_completion_lock);
1139 : 0 : ref->next = c->xref_dead_list;
1140 : 0 : c->xref_dead_list = ref;
1141 : : spin_unlock(&c->erase_completion_lock);
1142 : 0 : unrefer_xattr_datum(c, xd);
1143 : : } else {
1144 : 0 : ref->ic = ic;
1145 : 0 : ref->xd = xd;
1146 : 0 : ref->xseqno &= ~XREF_DELETE_MARKER;
1147 : : }
1148 : : goto out;
1149 : : }
1150 : : goto found;
1151 : : }
1152 : : }
1153 : : /* not found */
1154 [ # # ]: 0 : if (flags & XATTR_REPLACE) {
1155 : : rc = -ENODATA;
1156 : : goto out;
1157 : : }
1158 [ # # ]: 0 : if (!buffer) {
1159 : : rc = -ENODATA;
1160 : : goto out;
1161 : : }
1162 : : found:
1163 : 0 : xd = create_xattr_datum(c, xprefix, xname, buffer, size);
1164 [ # # ]: 0 : if (IS_ERR(xd)) {
1165 : : rc = PTR_ERR(xd);
1166 : 0 : goto out;
1167 : : }
1168 : 0 : up_write(&c->xattr_sem);
1169 : 0 : jffs2_complete_reservation(c);
1170 : :
1171 : : /* create xattr_ref */
1172 : : request = PAD(sizeof(struct jffs2_raw_xref));
1173 : 0 : rc = jffs2_reserve_space(c, request, &length,
1174 : : ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
1175 : 0 : down_write(&c->xattr_sem);
1176 [ # # ]: 0 : if (rc) {
1177 : 0 : JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
1178 : 0 : unrefer_xattr_datum(c, xd);
1179 : 0 : up_write(&c->xattr_sem);
1180 : 0 : return rc;
1181 : : }
1182 [ # # ]: 0 : if (ref)
1183 : 0 : *pref = ref->next;
1184 : 0 : newref = create_xattr_ref(c, ic, xd);
1185 [ # # ]: 0 : if (IS_ERR(newref)) {
1186 [ # # ]: 0 : if (ref) {
1187 : 0 : ref->next = ic->xref;
1188 : 0 : ic->xref = ref;
1189 : : }
1190 : : rc = PTR_ERR(newref);
1191 : 0 : unrefer_xattr_datum(c, xd);
1192 [ # # ]: 0 : } else if (ref) {
1193 : 0 : delete_xattr_ref(c, ref);
1194 : : }
1195 : : out:
1196 : 0 : up_write(&c->xattr_sem);
1197 : 0 : jffs2_complete_reservation(c);
1198 : 0 : return rc;
1199 : : }
1200 : :
1201 : : /* -------- garbage collector functions -------------
1202 : : * jffs2_garbage_collect_xattr_datum(c, xd, raw)
1203 : : * is used to move xdatum into new node.
1204 : : * jffs2_garbage_collect_xattr_ref(c, ref, raw)
1205 : : * is used to move xref into new node.
1206 : : * jffs2_verify_xattr(c)
1207 : : * is used to call do_verify_xattr_datum() before garbage collecting.
1208 : : * jffs2_release_xattr_datum(c, xd)
1209 : : * is used to release an in-memory object of xdatum.
1210 : : * jffs2_release_xattr_ref(c, ref)
1211 : : * is used to release an in-memory object of xref.
1212 : : * -------------------------------------------------- */
1213 : 0 : int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
1214 : : struct jffs2_raw_node_ref *raw)
1215 : : {
1216 : : uint32_t totlen, length, old_ofs;
1217 : : int rc = 0;
1218 : :
1219 : 0 : down_write(&c->xattr_sem);
1220 [ # # ]: 0 : if (xd->node != raw)
1221 : : goto out;
1222 [ # # ]: 0 : if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID))
1223 : : goto out;
1224 : :
1225 : 0 : rc = load_xattr_datum(c, xd);
1226 [ # # ]: 0 : if (unlikely(rc)) {
1227 : 0 : rc = (rc > 0) ? 0 : rc;
1228 : 0 : goto out;
1229 : : }
1230 : : old_ofs = ref_offset(xd->node);
1231 : 0 : totlen = PAD(sizeof(struct jffs2_raw_xattr)
1232 : : + xd->name_len + 1 + xd->value_len);
1233 : 0 : rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE);
1234 [ # # ]: 0 : if (rc) {
1235 : 0 : JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen);
1236 : 0 : goto out;
1237 : : }
1238 : 0 : rc = save_xattr_datum(c, xd);
1239 : : if (!rc)
1240 : : dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
1241 : : xd->xid, xd->version, old_ofs, ref_offset(xd->node));
1242 : : out:
1243 [ # # ]: 0 : if (!rc)
1244 : 0 : jffs2_mark_node_obsolete(c, raw);
1245 : 0 : up_write(&c->xattr_sem);
1246 : 0 : return rc;
1247 : : }
1248 : :
1249 : 0 : int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
1250 : : struct jffs2_raw_node_ref *raw)
1251 : : {
1252 : : uint32_t totlen, length, old_ofs;
1253 : : int rc = 0;
1254 : :
1255 : 0 : down_write(&c->xattr_sem);
1256 [ # # ]: 0 : BUG_ON(!ref->node);
1257 : :
1258 [ # # ]: 0 : if (ref->node != raw)
1259 : : goto out;
1260 [ # # ][ # # ]: 0 : if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref))
1261 : : goto out;
1262 : :
1263 : : old_ofs = ref_offset(ref->node);
1264 : 0 : totlen = ref_totlen(c, c->gcblock, ref->node);
1265 : :
1266 : 0 : rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE);
1267 [ # # ]: 0 : if (rc) {
1268 : 0 : JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
1269 : : __func__, rc, totlen);
1270 [ # # ]: 0 : rc = rc ? rc : -EBADFD;
1271 : 0 : goto out;
1272 : : }
1273 : 0 : rc = save_xattr_ref(c, ref);
1274 : : if (!rc)
1275 : : dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
1276 : : ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
1277 : : out:
1278 [ # # ]: 0 : if (!rc)
1279 : 0 : jffs2_mark_node_obsolete(c, raw);
1280 : 0 : up_write(&c->xattr_sem);
1281 : 0 : return rc;
1282 : : }
1283 : :
1284 : 0 : int jffs2_verify_xattr(struct jffs2_sb_info *c)
1285 : : {
1286 : : struct jffs2_xattr_datum *xd, *_xd;
1287 : : struct jffs2_eraseblock *jeb;
1288 : : struct jffs2_raw_node_ref *raw;
1289 : : uint32_t totlen;
1290 : : int rc;
1291 : :
1292 : 0 : down_write(&c->xattr_sem);
1293 [ # # ]: 0 : list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
1294 : 0 : rc = do_verify_xattr_datum(c, xd);
1295 [ # # ]: 0 : if (rc < 0)
1296 : 0 : continue;
1297 : : list_del_init(&xd->xindex);
1298 : : spin_lock(&c->erase_completion_lock);
1299 [ # # ]: 0 : for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
1300 [ # # ]: 0 : if (ref_flags(raw) != REF_UNCHECKED)
1301 : 0 : continue;
1302 : 0 : jeb = &c->blocks[ref_offset(raw) / c->sector_size];
1303 : 0 : totlen = PAD(ref_totlen(c, jeb, raw));
1304 : 0 : c->unchecked_size -= totlen; c->used_size += totlen;
1305 : 0 : jeb->unchecked_size -= totlen; jeb->used_size += totlen;
1306 : 0 : raw->flash_offset = ref_offset(raw)
1307 [ # # ]: 0 : | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL);
1308 : : }
1309 [ # # ]: 0 : if (xd->flags & JFFS2_XFLAGS_DEAD)
1310 : 0 : list_add(&xd->xindex, &c->xattr_dead_list);
1311 : : spin_unlock(&c->erase_completion_lock);
1312 : : }
1313 : 0 : up_write(&c->xattr_sem);
1314 : 0 : return list_empty(&c->xattr_unchecked) ? 1 : 0;
1315 : : }
1316 : :
1317 : 0 : void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
1318 : : {
1319 : : /* must be called under spin_lock(&c->erase_completion_lock) */
1320 [ # # ][ # # ]: 0 : if (atomic_read(&xd->refcnt) || xd->node != (void *)xd)
1321 : 0 : return;
1322 : :
1323 : : list_del(&xd->xindex);
1324 : 0 : jffs2_free_xattr_datum(xd);
1325 : : }
1326 : :
1327 : 0 : void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
1328 : : {
1329 : : /* must be called under spin_lock(&c->erase_completion_lock) */
1330 : : struct jffs2_xattr_ref *tmp, **ptmp;
1331 : :
1332 [ # # ]: 0 : if (ref->node != (void *)ref)
1333 : 0 : return;
1334 : :
1335 [ # # ]: 0 : for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) {
1336 [ # # ]: 0 : if (ref == tmp) {
1337 : 0 : *ptmp = tmp->next;
1338 : 0 : break;
1339 : : }
1340 : : }
1341 : 0 : jffs2_free_xattr_ref(ref);
1342 : : }
|