From: "ÂíÔÆ" <sx_yunma@bit.edu.cn>
To: linux-mtd@lists.infradead.org
Subject: [PATCH] XATTR support in JFFS2
Date: Mon, 22 Aug 2005 12:41:18 +0800 [thread overview]
Message-ID: <324685678.22043@bit.edu.cn> (raw)
[-- Attachment #1: Type: text/plain, Size: 412 bytes --]
Hi!
I've implemented the extended attributes for JFFS2. The implementation mechanism
is simple, but it can work:). This implementation support standard extended
attributes system call, such as setxattr, getxattr .... but does not support ACL.
The patch is based on Linux-2.6.10
Comments are welcome...
Signed-off-by: Yun Ma <yunma@sc.mcel.mot.com>
===========================
Best Regards
Yun Ma
[-- Attachment #2: patch-jffs2-xattr.patch --]
[-- Type: text/plain, Size: 18878 bytes --]
diff -uNr linux-2.6.10.mxc/fs/jffs2/file.c linux-2.6.10.jffs2/fs/jffs2/file.c
--- linux-2.6.10.mxc/fs/jffs2/file.c 2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/file.c 2005-08-19 15:48:40.000000000 +0800
@@ -20,6 +20,9 @@
#include <linux/highmem.h>
#include <linux/crc32.h>
#include <linux/jffs2.h>
+#ifdef CONFIG_JFFS2_FS_XATTR
+#include <linux/jffs2_xattr.h>
+#endif
#include "nodelist.h"
extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
@@ -55,6 +58,12 @@
struct inode_operations jffs2_file_inode_operations =
{
+#ifdef CONFIG_JFFS2_FS_XATTR
+ .setxattr = jffs2_setxattr,
+ .getxattr = jffs2_getxattr,
+ .listxattr = jffs2_listxattr,
+ .removexattr = jffs2_removexattr,
+#endif
.setattr = jffs2_setattr
};
diff -uNr linux-2.6.10.mxc/fs/jffs2/Makefile linux-2.6.10.jffs2/fs/jffs2/Makefile
--- linux-2.6.10.mxc/fs/jffs2/Makefile 2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/Makefile 2005-08-19 15:44:39.000000000 +0800
@@ -11,6 +11,7 @@
jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
jffs2-y += super.o
+jffs2-$(CONFIG_JFFS2_FS_XATTR) += xattr.o
jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
diff -uNr linux-2.6.10.mxc/fs/jffs2/nodelist.c linux-2.6.10.jffs2/fs/jffs2/nodelist.c
--- linux-2.6.10.mxc/fs/jffs2/nodelist.c 2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/nodelist.c 2005-08-19 15:47:12.000000000 +0800
@@ -173,6 +173,7 @@
goto free_out;
}
/* sanity check */
+ #ifndef CONFIG_JFFS2_FS_XATTR
if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
@@ -180,6 +181,7 @@
spin_lock(&c->erase_completion_lock);
continue;
}
+ #endif
if (je32_to_cpu(node.d.version) > *highest_version)
*highest_version = je32_to_cpu(node.d.version);
if (ref_obsolete(ref)) {
diff -uNr linux-2.6.10.mxc/fs/jffs2/xattr.c linux-2.6.10.jffs2/fs/jffs2/xattr.c
--- linux-2.6.10.mxc/fs/jffs2/xattr.c 1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.10.jffs2/fs/jffs2/xattr.c 2005-08-19 16:17:29.000000000 +0800
@@ -0,0 +1,467 @@
+/*
+ *
+ * Copyright 2005 Motorola, Inc. All Rights Reserved.
+ *
+ * Created by Ma yun <yunma@sc.mcel.mot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/jffs2_fs_i.h>
+#include <linux/jffs2_fs_sb.h>
+#include <linux/jffs2_xattr.h>
+#include <linux/mtd/mtd.h>
+#include <linux/time.h>
+#include "nodelist.h"
+
+
+struct xattr_buffer {
+ int size; /* the size of current use buffer */
+ struct jffs2_xattr_list *xattr; /* buffer containing EAs list */
+};
+
+static int ea_get(struct dentry *parent, struct inode *inode, struct xattr_buffer *ea_buf, int min_size)
+{
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode), *p;
+ struct jffs2_raw_dirent findnode;
+ struct jffs2_raw_node_ref *raw = NULL;
+ struct jffs2_full_dirent *fd_list = NULL;
+ size_t readlen;
+ int size;
+ uint32_t offset = 0;
+ uint32_t ino = f->inocache->ino;
+ int mem_size = 0;
+ int ret = 0;
+ int n_version =0 ;
+
+ memset(&findnode, 0, sizeof(findnode));
+ /* lookup the dirent list and find raw dirent*/
+
+ p = JFFS2_INODE_INFO(parent->d_inode);
+ down(&p->sem);
+ for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+ if (fd_list->ino == ino && fd_list->version >= n_version) n_version = fd_list->version;
+ }
+
+ for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+ if (fd_list->ino == ino && fd_list->version == n_version) break;
+ }
+
+ if (fd_list->ino == ino) {
+ for(raw = fd_list->raw; raw && raw->next_in_ino; raw = raw->next_in_ino){
+ offset = ref_offset(raw);
+ ret = jffs2_flash_read(c, offset, sizeof(findnode), &readlen,(char *)&findnode);
+ if (readlen != sizeof(findnode) || ret) {
+ up(&p->sem);
+ printk(KERN_WARNING"Error reading node from 0x%08x: %d\n",offset,ret);
+ return ret;
+ }
+ if ((je32_to_cpu(findnode.ino) == ino) && je16_to_cpu(findnode.nodetype) == JFFS2_NODETYPE_DIRENT) break;
+ }
+ } else {
+ up(&p->sem);
+ printk(KERN_WARNING"ea_get: can not find the file" );
+ return -1;
+ }
+ up(&p->sem);
+ /* actually, we should check CRC */
+
+ /* end of CRC check */
+ size = je32_to_cpu(findnode.totlen) - (findnode.nsize) - sizeof(findnode);
+ mem_size = max(size, min_size);
+ if (!mem_size) {
+ ea_buf->size = 0;
+ return 0;
+ } else {
+ /* allo`cate a buffer to work with */
+ ea_buf->size = mem_size;
+ ea_buf->xattr = kmalloc(mem_size, GFP_KERNEL);
+
+ if (ea_buf->xattr == NULL) {
+ return -ENOMEM;
+ }
+ /* copy rd EAs to ea_buf */
+ offset = ref_offset(raw);
+ ret = jffs2_flash_read(c, offset + sizeof(findnode) + findnode.nsize, size, &readlen, (char *)ea_buf->xattr);
+ if (ret|| readlen != size){
+ printk(KERN_WARNING"Error reading node form 0x%08x: %d\n", offset, ret);
+ return ret;
+ }
+ return size;
+ }
+}
+
+
+static int ea_put(struct dentry *parent, struct inode *inode, struct xattr_buffer *ea_buf, int new_size)
+{
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode), *p;
+ struct jffs2_raw_dirent *rd, findnode;
+ struct jffs2_raw_node_ref *raw;
+ struct jffs2_full_dirent *fd, *fd_list = NULL;
+ uint32_t direntlen, offset, alloclen, readlen;
+ int ret = 0;
+ char *name, *write_buf = NULL;
+ int namelen = 0;
+ uint32_t ino = f->inocache->ino;
+ int n_version =0 ;
+
+ memset(&findnode, 0, sizeof(findnode));
+ /* lookup the dirent list and find raw dirent*/
+ p = JFFS2_INODE_INFO(parent->d_inode);
+ down(&p->sem);
+
+ for(fd_list = p->dents; fd_list; fd_list = fd_list->next){
+ if (fd_list->ino == ino && fd_list->version >= n_version) n_version = fd_list->version;
+ }
+
+ for(fd_list = p->dents; fd_list; fd_list = fd_list->next)
+ if (fd_list->ino == ino && fd_list->version == fd_list->version) break;
+
+ if (fd_list->ino == ino){
+ for(raw = fd_list->raw; raw && raw->next_in_ino; raw = raw->next_in_ino) {
+ offset = ref_offset(raw);
+ ret = jffs2_flash_read(c, offset, sizeof(findnode), &readlen,(char *)&findnode);
+ if (ret||readlen != sizeof(findnode)) {
+ up(&p->sem);
+ printk(KERN_WARNING"Error reading node from 0x%08x: %d\n",offset,ret);
+ return ret;
+ }
+ if ((je32_to_cpu(findnode.ino) == ino) && je16_to_cpu(findnode.nodetype) == JFFS2_NODETYPE_DIRENT) break;
+ }
+ } else {
+ up(&p->sem);
+ printk(KERN_WARNING"ea_put: can not find the file" );
+ return -1;
+ }
+ up(&p->sem);
+
+ namelen = findnode.nsize;
+
+ /* alloc write_buf for write flash */
+ write_buf = kmalloc(namelen + new_size, GFP_KERNEL);
+ if (!write_buf) {
+ return -ENOMEM;
+ }
+ /* get the name in write_buf */
+ ret = jffs2_flash_read(c, offset + sizeof(findnode), findnode.nsize, &readlen, write_buf);
+ if (ret||readlen != findnode.nsize){
+ printk(KERN_WARNING"Error reading node form 0x%08x: %d\n", offset, ret);
+ return ret;
+ }
+ /* get the name in "name" */
+ name = kmalloc(namelen + 1, GFP_KERNEL);
+ if (!name) {
+ if (write_buf)
+ kfree(write_buf);
+ return -ENOMEM;
+ }
+ memcpy(name, write_buf, namelen);
+ /* find the space for write */
+ direntlen = sizeof(findnode) + namelen + new_size;
+ ret = jffs2_reserve_space(c, direntlen, &offset, &alloclen, ALLOC_NORMAL);
+ if (ret) {
+ return ret;
+ }
+ /* alloc the raw_dirent cache */
+ rd = jffs2_alloc_raw_dirent();
+ if (!rd) {
+ if (write_buf)
+ kfree(write_buf);
+ if (name)
+ kfree(name);
+ return -ENOMEM;
+ }
+
+ down(&p->sem);
+
+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+ rd->totlen = cpu_to_je32(direntlen);
+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4));
+
+ rd->pino = cpu_to_je32(p->inocache->ino);
+ rd->version = cpu_to_je32(++p->highest_version);
+ rd->ino = findnode.ino;
+ rd->mctime = cpu_to_je32(get_seconds());
+ rd->nsize = namelen;
+ rd->unused[0] = ea_buf->size;
+ /* fix me*/
+ memcpy(&(write_buf[namelen]), ea_buf->xattr, new_size);
+ rd->type = findnode.type;
+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd) - 8));
+ rd->name_crc = cpu_to_je32(crc32(0, write_buf, namelen));
+
+ fd = jffs2_write_dirent(c, p, rd, write_buf, namelen + new_size, offset, ALLOC_NORMAL);
+ /* restore the name */
+ fd->nhash = full_name_hash(name, namelen);
+ fd->name[namelen] = 0;
+ if (IS_ERR(fd)) {
+ if (write_buf)
+ kfree(write_buf);
+ if (name)
+ kfree(name);
+ jffs2_free_raw_dirent(rd);
+ jffs2_complete_reservation(c);
+ up(&p->sem);
+ return PTR_ERR(fd);
+ }
+ jffs2_add_fd_to_list(c, fd, &p->dents);
+ jffs2_complete_reservation(c);
+ jffs2_free_raw_dirent(rd);
+ up(&p->sem);
+ if (write_buf)
+ kfree(write_buf);
+ if (name)
+ kfree(name);
+
+ return 0;
+}
+
+
+static void ea_release(struct xattr_buffer *ea_buf)
+{
+ if (ea_buf->size)
+ kfree(ea_buf->xattr);
+}
+ssize_t jffs2_getxattr(struct dentry *dentry, const char *name, void *data, size_t buf_size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct dentry *parent;
+ struct jffs2_xattr_list *ealist;
+ struct jffs2_xattr *ea;
+ struct xattr_buffer ea_buf;
+ int xattr_size;
+ ssize_t size;
+ int namelen = strlen(name);
+ char *value;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ D1(printk(KERN_DEBUG"jffs2_getxattr: name=%s, buffer=%p, buffer_size=%ld",name,data,(long)buf_size));
+
+// down_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+ parent = dentry->d_parent;
+ xattr_size = ea_get(parent, inode, &ea_buf, 0);
+ if (xattr_size < 0) {
+ size = xattr_size;
+ goto out;
+ }
+
+ if (xattr_size == 0) {
+ goto not_found;
+ }
+
+ ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+
+ /* Find the named attribute*/
+ for (ea=FIRST_XATTR(ealist); ea < END_XATTR(ealist,xattr_size); ea = NEXT_XATTR(ea))
+ if ((namelen == ea->namelen) &&
+ memcmp(name,ea->name,namelen)==0) {
+ /* Found */
+ size = ea->valuelen;
+ if (!data)
+ goto release;
+ else if (size > buf_size) {
+ size = -ERANGE;
+ goto release;
+ }
+ value = ((char *)&ea->name) + ea->namelen + 1;
+ memcpy(data,value,size);
+ goto release;
+ }
+not_found:
+ data = NULL;
+ size = -ENODATA;
+release:
+ ea_release(&ea_buf);
+out:
+// up_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+ return size;
+}
+
+int jffs2_setxattr(struct dentry *dentry, const char *name, const void *value, size_t value_len, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ struct dentry *parent;
+ struct jffs2_xattr_list *ealist;
+ struct jffs2_xattr *ea, *old_ea = NULL, *next_ea = NULL;
+ struct xattr_buffer ea_buf;
+ int found=0;
+ int xattr_size = 0;
+ int namelen = strlen(name);
+ int old_ea_size = 0;
+ int new_size; /* the size of new EAs */
+ int length;
+ int ret;
+
+ if (value == NULL || value_len == 0) {
+ value = "";
+ value_len = 0;
+ }
+
+ parent = dentry->d_parent;
+ /* read the inode's EAs */
+ xattr_size = ea_get(parent, inode, &ea_buf, 0);
+ if (xattr_size < 0) {
+ ret = xattr_size;
+ goto out;
+ }
+
+ again:
+ ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+ new_size = sizeof(struct jffs2_xattr_list);
+
+ if (xattr_size) {
+ for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist,xattr_size); ea = NEXT_XATTR(ea)) {
+ if ((namelen == ea->namelen) &&
+ (memcmp(name, ea->name,namelen) == 0)) {
+ found = 1;
+ if (flags & XATTR_CREATE) {
+ ret = -EEXIST;
+ goto release;
+ }
+ old_ea = ea;
+ old_ea_size = JFFS2_XATTR_SIZE(ea);
+ next_ea = NEXT_XATTR(ea);
+ } else
+ new_size += JFFS2_XATTR_SIZE(ea);
+ }
+ }
+
+ if (!found) {
+ if (flags & XATTR_REPLACE) {
+ ret = -ENODATA;
+ goto release;
+ }
+ if (value == NULL) {
+ ret = 0;
+ goto release;
+ }
+ }
+ if (value && value_len)
+ new_size += sizeof(struct jffs2_xattr) + namelen + 1 + value_len;
+
+ /* compare with the size of current buffer */
+ if (new_size > ea_buf.size) {
+ /*
+ * We need to reallocate more space for merged ea list
+ */
+ ea_release(&ea_buf);
+ xattr_size = ea_get(parent, inode, &ea_buf, new_size);
+ if (xattr_size < 0) {
+ ret = xattr_size;
+ goto out;
+ }
+ goto again;
+ }
+
+ /* remove the old ea of the same name */
+ if (found) {
+ length = (char *)END_XATTR(ealist,xattr_size) - (char *)next_ea;
+ if (length > 0)
+ memmove(old_ea,next_ea,length);
+ xattr_size -= old_ea_size;
+ }
+ /* add new EA to the end */
+ if (value && value_len) {
+ ea = (struct jffs2_xattr *)((char *)ealist + xattr_size);
+ ea->namelen = namelen;
+ ea->valuelen = value_len;
+ memcpy(ea->name, name, namelen);
+ ea->name[namelen] = 0;
+ if (value_len)
+ memcpy(ea->name + namelen + 1, value, value_len);
+ xattr_size += JFFS2_XATTR_SIZE(ea);
+ }
+ /* DEGUG*/
+ if (new_size != xattr_size) {
+ printk(KERN_ERR"jffs2_setxattr: xattr_size = %d, new_size = %d\n", xattr_size, new_size);
+ ret = -EINVAL;
+ goto release;
+ }
+ if (new_size == sizeof(struct jffs2_xattr_list))
+ new_size = 0;
+
+ ret = ea_put(parent, inode, &ea_buf, new_size);
+ goto out;
+ release:
+ ea_release(&ea_buf);
+ out:
+ //up_write(&JFFS2_INODE_INFO(inode)->xattr_sem);
+ return ret;
+}
+
+ssize_t jffs2_listxattr(struct dentry *dentry, char *data, size_t buf_size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct dentry *parent;
+ char *buffer;
+ ssize_t size = 0;
+ int xattr_size;
+ struct jffs2_xattr_list *ealist;
+ struct jffs2_xattr *ea;
+ struct xattr_buffer ea_buf;
+
+ memset(data, 0, buf_size);
+ //down_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+ parent = dentry->d_parent;
+ xattr_size = ea_get(parent, inode, &ea_buf, 0);
+ if (xattr_size < 0) {
+ size = xattr_size;
+ goto out;
+ }
+ if (xattr_size == 0) {
+ goto release;
+ }
+
+ ealist = (struct jffs2_xattr_list *)ea_buf.xattr;
+
+ for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist, xattr_size); ea = NEXT_XATTR(ea))
+ size += ea->namelen +1;
+
+ if (!data)
+ goto release;
+
+ if (size > buf_size) {
+ size = -ERANGE;
+ goto release;
+ }
+ buffer = data;
+ for (ea = FIRST_XATTR(ealist); ea < END_XATTR(ealist, xattr_size); ea = NEXT_XATTR(ea)) {
+ memcpy(buffer, ea->name, ea->namelen);
+ buffer[ea->namelen] = '\\';
+ buffer += ea->namelen +1;
+ }
+ release:
+ ea_release(&ea_buf);
+ out:
+// up_read(&JFFS2_INODE_INFO(inode)->xattr_sem);
+ return size;
+}
+
+int jffs2_removexattr(struct dentry *dentry, const char *name)
+{
+ return jffs2_setxattr(dentry, name, NULL, 0, XATTR_REPLACE);
+}
diff -uNr linux-2.6.10.mxc/fs/Kconfig linux-2.6.10.jffs2/fs/Kconfig
--- linux-2.6.10.mxc/fs/Kconfig 2005-08-19 15:40:26.000000000 +0800
+++ linux-2.6.10.jffs2/fs/Kconfig 2005-08-19 15:50:52.000000000 +0800
@@ -1201,6 +1201,12 @@
Further information on the design and implementation of JFFS2 is
available at <http://sources.redhat.com/jffs2/>.
+config JFFS2_FS_XATTR
+ bool "JFFS2 extended attributes"
+ depends on JFFS2_FS
+ help
+ JFFS2 extended attributes
+
config JFFS2_FS_DEBUG
int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
depends on JFFS2_FS
diff -uNr linux-2.6.10.mxc/include/linux/jffs2_xattr.h linux-2.6.10.jffs2/include/linux/jffs2_xattr.h
--- linux-2.6.10.mxc/include/linux/jffs2_xattr.h 1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.10.jffs2/include/linux/jffs2_xattr.h 2005-08-19 16:20:18.000000000 +0800
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright 2005 Motorola, Inc. All Rights Reserved.
+ *
+ * Created by Ma yun <yunma@sc.mcel.mot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _JFFS2_XATTR
+#define _JFFS2_XATTR
+
+/* jffs2_xattr describe the on-disk format of the extended attributes.
+ *
+ */
+struct jffs2_xattr {
+ uint8_t namelen; /* Length of name */
+ uint8_t valuelen; /* Length of value */
+ char name[0]; /* Attribute name (include null-terminator)*/
+ /* Attribute Valude immediately follows name */
+}__attribute__((packed));
+
+struct jffs2_xattr_list {
+ struct jffs2_xattr xattr[0]; /* EAs list */
+}__attribute__((packed));
+
+
+/*
+ * Some macros for dealing with variable length EA lists.
+ */
+#define JFFS2_XATTR_SIZE(xattr) \
+ (sizeof(struct jffs2_xattr) + (xattr)->namelen + 1 + \
+ (xattr)->valuelen)
+#define NEXT_XATTR(xattr) \
+ ((struct jffs2_xattr *)(((char *)(xattr)) + (JFFS2_XATTR_SIZE(xattr))))
+#define FIRST_XATTR(xattr_list) \
+ ((xattr_list)->xattr)
+#define END_XATTR(xattr_list,size) \
+ ((struct jffs2_xattr *)(((char *)(xattr_list)) + size))
+
+extern int jffs2_setxattr(struct dentry *, const char *, const void *, size_t, int);
+extern ssize_t jffs2_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
+extern int jffs2_removexattr(struct dentry *, const char *);
+
+#endif
+
next reply other threads:[~2005-08-22 4:57 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-08-22 4:41 ÂíÔÆ [this message]
-- strict thread matches above, loose matches on Subject: below --
2005-08-23 3:24 [PATCH] XATTR support in JFFS2 Ma Yun
2005-08-23 12:39 ` Jörn Engel
2005-08-24 11:08 Ma Yun
2005-08-24 16:34 ` Jörn Engel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=324685678.22043@bit.edu.cn \
--to=sx_yunma@bit.edu.cn \
--cc=linux-mtd@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.