diff options
-rw-r--r-- | fs/jffs2/scan.c | 6 | ||||
-rw-r--r-- | fs/jffs2/xattr.c | 303 | ||||
-rw-r--r-- | fs/jffs2/xattr.h | 23 |
3 files changed, 105 insertions, 227 deletions
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 79638f56c5ea..2bfdc33752d3 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -332,10 +332,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
332 | xid = je32_to_cpu(rx->xid); | 332 | xid = je32_to_cpu(rx->xid); |
333 | version = je32_to_cpu(rx->version); | 333 | version = je32_to_cpu(rx->version); |
334 | 334 | ||
335 | totlen = sizeof(struct jffs2_raw_xattr); | 335 | totlen = PAD(sizeof(struct jffs2_raw_xattr) |
336 | if (version != XDATUM_DELETE_MARKER) | 336 | + rx->name_len + 1 + je16_to_cpu(rx->value_len)); |
337 | totlen += rx->name_len + 1 + je16_to_cpu(rx->value_len); | ||
338 | totlen = PAD(totlen); | ||
339 | if (totlen != je32_to_cpu(rx->totlen)) { | 337 | if (totlen != je32_to_cpu(rx->totlen)) { |
340 | JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", | 338 | JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", |
341 | ofs, je32_to_cpu(rx->totlen), totlen); | 339 | ofs, je32_to_cpu(rx->totlen), totlen); |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 03871ab7c26d..7622f79cb5b4 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
@@ -50,12 +50,9 @@ | |||
50 | * is used to write xdatum to medium. xd->version will be incremented. | 50 | * is used to write xdatum to medium. xd->version will be incremented. |
51 | * create_xattr_datum(c, xprefix, xname, xvalue, xsize) | 51 | * create_xattr_datum(c, xprefix, xname, xvalue, xsize) |
52 | * is used to create new xdatum and write to medium. | 52 | * is used to create new xdatum and write to medium. |
53 | * delete_xattr_datum_delay(c, xd) | ||
54 | * is used to delete a xdatum without 'delete marker'. It has a possibility to detect | ||
55 | * orphan xdatum on next mounting. | ||
56 | * delete_xattr_datum(c, xd) | 53 | * delete_xattr_datum(c, xd) |
57 | * is used to delete a xdatum with 'delete marker'. Calling jffs2_reserve_space() is | 54 | * is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows |
58 | * necessary before this function. | 55 | * GC to reclaim those physical nodes. |
59 | * -------------------------------------------------- */ | 56 | * -------------------------------------------------- */ |
60 | static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) | 57 | static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) |
61 | { | 58 | { |
@@ -154,10 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat | |||
154 | xd->flags |= JFFS2_XFLAGS_INVALID; | 151 | xd->flags |= JFFS2_XFLAGS_INVALID; |
155 | return EIO; | 152 | return EIO; |
156 | } | 153 | } |
157 | totlen = sizeof(rx); | 154 | totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); |
158 | if (xd->version != XDATUM_DELETE_MARKER) | ||
159 | totlen += rx.name_len + 1 + je16_to_cpu(rx.value_len); | ||
160 | totlen = PAD(totlen); | ||
161 | if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK | 155 | if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK |
162 | || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR | 156 | || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR |
163 | || je32_to_cpu(rx.totlen) != totlen | 157 | || je32_to_cpu(rx.totlen) != totlen |
@@ -268,6 +262,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x | |||
268 | */ | 262 | */ |
269 | int rc = 0; | 263 | int rc = 0; |
270 | 264 | ||
265 | BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD); | ||
271 | if (xd->xname) | 266 | if (xd->xname) |
272 | return 0; | 267 | return 0; |
273 | if (xd->flags & JFFS2_XFLAGS_INVALID) | 268 | if (xd->flags & JFFS2_XFLAGS_INVALID) |
@@ -285,20 +280,18 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x | |||
285 | struct jffs2_raw_xattr rx; | 280 | struct jffs2_raw_xattr rx; |
286 | struct kvec vecs[2]; | 281 | struct kvec vecs[2]; |
287 | size_t length; | 282 | size_t length; |
288 | int rc, totlen, nvecs = 1; | 283 | int rc, totlen; |
289 | uint32_t phys_ofs = write_ofs(c); | 284 | uint32_t phys_ofs = write_ofs(c); |
290 | 285 | ||
291 | BUG_ON(is_xattr_datum_dead(xd) || (xd->flags & JFFS2_XFLAGS_INVALID) | 286 | BUG_ON(!xd->xname); |
292 | ? !!xd->xname : !xd->xname); | 287 | BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)); |
293 | 288 | ||
294 | vecs[0].iov_base = ℞ | 289 | vecs[0].iov_base = ℞ |
295 | vecs[0].iov_len = totlen = sizeof(rx); | 290 | vecs[0].iov_len = sizeof(rx); |
296 | if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { | 291 | vecs[1].iov_base = xd->xname; |
297 | nvecs++; | 292 | vecs[1].iov_len = xd->name_len + 1 + xd->value_len; |
298 | vecs[1].iov_base = xd->xname; | 293 | totlen = vecs[0].iov_len + vecs[1].iov_len; |
299 | vecs[1].iov_len = xd->name_len + 1 + xd->value_len; | 294 | |
300 | totlen += vecs[1].iov_len; | ||
301 | } | ||
302 | /* Setup raw-xattr */ | 295 | /* Setup raw-xattr */ |
303 | memset(&rx, 0, sizeof(rx)); | 296 | memset(&rx, 0, sizeof(rx)); |
304 | rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 297 | rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -307,18 +300,14 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x | |||
307 | rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); | 300 | rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); |
308 | 301 | ||
309 | rx.xid = cpu_to_je32(xd->xid); | 302 | rx.xid = cpu_to_je32(xd->xid); |
310 | if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { | 303 | rx.version = cpu_to_je32(++xd->version); |
311 | rx.version = cpu_to_je32(++xd->version); | 304 | rx.xprefix = xd->xprefix; |
312 | rx.xprefix = xd->xprefix; | 305 | rx.name_len = xd->name_len; |
313 | rx.name_len = xd->name_len; | 306 | rx.value_len = cpu_to_je16(xd->value_len); |
314 | rx.value_len = cpu_to_je16(xd->value_len); | 307 | rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); |
315 | rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); | ||
316 | } else { | ||
317 | rx.version = cpu_to_je32(XDATUM_DELETE_MARKER); | ||
318 | } | ||
319 | rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); | 308 | rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); |
320 | 309 | ||
321 | rc = jffs2_flash_writev(c, vecs, nvecs, phys_ofs, &length, 0); | 310 | rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); |
322 | if (rc || totlen != length) { | 311 | if (rc || totlen != length) { |
323 | JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", | 312 | JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", |
324 | rc, totlen, length, phys_ofs); | 313 | rc, totlen, length, phys_ofs); |
@@ -405,53 +394,36 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, | |||
405 | return xd; | 394 | return xd; |
406 | } | 395 | } |
407 | 396 | ||
408 | static void delete_xattr_datum_delay(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) | 397 | static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) |
409 | { | 398 | { |
410 | /* must be called under down_write(xattr_sem) */ | 399 | /* must be called under down_write(xattr_sem) */ |
411 | BUG_ON(xd->refcnt); | 400 | BUG_ON(xd->refcnt); |
412 | 401 | ||
413 | unload_xattr_datum(c, xd); | 402 | unload_xattr_datum(c, xd); |
414 | set_xattr_datum_dead(xd); | 403 | xd->flags |= JFFS2_XFLAGS_DEAD; |
415 | spin_lock(&c->erase_completion_lock); | 404 | spin_lock(&c->erase_completion_lock); |
416 | list_add(&xd->xindex, &c->xattr_dead_list); | 405 | if (xd->node == (void *)xd) { |
417 | spin_unlock(&c->erase_completion_lock); | 406 | BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID)); |
418 | JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " | 407 | jffs2_free_xattr_datum(xd); |
419 | "An orphan xdatum may be detected on next mounting.\n", xd->xid); | 408 | } else { |
420 | } | 409 | list_add(&xd->xindex, &c->xattr_dead_list); |
421 | |||
422 | static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) | ||
423 | { | ||
424 | /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ | ||
425 | int rc; | ||
426 | BUG_ON(xd->refcnt); | ||
427 | |||
428 | unload_xattr_datum(c, xd); | ||
429 | set_xattr_datum_dead(xd); | ||
430 | rc = save_xattr_datum(c, xd); | ||
431 | if (rc) { | ||
432 | JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " | ||
433 | "An orphan xdatum may be detected on next mounting.\n", | ||
434 | xd->xid); | ||
435 | } | 410 | } |
436 | spin_lock(&c->erase_completion_lock); | ||
437 | list_add(&xd->xindex, &c->xattr_dead_list); | ||
438 | spin_unlock(&c->erase_completion_lock); | 411 | spin_unlock(&c->erase_completion_lock); |
412 | dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version); | ||
439 | } | 413 | } |
440 | 414 | ||
441 | /* -------- xref related functions ------------------ | 415 | /* -------- xref related functions ------------------ |
442 | * verify_xattr_ref(c, ref) | 416 | * verify_xattr_ref(c, ref) |
443 | * is used to load xref information from medium. Because summary data does not | 417 | * is used to load xref information from medium. Because summary data does not |
444 | * contain xid/ino, it's necessary to verify once while mounting process. | 418 | * contain xid/ino, it's necessary to verify once while mounting process. |
445 | * delete_xattr_ref_node(c, ref) | ||
446 | * is used to delete a jffs2 node is dominated by xref. When EBS is enabled, | ||
447 | * it overwrites the obsolete node by myself. | ||
448 | * delete_xattr_ref(c, ref) | ||
449 | * is used to delete jffs2_xattr_ref object. If the reference counter of xdatum | ||
450 | * is refered by this xref become 0, delete_xattr_datum() is called later. | ||
451 | * save_xattr_ref(c, ref) | 419 | * save_xattr_ref(c, ref) |
452 | * is used to write xref to medium. | 420 | * is used to write xref to medium. If delete marker is marked, it write |
421 | * a delete marker of xref into medium. | ||
453 | * create_xattr_ref(c, ic, xd) | 422 | * create_xattr_ref(c, ic, xd) |
454 | * is used to create a new xref and write to medium. | 423 | * is used to create a new xref and write to medium. |
424 | * delete_xattr_ref(c, ref) | ||
425 | * is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER, | ||
426 | * and allows GC to reclaim those physical nodes. | ||
455 | * jffs2_xattr_delete_inode(c, ic) | 427 | * jffs2_xattr_delete_inode(c, ic) |
456 | * is called to remove xrefs related to obsolete inode when inode is unlinked. | 428 | * is called to remove xrefs related to obsolete inode when inode is unlinked. |
457 | * jffs2_xattr_free_inode(c, ic) | 429 | * jffs2_xattr_free_inode(c, ic) |
@@ -591,13 +563,13 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct | |||
591 | return ref; /* success */ | 563 | return ref; /* success */ |
592 | } | 564 | } |
593 | 565 | ||
594 | static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) | 566 | static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) |
595 | { | 567 | { |
596 | /* must be called under down_write(xattr_sem) */ | 568 | /* must be called under down_write(xattr_sem) */ |
597 | struct jffs2_xattr_datum *xd; | 569 | struct jffs2_xattr_datum *xd; |
598 | 570 | ||
599 | set_xattr_ref_dead(ref); | ||
600 | xd = ref->xd; | 571 | xd = ref->xd; |
572 | ref->xseqno |= XREF_DELETE_MARKER; | ||
601 | ref->ino = ref->ic->ino; | 573 | ref->ino = ref->ic->ino; |
602 | ref->xid = ref->xd->xid; | 574 | ref->xid = ref->xd->xid; |
603 | spin_lock(&c->erase_completion_lock); | 575 | spin_lock(&c->erase_completion_lock); |
@@ -605,102 +577,29 @@ static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_r | |||
605 | c->xref_dead_list = ref; | 577 | c->xref_dead_list = ref; |
606 | spin_unlock(&c->erase_completion_lock); | 578 | spin_unlock(&c->erase_completion_lock); |
607 | 579 | ||
608 | JFFS2_NOTICE("xref(ino=%u, xid=%u) was removed without delete marker. " | 580 | dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n", |
609 | "An orphan xref may be detected on next mounting.\n", | 581 | ref->ino, ref->xid, ref->xseqno); |
610 | ref->ino, ref->xid); | ||
611 | 582 | ||
612 | if (!--xd->refcnt) | 583 | if (!--xd->refcnt) |
613 | delete_xattr_datum_delay(c, xd); | ||
614 | } | ||
615 | |||
616 | static int delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, int enforce) | ||
617 | { | ||
618 | /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ | ||
619 | struct jffs2_inode_cache *ic; | ||
620 | struct jffs2_xattr_datum *xd; | ||
621 | uint32_t length; | ||
622 | int rc; | ||
623 | |||
624 | set_xattr_ref_dead(ref); | ||
625 | ic = ref->ic; | ||
626 | xd = ref->xd; | ||
627 | ref->ino = ic->ino; | ||
628 | ref->xid = xd->xid; | ||
629 | rc = save_xattr_ref(c, ref); | ||
630 | if (rc) { | ||
631 | if (!enforce) { | ||
632 | clr_xattr_ref_dead(ref); | ||
633 | ref->ic = ic; | ||
634 | ref->xd = xd; | ||
635 | return rc; | ||
636 | } | ||
637 | JFFS2_WARNING("could not write delete marker of xref(ino=%u, xid=%u). " | ||
638 | "An orphan xref may be detected on next mounting.\n", | ||
639 | ref->ic->ino, ref->xd->xid); | ||
640 | } | ||
641 | spin_lock(&c->erase_completion_lock); | ||
642 | ref->next = c->xref_dead_list; | ||
643 | c->xref_dead_list = ref; | ||
644 | spin_unlock(&c->erase_completion_lock); | ||
645 | |||
646 | xd->refcnt--; | ||
647 | if (xd->refcnt) | ||
648 | return 0; | ||
649 | |||
650 | /* delete xdatum */ | ||
651 | unload_xattr_datum(c, xd); | ||
652 | up_write(&c->xattr_sem); | ||
653 | jffs2_complete_reservation(c); | ||
654 | |||
655 | rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xattr)), &length, | ||
656 | ALLOC_DELETION, JFFS2_SUMMARY_XATTR_SIZE); | ||
657 | if (rc) { | ||
658 | down(&c->alloc_sem); | ||
659 | down_write(&c->xattr_sem); | ||
660 | delete_xattr_datum_delay(c, xd); | ||
661 | } else { | ||
662 | down_write(&c->xattr_sem); | ||
663 | delete_xattr_datum(c, xd); | 584 | delete_xattr_datum(c, xd); |
664 | } | ||
665 | return 0; | ||
666 | } | 585 | } |
667 | 586 | ||
668 | void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 587 | void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) |
669 | { | 588 | { |
670 | /* It's called from jffs2_clear_inode() on inode removing. | 589 | /* It's called from jffs2_clear_inode() on inode removing. |
671 | When an inode with XATTR is removed, those XATTRs must be removed. */ | 590 | When an inode with XATTR is removed, those XATTRs must be removed. */ |
672 | struct jffs2_xattr_ref *ref; | 591 | struct jffs2_xattr_ref *ref, *_ref; |
673 | uint32_t length; | ||
674 | int rc, retry; | ||
675 | 592 | ||
676 | if (!ic || ic->nlink > 0) | 593 | if (!ic || ic->nlink > 0) |
677 | return; | 594 | return; |
678 | 595 | ||
679 | down_read(&c->xattr_sem); | ||
680 | if (!ic->xref) { | ||
681 | up_read(&c->xattr_sem); | ||
682 | return; | ||
683 | } | ||
684 | up_read(&c->xattr_sem); | ||
685 | retry: | ||
686 | rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xref)), &length, | ||
687 | ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); | ||
688 | down_write(&c->xattr_sem); | 596 | down_write(&c->xattr_sem); |
689 | if (ic->xref) { | 597 | for (ref = ic->xref; ref; ref = _ref) { |
690 | ref = ic->xref; | 598 | _ref = ref->next; |
691 | ic->xref = ref->next; | 599 | delete_xattr_ref(c, ref); |
692 | if (rc) { | ||
693 | delete_xattr_ref_delay(c, ref); | ||
694 | } else { | ||
695 | delete_xattr_ref(c, ref, 1); | ||
696 | } | ||
697 | } | 600 | } |
698 | retry = ic->xref ? 1 : 0; | 601 | ic->xref = NULL; |
699 | up_write(&c->xattr_sem); | 602 | up_write(&c->xattr_sem); |
700 | if (!rc) | ||
701 | jffs2_complete_reservation(c); | ||
702 | if (retry) | ||
703 | goto retry; | ||
704 | } | 603 | } |
705 | 604 | ||
706 | void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 605 | void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) |
@@ -743,7 +642,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac | |||
743 | rc = load_xattr_datum(c, ref->xd); | 642 | rc = load_xattr_datum(c, ref->xd); |
744 | if (unlikely(rc > 0)) { | 643 | if (unlikely(rc > 0)) { |
745 | *pref = ref->next; | 644 | *pref = ref->next; |
746 | delete_xattr_ref_delay(c, ref); | 645 | delete_xattr_ref(c, ref); |
747 | goto retry; | 646 | goto retry; |
748 | } else if (unlikely(rc < 0)) | 647 | } else if (unlikely(rc < 0)) |
749 | goto out; | 648 | goto out; |
@@ -755,7 +654,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac | |||
755 | ref->xd->flags &= ~JFFS2_XFLAGS_BIND; | 654 | ref->xd->flags &= ~JFFS2_XFLAGS_BIND; |
756 | if (unlikely(rc > 0)) { | 655 | if (unlikely(rc > 0)) { |
757 | *pcmp = cmp->next; | 656 | *pcmp = cmp->next; |
758 | delete_xattr_ref_delay(c, cmp); | 657 | delete_xattr_ref(c, cmp); |
759 | goto retry; | 658 | goto retry; |
760 | } else if (unlikely(rc < 0)) | 659 | } else if (unlikely(rc < 0)) |
761 | goto out; | 660 | goto out; |
@@ -764,10 +663,10 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac | |||
764 | && !strcmp(ref->xd->xname, cmp->xd->xname)) { | 663 | && !strcmp(ref->xd->xname, cmp->xd->xname)) { |
765 | if (ref->xseqno > cmp->xseqno) { | 664 | if (ref->xseqno > cmp->xseqno) { |
766 | *pcmp = cmp->next; | 665 | *pcmp = cmp->next; |
767 | delete_xattr_ref_delay(c, cmp); | 666 | delete_xattr_ref(c, cmp); |
768 | } else { | 667 | } else { |
769 | *pref = ref->next; | 668 | *pref = ref->next; |
770 | delete_xattr_ref_delay(c, ref); | 669 | delete_xattr_ref(c, ref); |
771 | } | 670 | } |
772 | goto retry; | 671 | goto retry; |
773 | } | 672 | } |
@@ -865,20 +764,11 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
865 | struct jffs2_inode_cache *ic; | 764 | struct jffs2_inode_cache *ic; |
866 | struct jffs2_raw_node_ref *raw; | 765 | struct jffs2_raw_node_ref *raw; |
867 | int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; | 766 | int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; |
767 | int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0; | ||
868 | 768 | ||
869 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); | 769 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); |
870 | /* Phase.1 : Drop dead xdatum */ | ||
871 | for (i=0; i < XATTRINDEX_HASHSIZE; i++) { | ||
872 | list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { | ||
873 | BUG_ON(xd->node == (void *)xd); | ||
874 | if (is_xattr_datum_dead(xd)) { | ||
875 | list_del_init(&xd->xindex); | ||
876 | list_add(&xd->xindex, &c->xattr_unchecked); | ||
877 | } | ||
878 | } | ||
879 | } | ||
880 | 770 | ||
881 | /* Phase.2 : Merge same xref */ | 771 | /* Phase.1 : Merge same xref */ |
882 | for (i=0; i < XREF_TMPHASH_SIZE; i++) | 772 | for (i=0; i < XREF_TMPHASH_SIZE; i++) |
883 | xref_tmphash[i] = NULL; | 773 | xref_tmphash[i] = NULL; |
884 | for (ref=c->xref_temp; ref; ref=_ref) { | 774 | for (ref=c->xref_temp; ref; ref=_ref) { |
@@ -919,13 +809,15 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
919 | } | 809 | } |
920 | c->xref_temp = NULL; | 810 | c->xref_temp = NULL; |
921 | 811 | ||
922 | /* Phase.3 : Bind xref with inode_cache and xattr_datum */ | 812 | /* Phase.2 : Bind xref with inode_cache and xattr_datum */ |
923 | for (i=0; i < XREF_TMPHASH_SIZE; i++) { | 813 | for (i=0; i < XREF_TMPHASH_SIZE; i++) { |
924 | for (ref=xref_tmphash[i]; ref; ref=_ref) { | 814 | for (ref=xref_tmphash[i]; ref; ref=_ref) { |
815 | xref_count++; | ||
925 | _ref = ref->next; | 816 | _ref = ref->next; |
926 | if (is_xattr_ref_dead(ref)) { | 817 | if (is_xattr_ref_dead(ref)) { |
927 | ref->next = c->xref_dead_list; | 818 | ref->next = c->xref_dead_list; |
928 | c->xref_dead_list = ref; | 819 | c->xref_dead_list = ref; |
820 | xref_dead_count++; | ||
929 | continue; | 821 | continue; |
930 | } | 822 | } |
931 | /* At this point, ref->xid and ref->ino contain XID and inode number. | 823 | /* At this point, ref->xid and ref->ino contain XID and inode number. |
@@ -933,11 +825,12 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
933 | xd = jffs2_find_xattr_datum(c, ref->xid); | 825 | xd = jffs2_find_xattr_datum(c, ref->xid); |
934 | ic = jffs2_get_ino_cache(c, ref->ino); | 826 | ic = jffs2_get_ino_cache(c, ref->ino); |
935 | if (!xd || !ic) { | 827 | if (!xd || !ic) { |
936 | JFFS2_WARNING("xref(ino=%u, xid=%u, xseqno=%u) is orphan. \n", | 828 | dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", |
937 | ref->ino, ref->xid, ref->xseqno); | 829 | ref->ino, ref->xid, ref->xseqno); |
938 | set_xattr_ref_dead(ref); | 830 | ref->xseqno |= XREF_DELETE_MARKER; |
939 | ref->next = c->xref_dead_list; | 831 | ref->next = c->xref_dead_list; |
940 | c->xref_dead_list = ref; | 832 | c->xref_dead_list = ref; |
833 | xref_orphan_count++; | ||
941 | continue; | 834 | continue; |
942 | } | 835 | } |
943 | ref->xd = xd; | 836 | ref->xd = xd; |
@@ -945,19 +838,20 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
945 | xd->refcnt++; | 838 | xd->refcnt++; |
946 | ref->next = ic->xref; | 839 | ref->next = ic->xref; |
947 | ic->xref = ref; | 840 | ic->xref = ref; |
948 | xref_count++; | ||
949 | } | 841 | } |
950 | } | 842 | } |
951 | 843 | ||
952 | /* Phase.4 : Link unchecked xdatum to xattr_unchecked list */ | 844 | /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */ |
953 | for (i=0; i < XATTRINDEX_HASHSIZE; i++) { | 845 | for (i=0; i < XATTRINDEX_HASHSIZE; i++) { |
954 | list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { | 846 | list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { |
847 | xdatum_count++; | ||
955 | list_del_init(&xd->xindex); | 848 | list_del_init(&xd->xindex); |
956 | if (!xd->refcnt) { | 849 | if (!xd->refcnt) { |
957 | JFFS2_WARNING("orphan xdatum(xid=%u, version=%u)\n", | 850 | dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n", |
958 | xd->xid, xd->version); | 851 | xd->xid, xd->version); |
959 | set_xattr_datum_dead(xd); | 852 | xd->flags |= JFFS2_XFLAGS_DEAD; |
960 | list_add(&xd->xindex, &c->xattr_unchecked); | 853 | list_add(&xd->xindex, &c->xattr_unchecked); |
854 | xdatum_orphan_count++; | ||
961 | continue; | 855 | continue; |
962 | } | 856 | } |
963 | if (is_xattr_datum_unchecked(c, xd)) { | 857 | if (is_xattr_datum_unchecked(c, xd)) { |
@@ -966,12 +860,14 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) | |||
966 | list_add(&xd->xindex, &c->xattr_unchecked); | 860 | list_add(&xd->xindex, &c->xattr_unchecked); |
967 | xdatum_unchecked_count++; | 861 | xdatum_unchecked_count++; |
968 | } | 862 | } |
969 | xdatum_count++; | ||
970 | } | 863 | } |
971 | } | 864 | } |
972 | /* build complete */ | 865 | /* build complete */ |
973 | JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and " | 866 | JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum" |
974 | "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count); | 867 | " (%u unchecked, %u orphan) and " |
868 | "%u of xref (%u dead, %u orphan) found.\n", | ||
869 | xdatum_count, xdatum_unchecked_count, xdatum_orphan_count, | ||
870 | xref_count, xref_dead_count, xref_orphan_count); | ||
975 | } | 871 | } |
976 | 872 | ||
977 | struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, | 873 | struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, |
@@ -1079,7 +975,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
1079 | rc = load_xattr_datum(c, xd); | 975 | rc = load_xattr_datum(c, xd); |
1080 | if (unlikely(rc > 0)) { | 976 | if (unlikely(rc > 0)) { |
1081 | *pref = ref->next; | 977 | *pref = ref->next; |
1082 | delete_xattr_ref_delay(c, ref); | 978 | delete_xattr_ref(c, ref); |
1083 | goto retry; | 979 | goto retry; |
1084 | } else if (unlikely(rc < 0)) | 980 | } else if (unlikely(rc < 0)) |
1085 | goto out; | 981 | goto out; |
@@ -1140,7 +1036,7 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, | |||
1140 | rc = load_xattr_datum(c, xd); | 1036 | rc = load_xattr_datum(c, xd); |
1141 | if (unlikely(rc > 0)) { | 1037 | if (unlikely(rc > 0)) { |
1142 | *pref = ref->next; | 1038 | *pref = ref->next; |
1143 | delete_xattr_ref_delay(c, ref); | 1039 | delete_xattr_ref(c, ref); |
1144 | goto retry; | 1040 | goto retry; |
1145 | } else if (unlikely(rc < 0)) { | 1041 | } else if (unlikely(rc < 0)) { |
1146 | goto out; | 1042 | goto out; |
@@ -1203,7 +1099,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, | |||
1203 | rc = load_xattr_datum(c, xd); | 1099 | rc = load_xattr_datum(c, xd); |
1204 | if (unlikely(rc > 0)) { | 1100 | if (unlikely(rc > 0)) { |
1205 | *pref = ref->next; | 1101 | *pref = ref->next; |
1206 | delete_xattr_ref_delay(c, ref); | 1102 | delete_xattr_ref(c, ref); |
1207 | goto retry; | 1103 | goto retry; |
1208 | } else if (unlikely(rc < 0)) | 1104 | } else if (unlikely(rc < 0)) |
1209 | goto out; | 1105 | goto out; |
@@ -1214,8 +1110,23 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, | |||
1214 | goto out; | 1110 | goto out; |
1215 | } | 1111 | } |
1216 | if (!buffer) { | 1112 | if (!buffer) { |
1217 | *pref = ref->next; | 1113 | ref->ino = ic->ino; |
1218 | rc = delete_xattr_ref(c, ref, 0); | 1114 | ref->xid = xd->xid; |
1115 | ref->xseqno |= XREF_DELETE_MARKER; | ||
1116 | rc = save_xattr_ref(c, ref); | ||
1117 | if (!rc) { | ||
1118 | *pref = ref->next; | ||
1119 | spin_lock(&c->erase_completion_lock); | ||
1120 | ref->next = c->xref_dead_list; | ||
1121 | c->xref_dead_list = ref; | ||
1122 | spin_unlock(&c->erase_completion_lock); | ||
1123 | if (!--xd->refcnt) | ||
1124 | delete_xattr_datum(c, xd); | ||
1125 | } else { | ||
1126 | ref->ic = ic; | ||
1127 | ref->xd = xd; | ||
1128 | ref->xseqno &= ~XREF_DELETE_MARKER; | ||
1129 | } | ||
1219 | goto out; | 1130 | goto out; |
1220 | } | 1131 | } |
1221 | goto found; | 1132 | goto found; |
@@ -1248,7 +1159,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, | |||
1248 | JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); | 1159 | JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); |
1249 | xd->refcnt--; | 1160 | xd->refcnt--; |
1250 | if (!xd->refcnt) | 1161 | if (!xd->refcnt) |
1251 | delete_xattr_datum_delay(c, xd); | 1162 | delete_xattr_datum(c, xd); |
1252 | up_write(&c->xattr_sem); | 1163 | up_write(&c->xattr_sem); |
1253 | return rc; | 1164 | return rc; |
1254 | } | 1165 | } |
@@ -1263,21 +1174,9 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, | |||
1263 | rc = PTR_ERR(newref); | 1174 | rc = PTR_ERR(newref); |
1264 | xd->refcnt--; | 1175 | xd->refcnt--; |
1265 | if (!xd->refcnt) | 1176 | if (!xd->refcnt) |
1266 | delete_xattr_datum_delay(c, xd); | 1177 | delete_xattr_datum(c, xd); |
1267 | } else if (ref) { | 1178 | } else if (ref) { |
1268 | up_write(&c->xattr_sem); | 1179 | delete_xattr_ref(c, ref); |
1269 | jffs2_complete_reservation(c); | ||
1270 | |||
1271 | rc = jffs2_reserve_space(c, request, &length, | ||
1272 | ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); | ||
1273 | down_write(&c->xattr_sem); | ||
1274 | if (rc) { | ||
1275 | JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); | ||
1276 | delete_xattr_ref_delay(c, ref); | ||
1277 | up_write(&c->xattr_sem); | ||
1278 | return 0; | ||
1279 | } | ||
1280 | delete_xattr_ref(c, ref, 1); | ||
1281 | } | 1180 | } |
1282 | out: | 1181 | out: |
1283 | up_write(&c->xattr_sem); | 1182 | up_write(&c->xattr_sem); |
@@ -1292,6 +1191,10 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, | |||
1292 | * is used to move xref into new node. | 1191 | * is used to move xref into new node. |
1293 | * jffs2_verify_xattr(c) | 1192 | * jffs2_verify_xattr(c) |
1294 | * is used to call do_verify_xattr_datum() before garbage collecting. | 1193 | * is used to call do_verify_xattr_datum() before garbage collecting. |
1194 | * jffs2_release_xattr_datum(c, xd) | ||
1195 | * is used to release an in-memory object of xdatum. | ||
1196 | * jffs2_release_xattr_ref(c, ref) | ||
1197 | * is used to release an in-memory object of xref. | ||
1295 | * -------------------------------------------------- */ | 1198 | * -------------------------------------------------- */ |
1296 | int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, | 1199 | int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, |
1297 | struct jffs2_raw_node_ref *raw) | 1200 | struct jffs2_raw_node_ref *raw) |
@@ -1302,18 +1205,17 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt | |||
1302 | down_write(&c->xattr_sem); | 1205 | down_write(&c->xattr_sem); |
1303 | if (xd->node != raw) | 1206 | if (xd->node != raw) |
1304 | goto out; | 1207 | goto out; |
1305 | if (is_xattr_datum_dead(xd) && (raw->next_in_ino == (void *)xd)) | 1208 | if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)) |
1306 | goto out; | 1209 | goto out; |
1307 | 1210 | ||
1308 | old_ofs = ref_offset(xd->node); | 1211 | rc = load_xattr_datum(c, xd); |
1309 | totlen = ref_totlen(c, c->gcblock, xd->node); | 1212 | if (unlikely(rc)) { |
1310 | 1213 | rc = (rc > 0) ? 0 : rc; | |
1311 | if (!is_xattr_datum_dead(xd)) { | 1214 | goto out; |
1312 | rc = load_xattr_datum(c, xd); | ||
1313 | if (unlikely(rc < 0)) | ||
1314 | goto out; | ||
1315 | } | 1215 | } |
1316 | 1216 | old_ofs = ref_offset(xd->node); | |
1217 | totlen = PAD(sizeof(struct jffs2_raw_xattr) | ||
1218 | + xd->name_len + 1 + xd->value_len); | ||
1317 | rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); | 1219 | rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); |
1318 | if (rc) { | 1220 | if (rc) { |
1319 | JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); | 1221 | JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); |
@@ -1331,7 +1233,6 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt | |||
1331 | return rc; | 1233 | return rc; |
1332 | } | 1234 | } |
1333 | 1235 | ||
1334 | |||
1335 | int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, | 1236 | int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, |
1336 | struct jffs2_raw_node_ref *raw) | 1237 | struct jffs2_raw_node_ref *raw) |
1337 | { | 1238 | { |
@@ -1392,7 +1293,7 @@ int jffs2_verify_xattr(struct jffs2_sb_info *c) | |||
1392 | raw->flash_offset = ref_offset(raw) | 1293 | raw->flash_offset = ref_offset(raw) |
1393 | | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); | 1294 | | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); |
1394 | } | 1295 | } |
1395 | if (is_xattr_datum_dead(xd)) | 1296 | if (xd->flags & JFFS2_XFLAGS_DEAD) |
1396 | list_add(&xd->xindex, &c->xattr_dead_list); | 1297 | list_add(&xd->xindex, &c->xattr_dead_list); |
1397 | spin_unlock(&c->erase_completion_lock); | 1298 | spin_unlock(&c->erase_completion_lock); |
1398 | } | 1299 | } |
@@ -1403,7 +1304,7 @@ int jffs2_verify_xattr(struct jffs2_sb_info *c) | |||
1403 | void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) | 1304 | void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) |
1404 | { | 1305 | { |
1405 | /* must be called under spin_lock(&c->erase_completion_lock) */ | 1306 | /* must be called under spin_lock(&c->erase_completion_lock) */ |
1406 | if (xd->node != (void *)xd) | 1307 | if (xd->refcnt > 0 || xd->node != (void *)xd) |
1407 | return; | 1308 | return; |
1408 | 1309 | ||
1409 | list_del(&xd->xindex); | 1310 | list_del(&xd->xindex); |
@@ -1421,8 +1322,8 @@ void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re | |||
1421 | for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { | 1322 | for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { |
1422 | if (ref == tmp) { | 1323 | if (ref == tmp) { |
1423 | *ptmp = tmp->next; | 1324 | *ptmp = tmp->next; |
1424 | jffs2_free_xattr_ref(ref); | ||
1425 | break; | 1325 | break; |
1426 | } | 1326 | } |
1427 | } | 1327 | } |
1328 | jffs2_free_xattr_ref(ref); | ||
1428 | } | 1329 | } |
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 06ab7b880212..4a10abc6d917 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ | 17 | #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ |
18 | #define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */ | 18 | #define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */ |
19 | #define JFFS2_XFLAGS_DEAD (0x40) /* This datum is already dead */ | ||
19 | #define JFFS2_XFLAGS_INVALID (0x80) /* This datum contains crc error */ | 20 | #define JFFS2_XFLAGS_INVALID (0x80) /* This datum contains crc error */ |
20 | 21 | ||
21 | struct jffs2_xattr_datum | 22 | struct jffs2_xattr_datum |
@@ -60,34 +61,12 @@ struct jffs2_xattr_ref | |||
60 | struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ | 61 | struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ |
61 | }; | 62 | }; |
62 | 63 | ||
63 | #define XDATUM_DELETE_MARKER (0xffffffff) | ||
64 | #define XREF_DELETE_MARKER (0x00000001) | 64 | #define XREF_DELETE_MARKER (0x00000001) |
65 | static inline int is_xattr_datum_dead(struct jffs2_xattr_datum *xd) | ||
66 | { | ||
67 | return (xd->version == XDATUM_DELETE_MARKER); | ||
68 | } | ||
69 | |||
70 | static inline void set_xattr_datum_dead(struct jffs2_xattr_datum *xd) | ||
71 | { | ||
72 | xd->version = XDATUM_DELETE_MARKER; | ||
73 | } | ||
74 | |||
75 | static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref) | 65 | static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref) |
76 | { | 66 | { |
77 | return ((ref->xseqno & XREF_DELETE_MARKER) != 0); | 67 | return ((ref->xseqno & XREF_DELETE_MARKER) != 0); |
78 | } | 68 | } |
79 | 69 | ||
80 | static inline void set_xattr_ref_dead(struct jffs2_xattr_ref *ref) | ||
81 | { | ||
82 | ref->xseqno |= XREF_DELETE_MARKER; | ||
83 | } | ||
84 | |||
85 | static inline void clr_xattr_ref_dead(struct jffs2_xattr_ref *ref) | ||
86 | { | ||
87 | ref->xseqno &= ~XREF_DELETE_MARKER; | ||
88 | } | ||
89 | |||
90 | |||
91 | #ifdef CONFIG_JFFS2_FS_XATTR | 70 | #ifdef CONFIG_JFFS2_FS_XATTR |
92 | 71 | ||
93 | extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c); | 72 | extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c); |