📄 xattr.c
字号:
int rc; spin_lock(&c->erase_completion_lock); if (ref_flags(ref->node) != REF_UNCHECKED) goto complete; offset = ref_offset(ref->node); spin_unlock(&c->erase_completion_lock); rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr); if (rc || sizeof(rr) != readlen) { JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n", rc, sizeof(rr), readlen, offset); return rc ? rc : -EIO; } /* obsolete node */ crc = crc32(0, &rr, sizeof(rr) - 4); if (crc != je32_to_cpu(rr.node_crc)) { JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", offset, je32_to_cpu(rr.node_crc), crc); return EIO; } if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) { JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, " "nodetype=%#04x/%#04x, totlen=%u/%zu\n", offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, je32_to_cpu(rr.totlen), PAD(sizeof(rr))); return EIO; } ref->ino = je32_to_cpu(rr.ino); ref->xid = je32_to_cpu(rr.xid); ref->xseqno = je32_to_cpu(rr.xseqno); if (ref->xseqno > c->highest_xseqno) c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER); spin_lock(&c->erase_completion_lock); complete: for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) { jeb = &c->blocks[ref_offset(raw) / c->sector_size]; totlen = PAD(ref_totlen(c, jeb, raw)); if (ref_flags(raw) == REF_UNCHECKED) { c->unchecked_size -= totlen; c->used_size += totlen; jeb->unchecked_size -= totlen; jeb->used_size += totlen; } raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL); } spin_unlock(&c->erase_completion_lock); dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n", ref->ino, ref->xid, ref_offset(ref->node)); return 0;}static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref){ /* must be called under down_write(xattr_sem) */ struct jffs2_raw_xref rr; size_t length; uint32_t xseqno, phys_ofs = write_ofs(c); int ret; rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); rr.totlen = cpu_to_je32(PAD(sizeof(rr))); rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4)); xseqno = (c->highest_xseqno += 2); if (is_xattr_ref_dead(ref)) { xseqno |= XREF_DELETE_MARKER; rr.ino = cpu_to_je32(ref->ino); rr.xid = cpu_to_je32(ref->xid); } else { rr.ino = cpu_to_je32(ref->ic->ino); rr.xid = cpu_to_je32(ref->xd->xid); } rr.xseqno = cpu_to_je32(xseqno); rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4)); ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr); if (ret || sizeof(rr) != length) { JFFS2_WARNING("jffs2_flash_write() returned %d, request=%zu, retlen=%zu, at %#08x\n", ret, sizeof(rr), length, phys_ofs); ret = ret ? ret : -EIO; if (length) jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL); return ret; } /* success */ ref->xseqno = xseqno; jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref); dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid); return 0;}static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_xattr_datum *xd){ /* must be called under down_write(xattr_sem) */ struct jffs2_xattr_ref *ref; int ret; ref = jffs2_alloc_xattr_ref(); if (!ref) return ERR_PTR(-ENOMEM); ref->ic = ic; ref->xd = xd; ret = save_xattr_ref(c, ref); if (ret) { jffs2_free_xattr_ref(ref); return ERR_PTR(ret); } /* Chain to inode */ ref->next = ic->xref; ic->xref = ref; return ref; /* success */}static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref){ /* must be called under down_write(xattr_sem) */ struct jffs2_xattr_datum *xd; xd = ref->xd; ref->xseqno |= XREF_DELETE_MARKER; ref->ino = ref->ic->ino; ref->xid = ref->xd->xid; spin_lock(&c->erase_completion_lock); ref->next = c->xref_dead_list; c->xref_dead_list = ref; spin_unlock(&c->erase_completion_lock); dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n", ref->ino, ref->xid, ref->xseqno); unrefer_xattr_datum(c, xd);}void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic){ /* It's called from jffs2_clear_inode() on inode removing. When an inode with XATTR is removed, those XATTRs must be removed. */ struct jffs2_xattr_ref *ref, *_ref; if (!ic || ic->nlink > 0) return; down_write(&c->xattr_sem); for (ref = ic->xref; ref; ref = _ref) { _ref = ref->next; delete_xattr_ref(c, ref); } ic->xref = NULL; up_write(&c->xattr_sem);}void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic){ /* It's called from jffs2_free_ino_caches() until unmounting FS. */ struct jffs2_xattr_datum *xd; struct jffs2_xattr_ref *ref, *_ref; down_write(&c->xattr_sem); for (ref = ic->xref; ref; ref = _ref) { _ref = ref->next; xd = ref->xd; if (atomic_dec_and_test(&xd->refcnt)) { unload_xattr_datum(c, xd); jffs2_free_xattr_datum(xd); } jffs2_free_xattr_ref(ref); } ic->xref = NULL; up_write(&c->xattr_sem);}static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic){ /* success of check_xattr_ref_inode() means taht inode (ic) dose not have * duplicate name/value pairs. If duplicate name/value pair would be found, * one will be removed. */ struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp; int rc = 0; if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) return 0; down_write(&c->xattr_sem); retry: rc = 0; for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { if (!ref->xd->xname) { rc = load_xattr_datum(c, ref->xd); if (unlikely(rc > 0)) { *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) { if (!cmp->xd->xname) { ref->xd->flags |= JFFS2_XFLAGS_BIND; rc = load_xattr_datum(c, cmp->xd); ref->xd->flags &= ~JFFS2_XFLAGS_BIND; if (unlikely(rc > 0)) { *pcmp = cmp->next; delete_xattr_ref(c, cmp); goto retry; } else if (unlikely(rc < 0)) goto out; } if (ref->xd->xprefix == cmp->xd->xprefix && !strcmp(ref->xd->xname, cmp->xd->xname)) { if (ref->xseqno > cmp->xseqno) { *pcmp = cmp->next; delete_xattr_ref(c, cmp); } else { *pref = ref->next; delete_xattr_ref(c, ref); } goto retry; } } } ic->flags |= INO_FLAGS_XATTR_CHECKED; out: up_write(&c->xattr_sem); return rc;}/* -------- xattr subsystem functions --------------- * jffs2_init_xattr_subsystem(c) * is used to initialize semaphore and list_head, and some variables. * jffs2_find_xattr_datum(c, xid) * is used to lookup xdatum while scanning process. * jffs2_clear_xattr_subsystem(c) * is used to release any xattr related objects. * jffs2_build_xattr_subsystem(c) * is used to associate xdatum and xref while super block building process. * jffs2_setup_xattr_datum(c, xid, version) * is used to insert xdatum while scanning process. * -------------------------------------------------- */void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c){ int i; for (i=0; i < XATTRINDEX_HASHSIZE; i++) INIT_LIST_HEAD(&c->xattrindex[i]); INIT_LIST_HEAD(&c->xattr_unchecked); INIT_LIST_HEAD(&c->xattr_dead_list); c->xref_dead_list = NULL; c->xref_temp = NULL; init_rwsem(&c->xattr_sem); c->highest_xid = 0; c->highest_xseqno = 0; c->xdatum_mem_usage = 0; c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */}static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid){ struct jffs2_xattr_datum *xd; int i = xid % XATTRINDEX_HASHSIZE; /* It's only used in scanning/building process. */ BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING))); list_for_each_entry(xd, &c->xattrindex[i], xindex) { if (xd->xid==xid) return xd; } return NULL;}void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c){ struct jffs2_xattr_datum *xd, *_xd; struct jffs2_xattr_ref *ref, *_ref; int i; for (ref=c->xref_temp; ref; ref = _ref) { _ref = ref->next; jffs2_free_xattr_ref(ref); } for (ref=c->xref_dead_list; ref; ref = _ref) { _ref = ref->next; jffs2_free_xattr_ref(ref); } for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { list_del(&xd->xindex); if (xd->xname) kfree(xd->xname); jffs2_free_xattr_datum(xd); } } list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) { list_del(&xd->xindex); jffs2_free_xattr_datum(xd); } list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { list_del(&xd->xindex); jffs2_free_xattr_datum(xd); }}#define XREF_TMPHASH_SIZE (128)void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c){ struct jffs2_xattr_ref *ref, *_ref; struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE]; struct jffs2_xattr_datum *xd, *_xd; struct jffs2_inode_cache *ic; struct jffs2_raw_node_ref *raw; int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0; BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); /* Phase.1 : Merge same xref */ for (i=0; i < XREF_TMPHASH_SIZE; i++) xref_tmphash[i] = NULL; for (ref=c->xref_temp; ref; ref=_ref) { struct jffs2_xattr_ref *tmp; _ref = ref->next; if (ref_flags(ref->node) != REF_PRISTINE) { if (verify_xattr_ref(c, ref)) { BUG_ON(ref->node->next_in_ino != (void *)ref); ref->node->next_in_ino = NULL; jffs2_mark_node_obsolete(c, ref->node); jffs2_free_xattr_ref(ref); continue; } } i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE; for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) { if (tmp->ino == ref->ino && tmp->xid == ref->xid) break; } if (tmp) { raw = ref->node; if (ref->xseqno > tmp->xseqno) { tmp->xseqno = ref->xseqno; raw->next_in_ino = tmp->node; tmp->node = raw; } else { raw->next_in_ino = tmp->node->next_in_ino; tmp->node->next_in_ino = raw; } jffs2_free_xattr_ref(ref); continue; } else { ref->next = xref_tmphash[i]; xref_tmphash[i] = ref; } } c->xref_temp = NULL; /* Phase.2 : Bind xref with inode_cache and xattr_datum */ for (i=0; i < XREF_TMPHASH_SIZE; i++) { for (ref=xref_tmphash[i]; ref; ref=_ref) { xref_count++; _ref = ref->next; if (is_xattr_ref_dead(ref)) { ref->next = c->xref_dead_list; c->xref_dead_list = ref; xref_dead_count++; continue; } /* At this point, ref->xid and ref->ino contain XID and inode number. ref->xd and ref->ic are not valid yet. */ xd = jffs2_find_xattr_datum(c, ref->xid); ic = jffs2_get_ino_cache(c, ref->ino); if (!xd || !ic || !ic->nlink) { dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", ref->ino, ref->xid, ref->xseqno); ref->xseqno |= XREF_DELETE_MARKER; ref->next = c->xref_dead_list; c->xref_dead_list = ref; xref_orphan_count++; continue; } ref->xd = xd; ref->ic = ic; atomic_inc(&xd->refcnt); ref->next = ic->xref; ic->xref = ref; } } /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */ for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { xdatum_count++; list_del_init(&xd->xindex); if (!atomic_read(&xd->refcnt)) { dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n", xd->xid, xd->version); xd->flags |= JFFS2_XFLAGS_DEAD; list_add(&xd->xindex, &c->xattr_unchecked); xdatum_orphan_count++; continue; } if (is_xattr_datum_unchecked(c, xd)) { dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n", xd->xid, xd->version); list_add(&xd->xindex, &c->xattr_unchecked); xdatum_unchecked_count++; } } } /* build complete */ JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum" " (%u unchecked, %u orphan) and " "%u of xref (%u dead, %u orphan) found.\n", xdatum_count, xdatum_unchecked_count, xdatum_orphan_count, xref_count, xref_dead_count, xref_orphan_count);}struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, uint32_t xid, uint32_t version){ struct jffs2_xattr_datum *xd; xd = jffs2_find_xattr_datum(c, xid); if (!xd) { xd = jffs2_alloc_xattr_datum(); if (!xd)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -