⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2006  NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */#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/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. Currentry, 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, const char *xname, const char *xvalue, int xsize){	int name_len = strlen(xname);	return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);}static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd){	struct jffs2_raw_node_ref *raw;	int rc = 0;	spin_lock(&c->erase_completion_lock);	for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {		if (ref_flags(raw) == REF_UNCHECKED) {			rc = 1;			break;		}	}	spin_unlock(&c->erase_completion_lock);	return rc;}static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd){	/* must be called under down_write(xattr_sem) */	D1(dbg_xattr("%s: xid=%u, version=%u\n", __FUNCTION__, xd->xid, xd->version));	if (xd->xname) {		c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len);		kfree(xd->xname);	}	list_del_init(&xd->xindex);	xd->hashkey = 0;	xd->xname = NULL;	xd->xvalue = NULL;}static void 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;	static int 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;			} else if (!(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);}static int 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;	spin_lock(&c->erase_completion_lock);	offset = ref_offset(xd->node);	if (ref_flags(xd->node) == REF_PRISTINE)		goto complete;	spin_unlock(&c->erase_completion_lock);	rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx);	if (rc || readlen != sizeof(rx)) {		JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",			      rc, sizeof(rx), readlen, offset);		return rc ? rc : -EIO;	}	crc = crc32(0, &rx, sizeof(rx) - 4);	if (crc != je32_to_cpu(rx.node_crc)) {		JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",			    offset, je32_to_cpu(rx.hdr_crc), crc);		xd->flags |= JFFS2_XFLAGS_INVALID;		return EIO;	}	totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));	if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK	    || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR	    || je32_to_cpu(rx.totlen) != totlen	    || je32_to_cpu(rx.xid) != xd->xid	    || je32_to_cpu(rx.version) != xd->version) {		JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "			    "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",			    offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,			    je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,			    je32_to_cpu(rx.totlen), totlen,			    je32_to_cpu(rx.xid), xd->xid,			    je32_to_cpu(rx.version), xd->version);		xd->flags |= JFFS2_XFLAGS_INVALID;		return EIO;	}	xd->xprefix = rx.xprefix;	xd->name_len = rx.name_len;	xd->value_len = je16_to_cpu(rx.value_len);	xd->data_crc = je32_to_cpu(rx.data_crc);	spin_lock(&c->erase_completion_lock); complete:	for (raw=xd->node; raw != (void *)xd; 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) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL);	}	spin_unlock(&c->erase_completion_lock);	/* unchecked xdatum is chained with c->xattr_unchecked */	list_del_init(&xd->xindex);	dbg_xattr("success on verfying xdatum (xid=%u, version=%u)\n",		  xd->xid, xd->version);	return 0;}static int 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;	}	data[xd->name_len] = '\0';	crc = crc32(0, data, length);	if (crc != xd->data_crc) {		JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)"			      " at %#08x, read: 0x%08x calculated: 0x%08x\n",			      ref_offset(xd->node), xd->data_crc, crc);		kfree(data);		xd->flags |= JFFS2_XFLAGS_INVALID;		return EIO;	}	xd->flags |= JFFS2_XFLAGS_HOT;	xd->xname = data;	xd->xvalue = data + xd->name_len+1;	c->xdatum_mem_usage += length;	xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len);	i = xd->hashkey % XATTRINDEX_HASHSIZE;	list_add(&xd->xindex, &c->xattrindex[i]);	if (!retry) {		retry = 1;		reclaim_xattr_datum(c);		if (!xd->xname)			goto retry;	}	dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n",		  xd->xid, xd->xprefix, xd->xname);	return 0;}static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd){	/* must be called under down_write(xattr_sem);	 * rc < 0 : recoverable error, try again	 * rc = 0 : success	 * rc > 0 : Unrecoverable error, this node should be deleted.	 */	int rc = 0;	BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD);	if (xd->xname)		return 0;	if (xd->flags & JFFS2_XFLAGS_INVALID)		return EIO;	if (unlikely(is_xattr_datum_unchecked(c, xd)))		rc = do_verify_xattr_datum(c, xd);	if (!rc)		rc = do_load_xattr_datum(c, xd);	return rc;}static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd){	/* must be called under down_write(xattr_sem) */	struct jffs2_raw_xattr rx;	struct kvec vecs[2];	size_t length;	int rc, totlen;	uint32_t phys_ofs = write_ofs(c);	BUG_ON(!xd->xname);	BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID));	vecs[0].iov_base = &rx;	vecs[0].iov_len = sizeof(rx);	vecs[1].iov_base = xd->xname;	vecs[1].iov_len = xd->name_len + 1 + xd->value_len;	totlen = vecs[0].iov_len + vecs[1].iov_len;	/* Setup raw-xattr */	memset(&rx, 0, sizeof(rx));	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);	rx.totlen = cpu_to_je32(PAD(totlen));	rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));	rx.xid = cpu_to_je32(xd->xid);	rx.version = cpu_to_je32(++xd->version);	rx.xprefix = xd->xprefix;	rx.name_len = xd->name_len;	rx.value_len = cpu_to_je16(xd->value_len);	rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));	rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));	rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);	if (rc || totlen != length) {		JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n",			      rc, totlen, length, phys_ofs);		rc = rc ? rc : -EIO;		if (length)			jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL);		return rc;	}	/* success */	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd);	dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",		  xd->xid, xd->version, xd->xprefix, xd->xname);	return 0;}static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,						    int xprefix, const char *xname,						    const char *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);	data = kmalloc(name_len + 1 + xsize, GFP_KERNEL);	if (!data) {		jffs2_free_xattr_datum(xd);		return ERR_PTR(-ENOMEM);	}	strcpy(data, xname);	memcpy(data + name_len + 1, xvalue, xsize);	atomic_set(&xd->refcnt, 1);	xd->xid = ++c->highest_xid;	xd->flags |= JFFS2_XFLAGS_HOT;	xd->xprefix = xprefix;	xd->hashkey = hashkey;	xd->xname = data;	xd->xvalue = data + name_len + 1;	xd->name_len = name_len;	xd->value_len = xsize;	xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len);	rc = save_xattr_datum(c, xd);	if (rc) {		kfree(xd->xname);		jffs2_free_xattr_datum(xd);		return ERR_PTR(rc);	}	/* Insert Hash Index */	i = hashkey % XATTRINDEX_HASHSIZE;	list_add(&xd->xindex, &c->xattrindex[i]);	c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len);	reclaim_xattr_datum(c);	return xd;}static void 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. * -------------------------------------------------- */static int 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -