📄 xattr.c
字号:
return ERR_PTR(-ENOMEM); xd->xid = xid; xd->version = version; if (xd->xid > c->highest_xid) c->highest_xid = xd->xid; list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]); } return xd;}/* -------- 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. * -------------------------------------------------- */struct xattr_handler *jffs2_xattr_handlers[] = { &jffs2_user_xattr_handler,#ifdef CONFIG_JFFS2_FS_SECURITY &jffs2_security_xattr_handler,#endif#ifdef CONFIG_JFFS2_FS_POSIX_ACL &jffs2_acl_access_xattr_handler, &jffs2_acl_default_xattr_handler,#endif &jffs2_trusted_xattr_handler, NULL};static struct xattr_handler *xprefix_to_handler(int xprefix) { struct xattr_handler *ret; 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 = &jffs2_acl_access_xattr_handler; break; case JFFS2_XPREFIX_ACL_DEFAULT: ret = &jffs2_acl_default_xattr_handler; break;#endif case JFFS2_XPREFIX_TRUSTED: ret = &jffs2_trusted_xattr_handler; break; default: ret = NULL; break; } return ret;}ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size){ struct inode *inode = dentry->d_inode; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_ref *ref, **pref; struct jffs2_xattr_datum *xd; struct xattr_handler *xhandle; ssize_t len, rc; int retry = 0; rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: len = 0; for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic != ic); xd = ref->xd; if (!xd->xname) { /* xdatum is unchached */ if (!retry) { retry = 1; up_read(&c->xattr_sem); down_write(&c->xattr_sem); goto retry; } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } } xhandle = xprefix_to_handler(xd->xprefix); if (!xhandle) continue; if (buffer) { rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len); } else { rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len); } if (rc < 0) goto out; len += rc; } rc = len; out: if (!retry) { up_read(&c->xattr_sem); } else { up_write(&c->xattr_sem); } return rc;}int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, char *buffer, size_t size){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; struct jffs2_xattr_ref *ref, **pref; int rc, retry = 0; rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic!=ic); xd = ref->xd; if (xd->xprefix != xprefix) continue; if (!xd->xname) { /* xdatum is unchached */ if (!retry) { retry = 1; up_read(&c->xattr_sem); down_write(&c->xattr_sem); goto retry; } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) { goto out; } } } if (!strcmp(xname, xd->xname)) { rc = xd->value_len; if (buffer) { if (size < rc) { rc = -ERANGE; } else { memcpy(buffer, xd->xvalue, rc); } } goto out; } } rc = -ENODATA; out: if (!retry) { up_read(&c->xattr_sem); } else { up_write(&c->xattr_sem); } return rc;}int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, const char *buffer, size_t size, int flags){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; struct jffs2_xattr_ref *ref, *newref, **pref; uint32_t length, request; int rc; rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size); rc = jffs2_reserve_space(c, request, &length, ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE); if (rc) { JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); return rc; } /* Find existing xattr */ down_write(&c->xattr_sem); retry: for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { xd = ref->xd; if (xd->xprefix != xprefix) continue; if (!xd->xname) { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } if (!strcmp(xd->xname, xname)) { if (flags & XATTR_CREATE) { rc = -EEXIST; goto out; } if (!buffer) { ref->ino = ic->ino; ref->xid = xd->xid; ref->xseqno |= XREF_DELETE_MARKER; rc = save_xattr_ref(c, ref); if (!rc) { *pref = ref->next; spin_lock(&c->erase_completion_lock); ref->next = c->xref_dead_list; c->xref_dead_list = ref; spin_unlock(&c->erase_completion_lock); unrefer_xattr_datum(c, xd); } else { ref->ic = ic; ref->xd = xd; ref->xseqno &= ~XREF_DELETE_MARKER; } goto out; } goto found; } } /* not found */ if (flags & XATTR_REPLACE) { rc = -ENODATA; goto out; } if (!buffer) { rc = -ENODATA; goto out; } found: xd = create_xattr_datum(c, xprefix, xname, buffer, size); if (IS_ERR(xd)) { rc = PTR_ERR(xd); goto out; } up_write(&c->xattr_sem); jffs2_complete_reservation(c); /* create xattr_ref */ request = PAD(sizeof(struct jffs2_raw_xref)); rc = jffs2_reserve_space(c, request, &length, ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE); down_write(&c->xattr_sem); if (rc) { JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); unrefer_xattr_datum(c, xd); up_write(&c->xattr_sem); return rc; } if (ref) *pref = ref->next; newref = create_xattr_ref(c, ic, xd); if (IS_ERR(newref)) { if (ref) { ref->next = ic->xref; ic->xref = ref; } rc = PTR_ERR(newref); unrefer_xattr_datum(c, xd); } else if (ref) { delete_xattr_ref(c, ref); } out: up_write(&c->xattr_sem); jffs2_complete_reservation(c); return rc;}/* -------- 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; rc = load_xattr_datum(c, xd); if (unlikely(rc)) { rc = (rc > 0) ? 0 : rc; goto out; } old_ofs = ref_offset(xd->node); totlen = PAD(sizeof(struct jffs2_raw_xattr) + xd->name_len + 1 + xd->value_len); rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); if (rc) { JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); goto out; } rc = save_xattr_datum(c, xd); if (!rc) dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n", xd->xid, xd->version, old_ofs, ref_offset(xd->node)); out: if (!rc) jffs2_mark_node_obsolete(c, raw); up_write(&c->xattr_sem); return rc;}int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, struct jffs2_raw_node_ref *raw){ uint32_t totlen, length, old_ofs; int rc = 0; down_write(&c->xattr_sem); BUG_ON(!ref->node); if (ref->node != raw) goto out; if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref)) goto out; old_ofs = ref_offset(ref->node); totlen = ref_totlen(c, c->gcblock, ref->node); rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE); if (rc) { JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n", __FUNCTION__, rc, totlen); rc = rc ? rc : -EBADFD; goto out; } rc = save_xattr_ref(c, ref); if (!rc) dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n", ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node)); out: if (!rc) jffs2_mark_node_obsolete(c, raw); up_write(&c->xattr_sem); return rc;}int jffs2_verify_xattr(struct jffs2_sb_info *c){ struct jffs2_xattr_datum *xd, *_xd; struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; uint32_t totlen; int rc; down_write(&c->xattr_sem); list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { rc = do_verify_xattr_datum(c, xd); if (rc < 0) continue; list_del_init(&xd->xindex); spin_lock(&c->erase_completion_lock); for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { if (ref_flags(raw) != REF_UNCHECKED) continue; jeb = &c->blocks[ref_offset(raw) / c->sector_size]; totlen = PAD(ref_totlen(c, jeb, raw)); c->unchecked_size -= totlen; c->used_size += totlen; jeb->unchecked_size -= totlen; jeb->used_size += totlen; raw->flash_offset = ref_offset(raw) | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); } if (xd->flags & JFFS2_XFLAGS_DEAD) list_add(&xd->xindex, &c->xattr_dead_list); spin_unlock(&c->erase_completion_lock); } up_write(&c->xattr_sem); return list_empty(&c->xattr_unchecked) ? 1 : 0;}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; list_del(&xd->xindex); jffs2_free_xattr_datum(xd);}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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -