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