#include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/time.h> #include <linux/pagemap.h> #include <linux/highmem.h> #include <linux/crc32.h> #include <linux/jffs2.h> #include <linux/xattr.h> #include <linux/posix_acl_xattr.h> #include <linux/mtd/mtd.h> #include"nodelist.h" /* -------- xdatum related functions ---------------- * xattr_datum_hashkey(xprefix, xname, xvalue, xsize) * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is * the index of the xattr name/value pair cache (c->xattrindex). * is_xattr_datum_unchecked(c, xd) * returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not * unchecked, it returns 0. * unload_xattr_datum(c, xd) * is used to release xattr name/value pair and detach from c->xattrindex. * reclaim_xattr_datum(c) * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold * is hard coded as 32KiB. * do_verify_xattr_datum(c, xd) * is used to load the xdatum informations without name/value pair from the medium. * It's necessary once, because those informations are not collected during mounting * process when EBS is enabled. * 0 will be returned, if success. An negative return value means recoverable error, and * positive return value means unrecoverable error. Thus, caller must remove this xdatum * and xref when it returned positive value. * do_load_xattr_datum(c, xd) * is used to load name/value pair from the medium. * The meanings of return value is same as do_verify_xattr_datum(). * load_xattr_datum(c, xd) * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum(). * If xd need to call do_verify_xattr_datum() at first, it's called before calling * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum(). * save_xattr_datum(c, xd) * is used to write xdatum to medium. xd->version will be incremented. * create_xattr_datum(c, xprefix, xname, xvalue, xsize) * is used to create new xdatum and write to medium. * unrefer_xattr_datum(c, xd) * is used to delete a xdatum. When nobody refers this xdatum, JFFS2_XFLAGS_DEAD * is set on xd->flags and chained xattr_dead_list or release it immediately. * In the first case, the garbage collector release it later.
* -------------------------------------------------- */ static uint32_t xattr_datum_hashkey(int xprefix, constchar *xname, constchar *xvalue, int xsize)
{ int name_len = strlen(xname);
staticvoid reclaim_xattr_datum(struct jffs2_sb_info *c)
{ /* must be called under down_write(xattr_sem) */ struct jffs2_xattr_datum *xd, *_xd;
uint32_t target, before; staticint index = 0; int count;
if (c->xdatum_mem_threshold > c->xdatum_mem_usage) return;
before = c->xdatum_mem_usage;
target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */ for (count = 0; count < XATTRINDEX_HASHSIZE; count++) {
list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) { if (xd->flags & JFFS2_XFLAGS_HOT) {
xd->flags &= ~JFFS2_XFLAGS_HOT;
} elseif (!(xd->flags & JFFS2_XFLAGS_BIND)) {
unload_xattr_datum(c, xd);
} if (c->xdatum_mem_usage <= target) goto out;
}
index = (index+1) % XATTRINDEX_HASHSIZE;
}
out:
JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n",
before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
}
staticint do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
{ /* must be called under down_write(xattr_sem) */ struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; struct jffs2_raw_xattr rx;
size_t readlen;
uint32_t crc, offset, totlen; int rc;
/* unchecked xdatum is chained with c->xattr_unchecked */
list_del_init(&xd->xindex);
dbg_xattr("success on verifying xdatum (xid=%u, version=%u)\n",
xd->xid, xd->version);
return 0;
}
staticint do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
{ /* must be called under down_write(xattr_sem) */ char *data;
size_t readlen;
uint32_t crc, length; int i, ret, retry = 0;
BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
BUG_ON(!list_empty(&xd->xindex));
retry:
length = xd->name_len + 1 + xd->value_len;
data = kmalloc(length, GFP_KERNEL); if (!data) return -ENOMEM;
ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr),
length, &readlen, data);
if (ret || length!=readlen) {
JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%zu, at %#08x\n",
ret, length, readlen, ref_offset(xd->node));
kfree(data); return ret ? ret : -EIO;
}
staticstruct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, int xprefix, constchar *xname, constchar *xvalue, int xsize)
{ /* must be called under down_write(xattr_sem) */ struct jffs2_xattr_datum *xd;
uint32_t hashkey, name_len; char *data; int i, rc;
/* Search xattr_datum has same xname/xvalue by index */
hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize);
i = hashkey % XATTRINDEX_HASHSIZE;
list_for_each_entry(xd, &c->xattrindex[i], xindex) { if (xd->hashkey==hashkey
&& xd->xprefix==xprefix
&& xd->value_len==xsize
&& !strcmp(xd->xname, xname)
&& !memcmp(xd->xvalue, xvalue, xsize)) {
atomic_inc(&xd->refcnt); return xd;
}
}
/* Not found, Create NEW XATTR-Cache */
name_len = strlen(xname);
xd = jffs2_alloc_xattr_datum(); if (!xd) return ERR_PTR(-ENOMEM);
staticvoid unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
{ /* must be called under down_write(xattr_sem) */ if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
unload_xattr_datum(c, xd);
xd->flags |= JFFS2_XFLAGS_DEAD; if (xd->node == (void *)xd) {
BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
jffs2_free_xattr_datum(xd);
} else {
list_add(&xd->xindex, &c->xattr_dead_list);
}
spin_unlock(&c->erase_completion_lock);
dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n",
xd->xid, xd->version);
}
}
/* -------- xref related functions ------------------ * verify_xattr_ref(c, ref) * is used to load xref information from medium. Because summary data does not * contain xid/ino, it's necessary to verify once while mounting process. * save_xattr_ref(c, ref) * is used to write xref to medium. If delete marker is marked, it write * a delete marker of xref into medium. * create_xattr_ref(c, ic, xd) * is used to create a new xref and write to medium. * delete_xattr_ref(c, ref) * is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER, * and allows GC to reclaim those physical nodes. * jffs2_xattr_delete_inode(c, ic) * is called to remove xrefs related to obsolete inode when inode is unlinked. * jffs2_xattr_free_inode(c, ic) * is called to release xattr related objects when unmounting. * check_xattr_ref_inode(c, ic) * is used to confirm inode does not have duplicate xattr name/value pair. * jffs2_xattr_do_crccheck_inode(c, ic) * is used to force xattr data integrity check during the initial gc scan.
* -------------------------------------------------- */ staticint verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
{ struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; struct jffs2_raw_xref rr;
size_t readlen;
uint32_t crc, offset, totlen; int rc;
dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
return 0;
}
staticstruct 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;
staticvoid 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;
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_evict_inode() on inode removing.
When an inode with XATTR is removed, those XATTRs must be removed. */ struct jffs2_xattr_ref *ref, *_ref;
staticint check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{ /* success of check_xattr_ref_inode() means that 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;
/* -------- 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;
/* -------- xattr subsystem functions --------------- * xprefix_to_handler(xprefix) * is used to translate xprefix into xattr_handler. * jffs2_listxattr(dentry, buffer, size) * is an implementation of listxattr handler on jffs2. * do_jffs2_getxattr(inode, xprefix, xname, buffer, size) * is an implementation of getxattr handler on jffs2. * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags) * is an implementation of setxattr handler on jffs2.
* -------------------------------------------------- */ conststruct xattr_handler * const jffs2_xattr_handlers[] = {
&jffs2_user_xattr_handler, #ifdef CONFIG_JFFS2_FS_SECURITY
&jffs2_security_xattr_handler, #endif
&jffs2_trusted_xattr_handler,
NULL
};
switch (xprefix) { case JFFS2_XPREFIX_USER:
ret = &jffs2_user_xattr_handler; break; #ifdef CONFIG_JFFS2_FS_SECURITY case JFFS2_XPREFIX_SECURITY:
ret = &jffs2_security_xattr_handler; break; #endif #ifdef CONFIG_JFFS2_FS_POSIX_ACL case JFFS2_XPREFIX_ACL_ACCESS:
ret = &nop_posix_acl_access; break; case JFFS2_XPREFIX_ACL_DEFAULT:
ret = &nop_posix_acl_default; break; #endif case JFFS2_XPREFIX_TRUSTED:
ret = &jffs2_trusted_xattr_handler; break; default: return NULL;
}
if (!xattr_handler_can_list(ret, dentry)) return NULL;
/* -------- garbage collector functions ------------- * jffs2_garbage_collect_xattr_datum(c, xd, raw) * is used to move xdatum into new node. * jffs2_garbage_collect_xattr_ref(c, ref, raw) * is used to move xref into new node. * jffs2_verify_xattr(c) * is used to call do_verify_xattr_datum() before garbage collecting. * jffs2_release_xattr_datum(c, xd) * is used to release an in-memory object of xdatum. * jffs2_release_xattr_ref(c, ref) * is used to release an in-memory object of xref.
* -------------------------------------------------- */ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, struct jffs2_raw_node_ref *raw)
{
uint32_t totlen, length, old_ofs; int rc = 0;
down_write(&c->xattr_sem); if (xd->node != raw) goto out; if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)) goto out;
void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
{ /* must be called under spin_lock(&c->erase_completion_lock) */ if (atomic_read(&xd->refcnt) || xd->node != (void *)xd) return;
void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
{ /* must be called under spin_lock(&c->erase_completion_lock) */ struct jffs2_xattr_ref *tmp, **ptmp;
if (ref->node != (void *)ref) return;
for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { if (ref == tmp) {
*ptmp = tmp->next; break;
}
}
jffs2_free_xattr_ref(ref);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.5 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.