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