[Yaffs] xattr for yaffs2 to use SELinux on Android

トップ ページ
添付ファイル:
Eメールのメッセージ
+ (text/plain)
このメッセージを削除
このメッセージに返信
著者: Yuichi Nakamura
日付:  
To: android-developers
CC: yaffs
題目: [Yaffs] xattr for yaffs2 to use SELinux on Android
Hi.

To port SELinux to Android on emulator,
we are working xattr support for yaffs2.

We have primitive code for xattr for yaffs2, as shown at the last of this message.
xattr is implemented as hidden files like reiserfs.
For example, selinux's xattr for a file is stored in following file.
...xattr/<Oid of a file>/security.selinux

I think there are many limitations and bugs,
so I want to improve this patch.
Do you have any comments, suggestions?
Or, anyone working for better implementation?

Following is a patch, it is based on yaffs2 in Android qemu kernel.


diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
index 382ee61..8ad7879 100644
--- a/fs/yaffs2/Makefile
+++ b/fs/yaffs2/Makefile
@@ -7,4 +7,4 @@ obj-$(CONFIG_YAFFS_FS) += yaffs.o
 yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
 yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
 yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
-yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
+yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o yaffs_xattr.o
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index e81a3db..00ae796 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -13,6 +13,8 @@
  * Michael Fischer for finding the problem with inode inconsistency.
  * Some code bodily lifted from JFFS
  *
+ * xattr Support: Hitachi Software Engineering Co., Ltd.
+ *                Yuichi Nakamura <>
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -51,6 +53,8 @@ extern const char *yaffs_guts_c_version;
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/mount.h>
+#include <linux/security.h>


#include "asm/div64.h"

@@ -100,6 +104,7 @@ extern const char *yaffs_guts_c_version;
#include "yaffs_mtdif.h"
#include "yaffs_mtdif1.h"
#include "yaffs_mtdif2.h"
+#include "yaffs_xattr.h"

unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
@@ -231,6 +236,8 @@ static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
#endif

+static void yaffs_kill_sb(struct super_block *sb);
+
 static struct address_space_operations yaffs_file_address_operations = {
     .readpage = yaffs_readpage,
     .writepage = yaffs_writepage,
@@ -279,13 +286,17 @@ static struct file_operations yaffs_file_operations = {
 #endif


 static struct inode_operations yaffs_file_inode_operations = {
-    .setattr = yaffs_setattr,
+     .getxattr = yaffs_getxattr,
+     .setxattr = yaffs_setxattr,
+    .setattr = yaffs_setattr,
 };


 static struct inode_operations yaffs_symlink_inode_operations = {
     .readlink = yaffs_readlink,
     .follow_link = yaffs_follow_link,
     .setattr = yaffs_setattr,
+    .getxattr = yaffs_getxattr,
+    .setxattr = yaffs_setxattr,
 };


 static struct inode_operations yaffs_dir_inode_operations = {
@@ -299,6 +310,8 @@ static struct inode_operations yaffs_dir_inode_operations = {
     .mknod = yaffs_mknod,
     .rename = yaffs_rename,
     .setattr = yaffs_setattr,
+    .getxattr = yaffs_getxattr,
+    .setxattr = yaffs_setxattr,
 };


 static struct file_operations yaffs_dir_operations = {
@@ -1012,16 +1025,29 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
     }


     ylist_for_each(i, &obj->variant.directoryVariant.children) {
+        struct super_block *sb;
         curoffs++;
         if (curoffs >= offset) {
             l = ylist_entry(i, yaffs_Object, siblings);
-
+            /*hide ...xattr dir*/
+            if (l) {
+              sb = (struct super_block *) (l->myDev->superBlock);
+              if (l->objectId == 
+                  yaffs_DentryToObject(yaffs_SuperToDevice(sb)->xaroot)->objectId) {
+                
+                offset++;
+                f->f_pos++;
+                continue;
+              }
+            }
             yaffs_GetObjectName(l, name,
                         YAFFS_MAX_NAME_LENGTH + 1);
             T(YAFFS_TRACE_OS,
               (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
                yaffs_GetObjectInode(l)));


+        
+
             if (filldir(dirent,
                     name,
                     strlen(name),
@@ -1045,6 +1071,8 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
     return 0;
 }


+
+
/*
* File creation. Allocate an inode, and we're done..
*/
@@ -1127,7 +1155,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,

     if (obj) {
         inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
-        d_instantiate(dentry, inode);
+        d_instantiate(dentry, inode);    
         T(YAFFS_TRACE_OS,
           (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
            obj->objectId, atomic_read(&inode->i_count)));
@@ -1141,11 +1169,34 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
     return error;
 }


+/*This is necessary to assign types to newly created files/dirs*/
+static int yaffs_init_security(struct inode *inode, struct inode *dir) {
+    
+    int err;
+    size_t len;
+    void *value;
+    char *name;
+    
+    err = security_inode_init_security(inode, dir, &name, &value, &len);
+    if (err) {
+    if (err == -EOPNOTSUPP)
+        return 0;
+    return err;
+    }
+    err = yaffs_xattr_set(inode, "security.selinux", value, len, 0);
+    kfree(name);
+    kfree(value);
+    return err;    
+}
+
 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
     int retVal;
     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
     retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+    if(retVal == 0) {    
+        yaffs_init_security(dentry->d_inode, dir);
+    }
 #if 0
     /* attempt to fix dir bug - didn't work */
     if (!retVal) {
@@ -1155,6 +1206,21 @@ static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
     return retVal;
 }


+/*mkdir directories for xattr.
+ i.e. mkdir under ...xattr
+*/
+int yaffs_mkdir_xattr(struct inode *dir, struct dentry *dentry, int mode) {
+    int retVal;
+    retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+
+    return retVal;
+}
+int yaffs_create_xattr(struct inode *dir, struct dentry *dentry, int mode) {
+    return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
             struct nameidata *n)
@@ -1163,7 +1229,12 @@ static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
 #endif
 {
     T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
-    return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+    int ret;
+    ret = yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+    if (ret == 0) {
+        yaffs_init_security(dentry->d_inode, dir);
+    }
+    return ret;
 }


static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
@@ -1695,6 +1766,7 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str)

     return error;
 }
+int yaffs_xattr_init(struct super_block *s, int mount_flags);


 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
                              struct super_block *sb,
@@ -1987,6 +2059,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
     }
     sb->s_root = root;
     sb->s_dirt = !dev->isCheckpointed;
+    yaffs_xattr_init(sb, sb->s_flags);
     T(YAFFS_TRACE_ALWAYS,
       ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));


@@ -2008,8 +2081,11 @@ static int yaffs_read_super(struct file_system_type *fs,
                 void *data, struct vfsmount *mnt)
 {


-    return get_sb_bdev(fs, flags, dev_name, data,
+    int ret;
+    ret = get_sb_bdev(fs, flags, dev_name, data,
                yaffs_internal_read_super_mtd, mnt);
+    yaffs_SuperToDevice(mnt -> mnt_sb) -> mnt = mntget(mnt);
+    return ret;
 }
 #else
 static struct super_block *yaffs_read_super(struct file_system_type *fs,
@@ -2026,7 +2102,7 @@ static struct file_system_type yaffs_fs_type = {
     .owner = THIS_MODULE,
     .name = "yaffs",
     .get_sb = yaffs_read_super,
-    .kill_sb = kill_block_super,
+    .kill_sb = yaffs_kill_sb,
     .fs_flags = FS_REQUIRES_DEV,
 };
 #else
@@ -2055,8 +2131,11 @@ static int yaffs2_read_super(struct file_system_type *fs,
             int flags, const char *dev_name, void *data,
             struct vfsmount *mnt)
 {
-    return get_sb_bdev(fs, flags, dev_name, data,
+    int ret;
+    ret = get_sb_bdev(fs, flags, dev_name, data,
             yaffs2_internal_read_super_mtd, mnt);
+    yaffs_SuperToDevice(mnt -> mnt_sb) -> mnt = mntget(mnt);
+    return ret;
 }
 #else
 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
@@ -2069,11 +2148,26 @@ static struct super_block *yaffs2_read_super(struct file_system_type *fs,
 }
 #endif


+static void yaffs_kill_sb(struct super_block *sb) {
+    yaffs_Device *dev = yaffs_SuperToDevice(sb);
+    
+    if(dev->xaroot) {
+        d_invalidate(dev->xaroot);
+        dput(dev->xaroot);
+        dev->xaroot = NULL;
+    }
+    if(dev->mnt) {
+        mntput(dev->mnt);
+        dev->mnt = NULL;
+    }
+    kill_block_super(sb);
+}
+
 static struct file_system_type yaffs2_fs_type = {
     .owner = THIS_MODULE,
     .name = "yaffs2",
     .get_sb = yaffs2_read_super,
-    .kill_sb = kill_block_super,
+    .kill_sb = yaffs_kill_sb,
     .fs_flags = FS_REQUIRES_DEV,
 };
 #else
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index fd32c5b..a77cf8e 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -731,6 +731,8 @@ struct yaffs_DeviceStruct {
     /* Special directories */
     yaffs_Object *rootDir;
     yaffs_Object *lostNFoundDir;
+    struct dentry *xaroot;
+    struct vfsmount *mnt;


     /* Buffer areas for storing data to recover from write failures TODO
      *      __u8            bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
diff --git a/fs/yaffs2/yaffs_xattr.c b/fs/yaffs2/yaffs_xattr.c
new file mode 100644
index 0000000..6a7c253
--- /dev/null
+++ b/fs/yaffs2/yaffs_xattr.c
@@ -0,0 +1,475 @@
+/*
+  xattr implementation for yaffs2
+  By Hitachi Software Engineering Co., Ltd.
+  Yuichi Nakamura <>
+  Many codes are borrowed from reiserfs.  
+  Attention:
+  This code is experimental and contatins many limitations and bugs.
+  Known issues:
+    - xattr for only security.selinux is supported
+    - may not thread safe
+    - ...xattr dir is not actually hidden. ...xattr is hidden from readdir, 
+      but you can cd to ...xattr and see files under ...xattr.
+*/
+
+#include "yaffs_xattr.h"
+#include "yaffs_guts.h"
+#include <linux/namei.h>
+#include <linux/xattr.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/pagemap.h>
+#include <linux/dcache.h>
+#include <linux/errno.h>
+#include <linux/mount.h>
+
+#define FL_READONLY 128
+#define XATTR_ROOT_NAME "...xattr"
+
+#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
+#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
+
+int yaffs_xattr_set(struct inode *inode, const char *name, const void *buffer,
+            size_t buffer_size, int flags);
+int yaffs_mkdir_xattr(struct inode *dir, struct dentry *dentry, int mode);
+int yaffs_create_xattr(struct inode *dir, struct dentry *dentry, int mode);
+
+static struct dentry *get_xa_root(struct super_block *s) {
+    struct dentry *xaroot = NULL;
+    xaroot = dget(yaffs_SuperToDevice(s)->xaroot);
+    
+    if(!xaroot) {
+    return NULL;
+    }
+    
+    return xaroot;    
+}
+
+static struct dentry *open_xa_dir(const struct inode *inode, int flags) {
+    struct dentry *xaroot, *xadir;
+    char namebuf[17];
+    yaffs_Object * in;
+    
+    xaroot = get_xa_root(inode->i_sb);
+    if (IS_ERR(xaroot)) {
+    return xaroot;
+    } else if (!xaroot) {
+    return ERR_PTR(-ENODATA);
+    }
+    
+    in = yaffs_InodeToObject(inode);
+    snprintf(namebuf, sizeof(namebuf), "%X", le32_to_cpu(in->objectId));
+
+    xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf));
+    if (IS_ERR(xadir)) {
+    dput(xaroot);
+    return xadir;
+    } 
+    if (xadir->d_inode == NULL) {
+    int err;
+    if (flags == 0 || flags & XATTR_CREATE) {
+        /* Although there is nothing else trying to create this directory,
+         * another directory with the same hash may be created, so we need
+         * to protect against that */
+        err = yaffs_mkdir_xattr(xaroot->d_inode, xadir, 0755);
+        if (err) {
+        dput(xaroot);
+        dput(xadir);
+        return ERR_PTR(err);
+        }
+    }
+    if (!xadir->d_inode) {
+        dput(xaroot);
+        dput(xadir);
+        return ERR_PTR(-ENODATA);
+    }
+    }
+
+    dput(xaroot);
+    return xadir;
+}
+
+
+/* Returns a dentry corresponding to a specific extended attribute file
+ * for the inode. If flags allow, the file is created. Otherwise, a
+ * valid or negative dentry, or an error is returned. 
+ * Same as function in reiserfs/xattr.c               */
+static struct dentry *get_xa_file_dentry(const struct inode *inode,
+                     const char *name, int flags)
+{
+    struct dentry *xadir, *xafile;
+    int err = 0;
+    
+    xadir = open_xa_dir(inode, flags);
+    if (IS_ERR(xadir)) {
+    return ERR_PTR(PTR_ERR(xadir));
+    } else if (xadir && !xadir->d_inode) {
+    dput(xadir);
+    return ERR_PTR(-ENODATA);
+    }
+    
+    xafile = lookup_one_len(name, xadir, strlen(name));
+
+    if (IS_ERR(xafile)) {
+    dput(xadir);
+    return ERR_PTR(PTR_ERR(xafile));
+    }
+    
+    if (xafile->d_inode) {    /* file exists */
+    ;
+    } else {
+    err = yaffs_create_xattr(xadir->d_inode, xafile,
+                 0755 | S_IFREG);
+    if (err) {
+        dput(xafile);
+        goto out;
+    }
+    }
+    
+  out:
+    dput(xadir);
+    if (err)
+    xafile = ERR_PTR(err);
+    return xafile;
+}
+
+
+/* Opens a file pointer to the attribute associated with inode */
+static struct dentry *open_xa_file(const struct inode *inode, const char *name,
+                 int flags)
+{
+    struct dentry *xafile;
+
+    xafile = get_xa_file_dentry(inode, name, flags);
+    if (IS_ERR(xafile)) {
+        return ERR_PTR(PTR_ERR(xafile));
+    }
+    else if (!xafile->d_inode) {
+        dput(xafile);
+        return ERR_PTR(-ENODATA);
+    }
+    return xafile;
+
+}
+
+/* Opens a file pointer to the attribute associated with inode */
+static struct file *open_xa_filep(const struct inode *inode, const char *name,
+                 int flags)
+{
+    struct dentry *xafile;
+    struct file *fp;
+    struct super_block *sb;
+    struct vfsmount *mnt;
+
+    xafile = get_xa_file_dentry(inode, name, flags);
+    if (IS_ERR(xafile))
+        return ERR_PTR(PTR_ERR(xafile));
+    else if (!xafile->d_inode) {
+        dput(xafile);
+        return ERR_PTR(-ENODATA);
+    }
+    sb = xafile->d_sb;
+    
+    mnt = mntget(yaffs_SuperToDevice(sb)->mnt);
+    /*mnt is mntputted in fput(fp)*/
+    fp = dentry_open(xafile, mnt, O_RDWR);
+    /* dentry_open dputs the dentry if it fails */
+
+    return fp;
+}
+
+
+
+ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buffer,
+          size_t size)
+{    
+    yaffs_Object * in;
+    struct dentry *xafile;
+    int ret = 0;
+    int xasize;
+    
+    xafile = open_xa_file(dentry->d_inode, name, FL_READONLY);
+    if(IS_ERR(xafile)) {
+    return PTR_ERR(xafile);
+    }
+    in = yaffs_InodeToObject(xafile->d_inode);
+ 
+    xasize = xafile->d_inode->i_size;
+    if (buffer == NULL) {
+    ret = xasize;
+    goto out;
+    }
+    if (size < xasize) {
+    ret = -ERANGE;
+    goto out;
+    }
+    ret = yaffs_ReadDataFromFile(in, buffer, 0, xasize);
+out:
+    dput(xafile);
+    return ret;
+}
+
+int yaffs_setxattr(struct dentry *dentry, const char *name, const void *value,
+          size_t size, int flags)
+{
+    struct dentry *xafile;
+    struct inode *node;
+
+    return yaffs_xattr_set(dentry->d_inode, name, value, size, flags);
+
+}
+
+static int
+__yaffs_xattr_del(struct dentry *xadir, const char *name, int namelen)
+{
+    struct dentry *dentry;
+    struct inode *dir = xadir->d_inode;
+    int err = 0;
+
+    dentry = lookup_one_len(name, xadir, namelen);
+    if (IS_ERR(dentry)) {
+        err = PTR_ERR(dentry);
+        goto out;
+    } else if (!dentry->d_inode) {
+        err = -ENODATA;
+        goto out_file;
+    }
+
+    /* Skip directories.. */
+    if (S_ISDIR(dentry->d_inode->i_mode))
+        goto out_file;
+
+    err = dir->i_op->unlink(dir, dentry);
+    if (!err)
+        d_delete(dentry);
+
+      out_file:
+    dput(dentry);
+
+      out:
+    return err;
+}
+
+
+int yaffs_xattr_del(struct inode *inode, const char *name)
+{
+    struct dentry *dir;
+    int err;
+
+    if (IS_RDONLY(inode))
+        return -EROFS;
+
+    dir = open_xa_dir(inode, FL_READONLY);
+    if (IS_ERR(dir)) {
+        err = PTR_ERR(dir);
+        goto out;
+    }
+
+    err = __yaffs_xattr_del(dir, name, strlen(name));
+    dput(dir);
+
+    if (!err) {
+        inode->i_ctime = CURRENT_TIME_SEC;
+        mark_inode_dirty(inode);
+    }
+
+      out:
+    return err;
+}
+/* Internal operations on file data */
+static inline void yaffs_put_page(struct page *page)
+{
+    kunmap(page);
+    page_cache_release(page);
+}
+
+static struct page *yaffs_get_page(struct file *fp, struct inode *dir, unsigned long n)
+{
+    struct address_space *mapping = dir->i_mapping;
+    struct page *page;
+
+    page = read_mapping_page(mapping, n, fp);
+    if (!IS_ERR(page)) {
+        wait_on_page_locked(page);
+        kmap(page);
+
+        if (!PageUptodate(page)) {
+            goto fail;
+        }
+    
+        if (PageError(page)) {
+            goto fail;
+        }
+    }
+
+    return page;
+
+      fail:
+    yaffs_put_page(page);
+
+    return ERR_PTR(-EIO);
+}
+
+
+int
+yaffs_xattr_set(struct inode *inode, const char *name, const void *buffer,
+        size_t buffer_size, int flags)
+{
+    int err = 0;
+    struct file *fp;
+    struct page *page;
+    char *data;
+    struct address_space *mapping;
+    size_t file_pos = 0;
+    size_t buffer_pos = 0;
+    struct inode *xinode;
+    struct iattr newattrs;
+    __u32 xahash = 0;
+
+    if (IS_RDONLY(inode))
+        return -EROFS;
+
+    if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+        return -EPERM;
+
+      open_file:
+    fp = open_xa_filep(inode, name, flags);
+    if (IS_ERR(fp)) {
+        err = PTR_ERR(fp);
+        goto out;
+    }
+
+    xinode = fp->f_dentry->d_inode;
+
+    /* we need to copy it off.. */
+    if (xinode->i_nlink > 1) {
+        fput(fp);
+        err = yaffs_xattr_del(inode, name);
+        if (err < 0)
+            goto out;
+        /* We just killed the old one, we're not replacing anymore */
+        if (flags & XATTR_REPLACE)
+            flags &= ~XATTR_REPLACE;
+        goto open_file;
+    }
+
+    /* Resize it so we're ok to write there */
+    newattrs.ia_size = buffer_size;
+    newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+    mutex_lock(&xinode->i_mutex);
+    err = notify_change(fp->f_dentry, &newattrs);
+    if (err)
+        goto out_filp;
+
+    mapping = xinode->i_mapping;
+    while (buffer_pos < buffer_size || buffer_pos == 0) {
+        size_t chunk;
+        size_t skip = 0;
+        size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));
+        if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)
+            chunk = PAGE_CACHE_SIZE;
+        else
+            chunk = buffer_size - buffer_pos;
+
+        page = yaffs_get_page(fp, xinode, file_pos >> PAGE_CACHE_SHIFT);
+        if (IS_ERR(page)) {
+            err = PTR_ERR(page);
+            goto out_filp;
+        }
+
+        lock_page(page);
+        data = page_address(page);
+
+        if (file_pos == 0) {
+            if (chunk + skip > PAGE_CACHE_SIZE)
+            chunk = PAGE_CACHE_SIZE - skip;
+        }
+
+        err = mapping->a_ops->prepare_write(fp, page, page_offset,
+                            page_offset + chunk + skip);
+        if (!err) {
+            if (buffer)
+                memcpy(data + skip, buffer + buffer_pos, chunk);
+            err =
+                mapping->a_ops->commit_write(fp, page, page_offset,
+                             page_offset + chunk +
+                             skip);
+        }
+        unlock_page(page);
+        yaffs_put_page(page);
+        buffer_pos += chunk;
+        file_pos += chunk;
+        skip = 0;
+        if (err || buffer_size == 0 || !buffer)
+            break;
+    }
+
+    /* We can't mark the inode dirty if it's not hashed. This is the case
+     * when we're inheriting the default ACL. If we dirty it, the inode
+     * gets marked dirty, but won't (ever) make it onto the dirty list until
+     * it's synced explicitly to clear I_DIRTY. This is bad. */
+    if (!hlist_unhashed(&inode->i_hash)) {
+        inode->i_ctime = CURRENT_TIME_SEC;
+        mark_inode_dirty(inode);
+    }
+
+      out_filp:
+    mutex_unlock(&xinode->i_mutex);
+    fput(fp);
+
+      out:
+    return err;
+}
+
+
+
+/* We need to take a copy of the mount flags since things like
+ * MS_RDONLY don't get set until *after* we're called.
+ * mount_flags != mount_options */
+int yaffs_xattr_init(struct super_block *s, int mount_flags)
+{
+    int err = 0;
+
+    if (!yaffs_SuperToDevice(s)->xaroot) {
+        struct dentry *dentry;
+        dentry = lookup_one_len(XATTR_ROOT_NAME, s->s_root,
+                    strlen(XATTR_ROOT_NAME));
+        if (!IS_ERR(dentry)) {
+            if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
+                struct inode *inode = dentry->d_parent->d_inode;    
+                mutex_lock(&inode->i_mutex);
+                err = yaffs_mkdir_xattr(inode, dentry, 0755);
+                mutex_unlock(&inode->i_mutex);
+                if (err) {
+                    dput(dentry);
+                    dentry = NULL;
+                }
+
+                if (dentry && dentry->d_inode)
+                    printk("Created %s on yaffs - reserved for "
+                       "xattr storage.",
+                       XATTR_ROOT_NAME);
+
+            } else if (!dentry->d_inode) {
+                dput(dentry);
+                dentry = NULL;
+            }
+        } else
+            err = PTR_ERR(dentry);
+
+        if (!err && dentry) {
+            yaffs_SuperToDevice(s)->xaroot = dentry;
+        } else if (!(mount_flags & MS_RDONLY)) {    /* xattrs are unavailable */
+            /* If we're read-only it just means that the dir hasn't been
+             * created. Not an error -- just no xattrs on the fs. We'll
+             * check again if we go read-write */
+            printk("xattrs/ACLs enabled and couldn't "
+               "find/create .reiserfs_priv. Failing mount.");
+            err = -EOPNOTSUPP;
+        }
+    }
+
+    return err;
+}
diff --git a/fs/yaffs2/yaffs_xattr.h b/fs/yaffs2/yaffs_xattr.h
new file mode 100644
index 0000000..f06d1c9
--- /dev/null
+++ b/fs/yaffs2/yaffs_xattr.h
@@ -0,0 +1,13 @@
+#ifndef __YAFFS_XATTR_H__
+#define __YAFFS_XATTR_H__
+
+#include <linux/fs.h>
+
+ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buffer,
+           size_t size);
+int yaffs_setxattr(struct dentry *dentry, const char *name, const void *value,
+           size_t size, int flags);
+int
+yaffs_xattr_set(struct inode *inode, const char *name, const void *buffer,
+        size_t buffer_size, int flags);
+#endif




--
Yuichi Nakamura
Hitachi Software Engineering Co., Ltd.
SELinux Policy Editor: http://seedit.sourceforge.net