[PATCH 11/16 v5] pramfs: ACL management

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

ACL operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/acl.c linux-2.6.36/fs/pramfs/acl.c
--- linux-2.6.36-orig/fs/pramfs/acl.c   1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/acl.c2010-11-27 14:36:01.0 +0100
@@ -0,0 +1,433 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * POSIX ACL operations
+ *
+ * Copyright 2010 Marco Stornelli 
+ *
+ * based on fs/ext2/acl.c with the following copyright:
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, 
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * Load ACL information from filesystem.
+ */
+static struct posix_acl *pram_acl_load(const void *value, size_t size)
+{
+   const char *end = (char *)value + size;
+   int n, count;
+   struct posix_acl *acl;
+
+   if (!value)
+   return NULL;
+   if (size < sizeof(struct pram_acl_header))
+return ERR_PTR(-EINVAL);
+   if (((struct pram_acl_header *)value)->a_version !=
+   cpu_to_be32(PRAM_ACL_VERSION))
+   return ERR_PTR(-EINVAL);
+   value = (char *)value + sizeof(struct pram_acl_header);
+   count = pram_acl_count(size);
+   if (count < 0)
+   return ERR_PTR(-EINVAL);
+   if (count == 0)
+   return NULL;
+   acl = posix_acl_alloc(count, GFP_KERNEL);
+   if (!acl)
+   return ERR_PTR(-ENOMEM);
+   for (n = 0; n < count; n++) {
+   struct pram_acl_entry *entry = (struct pram_acl_entry *)value;
+   if ((char *)value + sizeof(struct pram_acl_entry_short) > end)
+   goto fail;
+   acl->a_entries[n].e_tag  = be16_to_cpu(entry->e_tag);
+   acl->a_entries[n].e_perm = be16_to_cpu(entry->e_perm);
+   switch (acl->a_entries[n].e_tag) {
+   case ACL_USER_OBJ:
+   case ACL_GROUP_OBJ:
+   case ACL_MASK:
+   case ACL_OTHER:
+   value = (char *)value +
+   sizeof(struct pram_acl_entry_short);
+   acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
+   break;
+   case ACL_USER:
+   case ACL_GROUP:
+   value = (char *)value + sizeof(struct pram_acl_entry);
+   if ((char *)value > end)
+   goto fail;
+   acl->a_entries[n].e_id =
+   be32_to_cpu(entry->e_id);
+   break;
+   default:
+   goto fail;
+   }
+   }
+   if (value != end)
+   goto fail;
+   return acl;
+
+fail:
+   posix_acl_release(acl);
+   return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Save ACL information into the filesystem.
+ */
+static void *pram_acl_save(const struct posix_acl *acl, size_t *size)
+{
+   struct pram_acl_header *ext_acl;
+   char *e;
+   size_t n;
+
+   *size = pram_acl_size(acl->a_count);
+   ext_acl = kmalloc(sizeof(struct pram_acl_header) + acl->a_count *
+   sizeof(struct pram_acl_entry), GFP_KERNEL);
+   if (!ext_acl)
+   return ERR_PTR(-ENOMEM);
+   ext_acl->a_version = cpu_to_be32(PRAM_ACL_VERSION);
+   e = (char *)ext_acl + sizeof(struct pram_acl_header);
+   for (n = 0; n < acl->a_count; n++) {
+   struct pram_acl_entry *entry = (struct pram_acl_entry *)e;
+   entry->e_tag  = cpu_to_be16(acl->a_entries[n].e_tag);
+   entry->e_perm = cpu_to_be16(acl->a_entries[n].e_perm);
+   switch (acl->a_entries[n].e_tag) {
+   case ACL_USER:
+   case ACL_GROUP:
+   entry->e_id =
+   cpu_to_be32(acl->a_entries[n].e_id);
+   e += sizeof(struct pram_acl_entry);
+   break;
+   case ACL_USER_OBJ:
+   case ACL_GROUP_OBJ:
+   case ACL_MASK:
+   case ACL_OTHER:
+   e += sizeof(struct pram_acl_entry_short);
+   break;
+   default:
+   goto fail;
+   }
+   }
+   return (char *)ext_acl;
+
+fail:
+   kfree(ext_acl);
+   return ERR_PTR(-EINVAL);
+}
+
+/*
+ * inode->i_mutex: don't care
+ */
+static struct posix_acl *pram_get_acl(struct inode *inode, int type)
+{
+   int name_index;
+   char *value = NULL;
+   struct posix_acl *acl;
+   int retval;
+
+   if (!test_opt(inode->i_sb, POSIX_ACL))
+   return NULL;
+
+   acl = get_cached_acl(inode, type);
+   if (a

[PATCH 06/16 v5] pramfs: inode operations for dirs

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Inode operations for directories.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/namei.c linux-2.6.36/fs/pramfs/namei.c
--- linux-2.6.36-orig/fs/pramfs/namei.c 1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/namei.c  2010-11-28 10:35:12.0 +0100
@@ -0,0 +1,366 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Inode operations for directories.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include 
+#include 
+#include "pram.h"
+#include "acl.h"
+#include "xattr.h"
+#include "xip.h"
+
+/*
+ * Couple of helper functions - make the code slightly cleaner.
+ */
+
+static inline void pram_inc_count(struct inode *inode)
+{
+   inode->i_nlink++;
+   pram_write_inode(inode, 0);
+}
+
+static inline void pram_dec_count(struct inode *inode)
+{
+   if (inode->i_nlink) {
+   inode->i_nlink--;
+   pram_write_inode(inode, 0);
+   }
+}
+
+static inline int pram_add_nondir(struct inode *dir,
+  struct dentry *dentry,
+  struct inode *inode)
+{
+   int err = pram_add_link(dentry, inode);
+   if (!err) {
+   d_instantiate(dentry, inode);
+   unlock_new_inode(inode);
+   return 0;
+   }
+   pram_dec_count(inode);
+   unlock_new_inode(inode);
+   iput(inode);
+   return err;
+}
+
+/*
+ * Methods themselves.
+ */
+
+static ino_t
+pram_inode_by_name(struct inode *dir,
+  struct dentry *dentry)
+{
+   struct pram_inode *pi;
+   ino_t ino;
+   int namelen;
+
+   pi = pram_get_inode(dir->i_sb, dir->i_ino);
+   ino = be64_to_cpu(pi->i_type.dir.head);
+
+   while (ino) {
+   pi = pram_get_inode(dir->i_sb, ino);
+
+   if (pi->i_links_count) {
+   namelen = strlen(pi->i_d.d_name);
+
+   if (namelen == dentry->d_name.len &&
+   !memcmp(dentry->d_name.name,
+   pi->i_d.d_name, namelen))
+   break;
+   }
+
+   ino = be64_to_cpu(pi->i_d.d_next);
+   }
+
+   return ino;
+}
+
+static struct dentry *
+pram_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+   struct inode *inode = NULL;
+   ino_t ino;
+
+   if (dentry->d_name.len > PRAM_NAME_LEN)
+   return ERR_PTR(-ENAMETOOLONG);
+
+   ino = pram_inode_by_name(dir, dentry);
+   if (ino) {
+   inode = pram_iget(dir->i_sb, ino);
+   if (!inode)
+   return ERR_PTR(-EACCES);
+   }
+
+   d_splice_alias(inode, dentry);
+   return NULL;
+}
+
+
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate().
+ */
+static int pram_create(struct inode *dir, struct dentry *dentry,
+   int mode, struct nameidata *nd)
+{
+   struct inode *inode = pram_new_inode(dir, mode);
+   int err = PTR_ERR(inode);
+   if (!IS_ERR(inode)) {
+   inode->i_op = &pram_file_inode_operations;
+   if (pram_use_xip(inode->i_sb)) {
+   inode->i_mapping->a_ops = &pram_aops_xip;
+   inode->i_fop = &pram_xip_file_operations;
+   } else {
+   inode->i_fop = &pram_file_operations;
+   inode->i_mapping->a_ops = &pram_aops;
+   }
+   err = pram_add_nondir(dir, dentry, inode);
+   }
+   return err;
+}
+
+static int pram_mknod(struct inode *dir, struct dentry *dentry, int mode,
+  dev_t rdev)
+{
+   struct inode *inode = pram_new_inode(dir, mode);
+   int err = PTR_ERR(inode);
+   if (!IS_ERR(inode)) {
+   init_special_inode(inode, mode, rdev);
+   pram_write_inode(inode, 0); /* update rdev */
+   err = pram_add_nondir(dir, dentry, inode);
+   }
+   return err;
+}
+
+static int pram_symlink(struct inode *dir,
+ struct dentry *dentry,
+ const char *symname)
+{
+   struct super_block *sb = dir->i_sb;
+   int err = -ENAMETOOLONG;
+   unsigned len = strlen(symname);
+   struct inode *inode;
+
+   if (len+1 > sb->s_blocksize)
+   goto out;
+
+   inode = pram_new_inode(dir, S_IFLNK | S_IRWXUGO);
+   err = PTR_ERR(inode);
+

[PATCH 08/16 v5] pramfs: headers

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Definitions for the PRAMFS filesystem.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/pram.h linux-2.6.36/fs/pramfs/pram.h
--- linux-2.6.36-orig/fs/pramfs/pram.h  1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/pram.h   2010-12-15 19:23:48.0 +0100
@@ -0,0 +1,229 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Definitions for the PRAMFS filesystem.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __PRAM_H
+#define __PRAM_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "wprotect.h"
+
+/*
+ * Debug code
+ */
+#ifdef pr_fmt
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#endif
+
+#define pram_dbg(s, args...)   pr_debug(s, ## args)
+#define pram_err(sb, s, args...)   pram_error_mng(sb, s, ## args)
+#define pram_warn(s, args...)  pr_warning(s, ## args)
+#define pram_info(s, args...)  pr_info(s, ## args)
+
+/* Function Prototypes */
+extern void pram_error_mng(struct super_block * sb, const char * fmt, ...);
+extern int pram_get_and_update_block(struct inode *inode, sector_t iblock,
+struct buffer_head *bh, int create);
+
+static inline int pram_readpage(struct file *file, struct page *page)
+{
+   return block_read_full_page(page, pram_get_and_update_block);
+}
+
+/* file.c */
+extern ssize_t pram_direct_IO(int rw, struct kiocb *iocb,
+ const struct iovec *iov,
+ loff_t offset, unsigned long nr_segs);
+extern int pram_mmap(struct file *file, struct vm_area_struct *vma);
+
+#define pram_set_bit   ext2_set_bit
+#define pram_clear_bit ext2_clear_bit
+#define pram_find_next_zero_bitext2_find_next_zero_bit
+
+#define clear_opt(o, opt)  (o &= ~PRAM_MOUNT_##opt)
+#define set_opt(o, opt)(o |= PRAM_MOUNT_##opt)
+#define test_opt(sb, opt)  (((struct pram_sb_info 
*)sb->s_fs_info)->s_mount_opt & \
+PRAM_MOUNT_##opt)
+
+/* balloc.c */
+extern void pram_init_bitmap(struct super_block *sb);
+extern void pram_free_block(struct super_block *sb, unsigned long blocknr);
+extern int pram_new_block(struct super_block *sb, unsigned long *blocknr, int 
zero);
+extern unsigned long pram_count_free_blocks(struct super_block *sb);
+
+/* dir.c */
+extern int pram_add_link(struct dentry *dentry, struct inode *inode);
+extern int pram_remove_link(struct inode *inode);
+
+/* namei.c */
+extern struct dentry *pram_get_parent(struct dentry *child);
+
+/* inode.c */
+extern int pram_alloc_blocks(struct inode *inode, int file_blocknr, int num);
+extern u64 pram_find_data_block(struct inode *inode,
+unsigned long file_blocknr);
+
+extern struct inode *pram_iget(struct super_block *sb, unsigned long ino);
+extern void pram_put_inode(struct inode *inode);
+extern void pram_evict_inode(struct inode *inode);
+extern struct inode *pram_new_inode(struct inode *dir, int mode);
+extern int pram_update_inode(struct inode *inode);
+extern int pram_write_inode(struct inode *inode, struct writeback_control 
*wbc);
+extern void pram_dirty_inode(struct inode *inode);
+extern int pram_notify_change(struct dentry *dentry, struct iattr *attr);
+
+
+/* super.c */
+#ifdef CONFIG_PRAMFS_TEST
+extern struct pram_super_block *get_pram_super(void);
+#endif
+extern struct super_block *pram_read_super(struct super_block *sb,
+ void *data,
+ int silent);
+extern int pram_statfs(struct dentry *d, struct kstatfs *buf);
+extern int pram_remount(struct super_block *sb, int *flags, char *data);
+
+/* symlink.c */
+extern int pram_block_symlink(struct inode *inode,
+  const char *symname, int len);
+
+/* Inline functions start here */
+
+static inline int pram_calc_checksum(u8 *data, int n)
+{
+   u16 crc = 0;
+   crc = crc16(~0, (__u8 *)data + sizeof(__be16), n - sizeof(__be16));
+   if (*((__be16 *)data) == cpu_to_be16(crc))
+   return 0;
+   else
+   return 1;
+}
+
+/* If this is part of a read-modify-write of the super block,
+   pram_memunlock_super() before calling! */
+static inline struct pram_super_block *
+pram_get_super(struct super_block *sb)
+{
+   struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+   return (struct pram_super_block *)sbi->virt_addr;
+}
+
+static inline struct pram_super_block *
+pram_get_redund_super(struct super_block *sb)
+{
+   struct pram_sb_i

[PATCH 16/16 v5] pramfs: Makefile and Kconfig

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Makefile and Kconfig.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/Makefile linux-2.6.36/fs/Makefile
--- linux-2.6.36-orig/fs/Makefile   2010-09-13 01:07:37.0 +0200
+++ linux-2.6.36/fs/Makefile2010-09-14 18:49:52.0 +0200
@@ -126,3 +126,4 @@ obj-$(CONFIG_BTRFS_FS)  += btrfs/
 obj-$(CONFIG_GFS2_FS)   += gfs2/
 obj-$(CONFIG_EXOFS_FS)  += exofs/
 obj-$(CONFIG_CEPH_FS)  += ceph/
+obj-$(CONFIG_PRAMFS)   += pramfs/
diff -Nurp linux-2.6.36-orig/fs/Kconfig linux-2.6.36/fs/Kconfig
--- linux-2.6.36-orig/fs/Kconfig2010-09-13 01:07:37.0 +0200
+++ linux-2.6.36/fs/Kconfig 2010-09-14 18:49:52.0 +0200
@@ -13,7 +13,7 @@ source "fs/ext4/Kconfig"
 config FS_XIP
 # execute in place
bool
-   depends on EXT2_FS_XIP
+   depends on EXT2_FS_XIP || PRAMFS_XIP
default y
  source "fs/jbd/Kconfig"
@@ -25,13 +25,14 @@ config FS_MBCACHE
default y if EXT2_FS=y && EXT2_FS_XATTR
default y if EXT3_FS=y && EXT3_FS_XATTR
default y if EXT4_FS=y && EXT4_FS_XATTR
-   default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR
+   default y if PRAMFS=y && PRAMFS_XATTR
+   default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS_XATTR || 
PRAMFS_XATTR
  source "fs/reiserfs/Kconfig"
 source "fs/jfs/Kconfig"
  config FS_POSIX_ACL
-# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4)
+# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4/pramfs)
 #
 # NOTE: you can implement Posix ACLs without these helpers (XFS does).
 #  Never use this symbol for ifdefs.
@@ -189,6 +190,7 @@ source "fs/romfs/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 source "fs/exofs/Kconfig"
+source "fs/pramfs/Kconfig"
  endif # MISC_FILESYSTEMS
 diff -Nurp linux-2.6.36-orig/fs/pramfs/Kconfig linux-2.6.36/fs/pramfs/Kconfig
--- linux-2.6.36-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/Kconfig  2010-12-12 10:42:23.0 +0100
@@ -0,0 +1,72 @@
+config PRAMFS
+   tristate "Persistent and Protected RAM file system support"
+   depends on HAS_IOMEM && EXPERIMENTAL
+   select CRC16
+   help
+  If your system has a block of fast (comparable in access speed to
+  system memory) and non-volatile RAM and you wish to mount a
+  light-weight, full-featured, and space-efficient filesystem over it,
+  say Y here, and read .
+
+  To compile this as a module,  choose M here: the module will be
+  called pramfs.
+
+config PRAMFS_XIP
+   bool "Execute-in-place in PRAMFS"
+   depends on PRAMFS
+   help
+  Say Y here to enable XIP feature of PRAMFS.
+
+config PRAMFS_WRITE_PROTECT
+   bool "PRAMFS write protection"
+   depends on PRAMFS && MMU && HAVE_SET_MEMORY_RO
+   default y
+   help
+  Say Y here to enable the write protect feature of PRAMFS.
+
+config PRAMFS_XATTR
+   bool "PRAMFS extended attributes"
+   depends on PRAMFS
+   help
+ Extended attributes are name:value pairs associated with inodes by
+ the kernel or by users (see the attr(5) manual page, or visit
+  for details).
+
+ If unsure, say N.
+
+config PRAMFS_POSIX_ACL
+   bool "PRAMFS POSIX Access Control Lists"
+   depends on PRAMFS_XATTR
+   select FS_POSIX_ACL
+   help
+ Posix Access Control Lists (ACLs) support permissions for users and
+ groups beyond the owner/group/world scheme.
+
+ To learn more about Access Control Lists, visit the Posix ACLs for
+ Linux website .
+
+ If you don't know what Access Control Lists are, say N.
+
+config PRAMFS_SECURITY
+   bool "PRAMFS Security Labels"
+   depends on PRAMFS_XATTR
+   help
+ Security labels support alternative access control models
+ implemented by security modules like SELinux.  This option
+ enables an extended attribute handler for file security
+ labels in the pram filesystem.
+
+ If you are not using a security module that requires using
+ extended attributes for file security labels, say N.
+
+config PRAMFS_TEST
+   boolean
+   depends on PRAMFS
+
+config PRAMFS_TEST_MODULE
+   tristate "PRAMFS Test"
+   depends on PRAMFS && m
+   select PRAMFS_TEST
+   help
+ Say Y here to build a simple module to test the protection of
+ PRAMFS. The module will be called pramfs_test.
diff -Nurp linux-2.6.36-orig/arch/Kconfig linux-2.6.36/arch/Kconfig
--- linux-2.6.36-orig/arch/Kconfig  2010-10-20 22:30:22.0 +0200
+++ linux-2.6.36/arch/Kconfig   2010-11-01 11:42:26.0 +0100
@@ -83,6 +83,9 @@ config USER_RETURN_NOTIFIER
 config HAVE_IOREMAP_PROT
bool
 +config HAVE_SET_MEMORY_RO
+   bool
+
 config HAVE_KPROBES

[PATCH 14/16 v5] pramfs: memory protection

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Memory write protection.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/wprotect.c 
linux-2.6.36/fs/pramfs/wprotect.c
--- linux-2.6.36-orig/fs/pramfs/wprotect.c  1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/wprotect.c   2010-12-04 11:57:31.0 +0100
@@ -0,0 +1,41 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Write protection for the filesystem pages.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+
+DEFINE_SPINLOCK(writeable_lock);
+
+void pram_writeable(void *vaddr, unsigned long size, int rw)
+{
+   int ret = 0;
+   unsigned long nrpages = size >> PAGE_SHIFT;
+   unsigned long addr = (unsigned long)vaddr;
+
+   /* Page aligned */
+   addr &= PAGE_MASK;
+
+   if (size & (PAGE_SIZE - 1))
+   nrpages++;
+
+   if (rw)
+   ret = set_memory_rw(addr, nrpages);
+   else
+   ret = set_memory_ro(addr, nrpages);
+
+   BUG_ON(ret);
+}
diff -Nurp linux-2.6.36-orig/fs/pramfs/wprotect.h 
linux-2.6.36/fs/pramfs/wprotect.h
--- linux-2.6.36-orig/fs/pramfs/wprotect.h  1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/wprotect.h   2010-12-04 16:45:05.0 +0100
@@ -0,0 +1,149 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Memory protection definitions for the PRAMFS filesystem.
+ *
+ * Copyright 2010 Marco Stornelli 
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __WPROTECT_H
+#define __WPROTECT_H
+
+/* pram_memunlock_super() before calling! */
+static inline void pram_sync_super(struct pram_super_block *ps)
+{
+   u16 crc = 0;
+   ps->s_wtime = cpu_to_be32(get_seconds());
+   ps->s_sum = 0;
+   crc = crc16(~0, (__u8 *)ps + sizeof(__be16), PRAM_SB_SIZE - 
sizeof(__be16));
+   ps->s_sum = cpu_to_be16(crc);
+   /* Keep sync redundant super block */
+   memcpy((void *)ps + PRAM_SB_SIZE, (void *)ps, PRAM_SB_SIZE);
+}
+
+/* pram_memunlock_inode() before calling! */
+static inline void pram_sync_inode(struct pram_inode *pi)
+{
+   u16 crc = 0;
+   pi->i_sum = 0;
+   crc = crc16(~0, (__u8 *)pi + sizeof(__be16), PRAM_INODE_SIZE - 
sizeof(__be16));
+   pi->i_sum = cpu_to_be16(crc);
+}
+
+#ifdef CONFIG_PRAMFS_WRITE_PROTECT
+extern void pram_writeable(void *vaddr, unsigned long size, int rw);
+extern spinlock_t writeable_lock;
+static inline int pram_is_protected(struct super_block *sb)
+{
+   struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+   return sbi->s_mount_opt & PRAM_MOUNT_PROTECT;
+}
+
+static inline void __pram_memunlock_range(void *p, unsigned long len)
+{
+   /* + * NOTE: Ideally we should lock all the kernel to be memory safe
+* and avoid to write in the protected memory,
+* obviously it's not possible, so we only serialize
+* the operations at fs level. We can't disable the interrupts
+* because we could have a deadlock in this path.
+*/
+   spin_lock(&writeable_lock);
+   pram_writeable(p, len, 1);
+}
+
+static inline void __pram_memlock_range(void *p, unsigned long len)
+{
+   pram_writeable(p, len, 0);
+   spin_unlock(&writeable_lock);
+}
+
+static inline void pram_memunlock_range(struct super_block *sb, void *p,
+   unsigned long len)
+{
+   if (pram_is_protected(sb))
+   __pram_memunlock_range(p, len);
+}
+
+static inline void pram_memlock_range(struct super_block *sb, void *p,
+   unsigned long len)
+{
+   if (pram_is_protected(sb))
+   __pram_memlock_range(p, len);
+}
+
+static inline void pram_memunlock_super(struct super_block *sb,
+   struct pram_super_block *ps)
+{
+   if (pram_is_protected(sb))
+   __pram_memunlock_range(ps, PRAM_SB_SIZE);
+}
+
+static inline void pram_memlock_super(struct super_block *sb,
+   struct pram_super_block *ps)
+{
+   pram_sync_super(ps);
+   if (pram_is_protected(sb))
+   __pram_memlock_range(ps, PRAM_SB_SIZE);
+}
+
+static inline void pram_memunlock_inode(struct super_block *sb,
+   struct pram_inode *pi)
+{
+   if (pram_is_protected(sb))
+   __pram_memunlock_range(pi, PRAM_SB_SIZE);
+}
+
+static inline void pram_memlock_inode(struct super_block *sb,
+   

[PATCH 13/16 v5] pramfs: extended attributes block descriptors tree

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Extended attributes block descriptors tree.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/desctree.c 
linux-2.6.36/fs/pramfs/desctree.c
--- linux-2.6.36-orig/fs/pramfs/desctree.c  1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/desctree.c   2010-11-27 11:12:04.0 +0100
@@ -0,0 +1,181 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes block descriptors tree.
+ *
+ * Copyright 2010 Marco Stornelli 
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include "desctree.h"
+#include "pram.h"
+
+/* xblock_desc_init_always()
+ *
+ * These are initializations that need to be done on every
+ * descriptor allocation as the fields are not initialised
+ * by slab allocation.
+ */
+void xblock_desc_init_always(struct pram_xblock_desc *desc)
+{
+   atomic_set(&desc->refcount, 0);
+   desc->blocknr = 0;
+   desc->flags = 0;
+}
+
+/* xblock_desc_init_once()
+ *
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the descriptor, so let the slab aware of that.
+ */
+void xblock_desc_init_once(struct pram_xblock_desc *desc)
+{
+   mutex_init(&desc->lock);
+}
+
+/* __insert_xblock_desc()
+ *
+ * Insert a new descriptor in the tree.
+ */
+static void __insert_xblock_desc(struct pram_sb_info *sbi,
+unsigned long blocknr, struct rb_node *node)
+{
+   struct rb_node **p = &(sbi->desc_tree.rb_node);
+   struct rb_node *parent = NULL;
+   struct pram_xblock_desc *desc;
+
+   while (*p) {
+   parent = *p;
+   desc = rb_entry(parent, struct pram_xblock_desc, node);
+
+   if (blocknr < desc->blocknr)
+   p = &(*p)->rb_left;
+   else if (blocknr > desc->blocknr)
+   p = &(*p)->rb_right;
+   else
+   /* Oops...an other descriptor for the same block ? */
+   BUG();
+   }
+
+   rb_link_node(node, parent, p);
+   rb_insert_color(node, &sbi->desc_tree);
+}
+
+void insert_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc 
*desc)
+{
+   spin_lock(&sbi->desc_tree_lock);
+   __insert_xblock_desc(sbi, desc->blocknr, &desc->node);
+   spin_unlock(&sbi->desc_tree_lock);
+};
+
+/* __lookup_xblock_desc()
+ *
+ * Search an extended attribute descriptor in the tree via the
+ * block number. It returns the descriptor if it's found or
+ * NULL. If not found it creates a new descriptor if create is not 0.
+ */
+static struct pram_xblock_desc *__lookup_xblock_desc(struct pram_sb_info *sbi,
+   unsigned long blocknr,
+   struct kmem_cache *cache,
+   int create)
+{
+   struct rb_node *n = sbi->desc_tree.rb_node;
+   struct pram_xblock_desc *desc = NULL;
+
+   while (n) {
+   desc = rb_entry(n, struct pram_xblock_desc, node);
+
+   if (blocknr < desc->blocknr)
+   n = n->rb_left;
+   else if (blocknr > desc->blocknr)
+   n = n->rb_right;
+   else {
+   atomic_inc(&desc->refcount);
+   goto out;
+   }
+   }
+
+   /* not found */
+   if (create) {
+   desc = kmem_cache_alloc(cache, GFP_NOFS);
+   if (!desc)
+   return ERR_PTR(-ENOMEM);
+   xblock_desc_init_always(desc);
+   atomic_set(&desc->refcount, 1);
+   desc->blocknr = blocknr;
+   __insert_xblock_desc(sbi, desc->blocknr, &desc->node);
+   }
+out:
+   return desc;
+}
+
+struct pram_xblock_desc *lookup_xblock_desc(struct pram_sb_info *sbi,
+   unsigned long blocknr,
+   struct kmem_cache *cache,
+   int create)
+{
+   struct pram_xblock_desc *desc = NULL;
+
+   spin_lock(&sbi->desc_tree_lock);
+   desc = __lookup_xblock_desc(sbi, blocknr, cache, create);
+   spin_unlock(&sbi->desc_tree_lock);
+   return desc;
+}
+
+/* put_xblock_desc()
+ *
+ * Decrement the reference count and if it reaches zero and the
+ * desciptor has been marked to be free, then we free it.
+ * It returns 0 if the descriptor has been deleted and 1 otherwise.
+ */
+int put_xblock_desc(struct pram_sb_info *sbi, struct pram_xblock_desc *desc)
+{
+   int ret = 1;
+   if (!desc)
+   return ret;
+
+   if (atomic_dec_and_lock(&desc->refcount, &sbi->desc_tree_lock)) {
+   if (test_bit(FREEING, &desc->flags)) {
+   rb_erase(&desc

[PATCH 12/16 v5] pramfs: extended attributes management

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Extended attributes operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/xattr.c linux-2.6.36/fs/pramfs/xattr.c
--- linux-2.6.36-orig/fs/pramfs/xattr.c 1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/xattr.c  2010-11-28 17:51:11.0 +0100
@@ -0,0 +1,1104 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes operations.
+ *
+ * Copyright 2010 Marco Stornelli 
+ *
+ * based on fs/ext2/xattr.c with the following copyright:
+ *
+ * Fix by Harrison Xing .
+ * Extended attributes for symlinks and special files added per
+ *  suggestion of Luka Renko .
+ * xattr consolidation Copyright (c) 2004 James Morris ,
+ *  Red Hat Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * Extended attributes are stored in blocks allocated outside of
+ * any inode. The i_xattr field is then made to point to this allocated
+ * block. If all extended attributes of an inode are identical, these
+ * inodes may share the same extended attribute block. Such situations
+ * are automatically detected by keeping a cache of recent attribute block
+ * numbers and hashes over the block's contents in memory.
+ *
+ *
+ * Extended attribute block layout:
+ *
+ *   +--+
+ *   | header   |
+ *   | entry 1  | |
+ *   | entry 2  | | growing downwards
+ *   | entry 3  | v
+ *   | four null bytes  |
+ *   | . . .|
+ *   | value 1  | ^
+ *   | value 3  | | growing upwards
+ *   | value 2  | |
+ *   +--+
+ *
+ * The block header is followed by multiple entry descriptors. These entry
+ * descriptors are variable in size, and alligned to PRAM_XATTR_PAD
+ * byte boundaries. The entry descriptors are sorted by attribute name,
+ * so that two extended attribute blocks can be compared efficiently.
+ *
+ * Attribute values are aligned to the end of the block, stored in
+ * no specific order. They are also padded to PRAM_XATTR_PAD byte
+ * boundaries. No additional gaps are left between them.
+ *
+ * Locking strategy
+ * 
+ * pi->i_xattr is protected by PRAM_I(inode)->xattr_sem.
+ * EA blocks are only changed if they are exclusive to an inode, so
+ * holding xattr_sem also means that nothing but the EA block's reference
+ * count will change. Multiple writers to an EA block are synchronized
+ * by the mutex in each block descriptor. Block descriptors are kept in a
+ * red black tree and the key is the absolute block number.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+#include "xattr.h"
+#include "acl.h"
+#include "desctree.h"
+
+#define HDR(bp) ((struct pram_xattr_header *)(bp))
+#define ENTRY(ptr) ((struct pram_xattr_entry *)(ptr))
+#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
+#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
+#define GET_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, 
pram_xblock_desc_cache, 1)
+#define LOOKUP_DESC(sbi, blocknr) lookup_xblock_desc(sbi, blocknr, NULL, 0)
+
+#ifdef PRAM_XATTR_DEBUG
+# define ea_idebug(inode, f...) do { \
+   printk(KERN_DEBUG "inode %ld: ", inode->i_ino); \
+   printk(f); \
+   printk("\n"); \
+   } while (0)
+# define ea_bdebug(blocknr, f...) do { \
+   printk(KERN_DEBUG "block %lu: ", blocknr); \
+   printk(f); \
+   printk("\n"); \
+   } while (0)
+#else
+# define ea_idebug(f...)
+# define ea_bdebug(f...)
+#endif
+
+static int pram_xattr_set2(struct inode *, char *, struct pram_xblock_desc *, 
struct pram_xattr_header *);
+
+static int pram_xattr_cache_insert(struct super_block *sb, unsigned long 
blocknr, u32 xhash);
+static struct pram_xblock_desc *pram_xattr_cache_find(struct inode *,
+struct pram_xattr_header *);
+static void pram_xattr_rehash(struct pram_xattr_header *,
+ struct pram_xattr_entry *);
+
+static struct mb_cache *pram_xattr_cache;
+static struct kmem_cache *pram_xblock_desc_cache;
+
+static const struct xattr_handler *pram_xattr_handler_map[] = {
+   [PRAM_XATTR_INDEX_USER]  = &pram_xattr_user_handler,
+#ifdef CONFIG_PRAMFS_POSIX_ACL
+   [PRAM_XATTR_INDEX_POSIX_ACL_ACCESS]  = &pram_xattr_acl_access_handler,
+   [PRAM_XATTR_INDEX_POSIX_ACL_DEFAULT] = &pram_xattr_acl_default_handler,
+#endif
+   [PRAM_XATTR_INDEX_TRUSTED]   = &pram_xattr_trusted_handler,
+#ifdef CONFIG_PRAMFS_SECURITY
+   [PRAM_XATTR_INDEX_SECURITY]  = &pram_xattr_security_handler,
+#endif
+};
+
+const struct xattr_handler *pram_xattr_handlers[] = {
+   &pram_xattr_user_handler,
+   &pram_xattr_trusted_handler,
+#ifdef CONFIG_PRAMFS_POSIX_ACL
+   &pram_xattr_acl_access_handler,
+   &pram_xattr_acl_default_ha

[PATCH 15/16 v5] pramfs: test module

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Test module.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/pramfs_test.c 
linux-2.6.36/fs/pramfs/pramfs_test.c
--- linux-2.6.36-orig/fs/pramfs/pramfs_test.c   1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/pramfs_test.c2010-11-27 11:12:55.0 
+0100
@@ -0,0 +1,47 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Pramfs test module.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+
+int __init test_pramfs_write(void)
+{
+   struct pram_super_block *psb;
+
+   psb = get_pram_super();
+   if (!psb) {
+   printk(KERN_ERR
+   "%s: PRAMFS super block not found (not mounted?)\n",
+   __func__);
+   return 1;
+   }
+
+   /*
+* Attempt an unprotected clear of checksum information in the
+* superblock, this should cause a kernel page protection fault.
+*/
+   printk("%s: writing to kernel VA %p\n", __func__, psb);
+   psb->s_sum = 0;
+
+   return 0;
+}
+
+void test_pramfs_write_cleanup(void) {}
+
+/* Module information */
+MODULE_LICENSE("GPL");
+module_init(test_pramfs_write);
+module_exit(test_pramfs_write_cleanup);
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/16 v5] pramfs: dir operations

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

File operations for directories.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/dir.c linux-2.6.36/fs/pramfs/dir.c
--- linux-2.6.36-orig/fs/pramfs/dir.c   1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/dir.c2010-11-28 10:31:01.0 +0100
@@ -0,0 +1,204 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * File operations for directories.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include "pram.h"
+
+/*
+ * Parent is locked.
+ */
+int pram_add_link(struct dentry *dentry, struct inode *inode)
+{
+   struct inode *dir = dentry->d_parent->d_inode;
+   struct pram_inode *pidir, *pi, *pitail = NULL;
+   u64 tail_ino, prev_ino;
+
+   const char *name = dentry->d_name.name;
+
+   int namelen = min_t(unsigned int, dentry->d_name.len, PRAM_NAME_LEN);
+
+   pidir = pram_get_inode(dir->i_sb, dir->i_ino);
+   pi = pram_get_inode(dir->i_sb, inode->i_ino);
+
+   dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+
+   tail_ino = be64_to_cpu(pidir->i_type.dir.tail);
+   if (tail_ino != 0) {
+   pitail = pram_get_inode(dir->i_sb, tail_ino);
+   pram_memunlock_inode(dir->i_sb, pitail);
+   pitail->i_d.d_next = cpu_to_be64(inode->i_ino);
+   pram_memlock_inode(dir->i_sb, pitail);
+
+   prev_ino = tail_ino;
+
+   pram_memunlock_inode(dir->i_sb, pidir);
+   pidir->i_type.dir.tail = cpu_to_be64(inode->i_ino);
+   pidir->i_mtime = cpu_to_be32(dir->i_mtime.tv_sec);
+   pidir->i_ctime = cpu_to_be32(dir->i_ctime.tv_sec);
+   pram_memlock_inode(dir->i_sb, pidir);
+   } else {
+   /* the directory is empty */
+   prev_ino = 0;
+
+   pram_memunlock_inode(dir->i_sb, pidir);
+   pidir->i_type.dir.tail = cpu_to_be64(inode->i_ino);
+   pidir->i_type.dir.head = cpu_to_be64(inode->i_ino);
+   pidir->i_mtime = cpu_to_be32(dir->i_mtime.tv_sec);
+   pidir->i_ctime = cpu_to_be32(dir->i_ctime.tv_sec);
+   pram_memlock_inode(dir->i_sb, pidir);
+   }
+
+
+   pram_memunlock_inode(dir->i_sb, pi);
+   pi->i_d.d_prev = cpu_to_be64(prev_ino);
+   pi->i_d.d_parent = cpu_to_be64(dir->i_ino);
+   memcpy(pi->i_d.d_name, name, namelen);
+   pi->i_d.d_name[namelen] = '\0';
+   pram_memlock_inode(dir->i_sb, pi);
+   return 0;
+}
+
+int pram_remove_link(struct inode *inode)
+{
+   struct super_block *sb = inode->i_sb;
+   struct pram_inode *prev = NULL;
+   struct pram_inode *next = NULL;
+   struct pram_inode *pidir, *pi;
+
+   pi = pram_get_inode(sb, inode->i_ino);
+   pidir = pram_get_inode(sb, be64_to_cpu(pi->i_d.d_parent));
+   if (!pidir)
+   return -EACCES;
+
+   if (inode->i_ino == be64_to_cpu(pidir->i_type.dir.head)) {
+   /* first inode in directory */
+   next = pram_get_inode(sb, be64_to_cpu(pi->i_d.d_next));
+
+   if (next) {
+   pram_memunlock_inode(sb, next);
+   next->i_d.d_prev = 0;
+   pram_memlock_inode(sb, next);
+
+   pram_memunlock_inode(sb, pidir);
+   pidir->i_type.dir.head = pi->i_d.d_next;
+   } else {
+   pram_memunlock_inode(sb, pidir);
+   pidir->i_type.dir.head = 0;
+   pidir->i_type.dir.tail = 0;
+   }
+   pram_memlock_inode(sb, pidir);
+   } else if (inode->i_ino == be64_to_cpu(pidir->i_type.dir.tail)) {
+   /* last inode in directory */
+   prev = pram_get_inode(sb, be64_to_cpu(pi->i_d.d_prev));
+
+   pram_memunlock_inode(sb, prev);
+   prev->i_d.d_next = 0;
+   pram_memlock_inode(sb, prev);
+
+   pram_memunlock_inode(sb, pidir);
+   pidir->i_type.dir.tail = pi->i_d.d_prev;
+   pram_memlock_inode(sb, pidir);
+   } else {
+   /* somewhere in the middle */
+   prev = pram_get_inode(sb, be64_to_cpu(pi->i_d.d_prev));
+   next = pram_get_inode(sb, be64_to_cpu(pi->i_d.d_next));
+
+   if (prev && next) {
+   pram_memunlock_inode(sb, prev);
+   prev->i_d.d_next = pi->i_d.d_next;
+   pram_memlock_inode(sb, prev);
+
+   pram_memunlock_inode(sb, next);
+   next->i_d.d_prev = pi->i_d.d_prev;
+   

[PATCH 10/16 v5] pramfs: xip operations

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

XIP operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.c linux-2.6.36/fs/pramfs/xip.c
--- linux-2.6.36-orig/fs/pramfs/xip.c   1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/xip.c2010-12-12 18:34:05.0 +0100
@@ -0,0 +1,83 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * XIP operations.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+#include "xip.h"
+
+static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock,
+sector_t *data_block, int create)
+{
+   int err = -EIO;
+   u64 block;
+
+   mutex_lock(&PRAM_I(inode)->truncate_mutex);
+
+   block = pram_find_data_block(inode, iblock);
+
+   if (!block) {
+   if (!create) {
+   err = -ENODATA;
+   goto err;
+   }
+
+   err = pram_alloc_blocks(inode, iblock, 1);
+   if (err)
+   goto err;
+
+   block = pram_find_data_block(inode, iblock);
+   if (!block) {
+   err = -ENODATA;
+   goto err;
+   }
+   }
+
+   *data_block = block;
+   err = 0;
+
+ err:
+   mutex_unlock(&PRAM_I(inode)->truncate_mutex);
+   return err;
+}
+
+static inline int __pram_get_block(struct inode *inode, pgoff_t pgoff, int 
create,
+  sector_t *result)
+{
+   int rc = 0;
+
+   rc = pram_find_and_alloc_blocks(inode, (sector_t)pgoff, result, create);
+
+   if (rc == -ENODATA)
+   BUG_ON(create);
+
+   return rc;
+}
+
+int pram_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
+   void **kmem, unsigned long *pfn)
+{
+   int rc;
+   sector_t block;
+
+   /* first, retrieve the block */
+   rc = __pram_get_block(mapping->host, pgoff, create, &block);
+   if (rc)
+   goto exit;
+
+   *kmem = pram_get_block(mapping->host->i_sb, block);
+   *pfn = page_to_pfn(virt_to_page((unsigned long)*kmem));
+
+exit:
+   return rc;
+}
diff -Nurp linux-2.6.36-orig/fs/pramfs/xip.h linux-2.6.36/fs/pramfs/xip.h
--- linux-2.6.36-orig/fs/pramfs/xip.h   1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/xip.h2010-11-28 12:37:00.0 +0100
@@ -0,0 +1,28 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * XIP operations.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifdef CONFIG_PRAMFS_XIP
+int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **,
+ unsigned long *);
+static inline int pram_use_xip(struct super_block *sb)
+{
+   struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+   return sbi->s_mount_opt & PRAM_MOUNT_XIP;
+}
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_mem)
+
+#else
+
+#define mapping_is_xip(map)0
+#define pram_use_xip(sb)   0
+#define pram_get_xip_mem   NULL
+
+#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 07/16 v5] pramfs: symbolic links

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Symlink operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/symlink.c 
linux-2.6.36/fs/pramfs/symlink.c
--- linux-2.6.36-orig/fs/pramfs/symlink.c   1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/symlink.c2010-11-27 11:13:18.0 +0100
@@ -0,0 +1,76 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Symlink operations
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include "pram.h"
+#include "xattr.h"
+
+int pram_block_symlink(struct inode *inode, const char *symname, int len)
+{
+   struct super_block *sb = inode->i_sb;
+   u64 block;
+   char *blockp;
+   int err;
+
+   err = pram_alloc_blocks(inode, 0, 1);
+   if (err)
+   return err;
+
+   block = pram_find_data_block(inode, 0);
+   blockp = pram_get_block(sb, block);
+
+   pram_memunlock_block(sb, blockp);
+   memcpy(blockp, symname, len);
+   blockp[len] = '\0';
+   pram_memlock_block(sb, blockp);
+   return 0;
+}
+
+static int pram_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+   struct inode *inode = dentry->d_inode;
+   struct super_block *sb = inode->i_sb;
+   u64 block;
+   char *blockp;
+
+   block = pram_find_data_block(inode, 0);
+   blockp = pram_get_block(sb, block);
+   return vfs_readlink(dentry, buffer, buflen, blockp);
+}
+
+static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+   struct inode *inode = dentry->d_inode;
+   struct super_block *sb = inode->i_sb;
+   off_t block;
+   int status;
+   char *blockp;
+
+   block = pram_find_data_block(inode, 0);
+   blockp = pram_get_block(sb, block);
+   status = vfs_follow_link(nd, blockp);
+   return ERR_PTR(status);
+}
+
+struct inode_operations pram_symlink_inode_operations = {
+   .readlink   = pram_readlink,
+   .follow_link= pram_follow_link,
+   .setattr= pram_notify_change,
+#ifdef CONFIG_PRAMFS_XATTR
+   .setxattr   = generic_setxattr,
+   .getxattr   = generic_getxattr,
+   .listxattr  = pram_listxattr,
+   .removexattr= generic_removexattr,
+#endif
+};
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/16 v5] pramfs: inode operations

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Inode methods (allocate/free/read/write).

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/inode.c linux-2.6.36/fs/pramfs/inode.c
--- linux-2.6.36-orig/fs/pramfs/inode.c 1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/inode.c  2010-12-15 19:24:14.0 +0100
@@ -0,0 +1,729 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Inode methods (allocate/free/read/write).
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+#include "xattr.h"
+#include "xip.h"
+#include "acl.h"
+
+struct backing_dev_info pram_backing_dev_info __read_mostly = {
+   .ra_pages   = 0,/* No readahead */
+   .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
+};
+
+/*
+ * allocate a data block for inode and return it's absolute blocknr.
+ * Zeroes out the block if zero set. Increments inode->i_blocks.
+ */
+static int pram_new_data_block(struct inode *inode, unsigned long *blocknr, 
int zero)
+{
+   int errval = pram_new_block(inode->i_sb, blocknr, zero);
+
+   if (!errval) {
+   struct pram_inode *pi = pram_get_inode(inode->i_sb,
+   inode->i_ino);
+   inode->i_blocks++;
+   pram_memunlock_inode(inode->i_sb, pi);
+   pi->i_blocks = cpu_to_be32(inode->i_blocks);
+   pram_memlock_inode(inode->i_sb, pi);
+   }
+
+   return errval;
+}
+
+/*
+ * find the offset to the block represented by the given inode's file
+ * relative block number.
+ */
+u64 pram_find_data_block(struct inode *inode, unsigned long file_blocknr)
+{
+   struct super_block *sb = inode->i_sb;
+   struct pram_inode *pi;
+   u64 *row; /* ptr to row block */
+   u64 *col; /* ptr to column blocks */
+   u64 bp = 0;
+   unsigned int i_row, i_col;
+   unsigned int N = sb->s_blocksize >> 3; /* num block ptrs per block */
+   unsigned int Nbits = sb->s_blocksize_bits - 3;
+
+   pi = pram_get_inode(sb, inode->i_ino);
+
+   i_row = file_blocknr >> Nbits;
+   i_col  = file_blocknr & (N-1);
+
+   row = pram_get_block(sb, be64_to_cpu(pi->i_type.reg.row_block));
+   if (row) {
+   col = pram_get_block(sb, be64_to_cpu(row[i_row]));
+   if (col)
+   bp = be64_to_cpu(col[i_col]);
+   }
+
+   return bp;
+}
+
+/*
+ * Free data blocks from inode in the range start <=> end
+ */
+static void __pram_truncate_blocks(struct inode *inode, loff_t start, loff_t 
end)
+{
+   struct super_block *sb = inode->i_sb;
+   struct pram_inode *pi = pram_get_inode(sb, inode->i_ino);
+   int N = sb->s_blocksize >> 3; /* num block ptrs per block */
+   int Nbits = sb->s_blocksize_bits - 3;
+   int first_row_index, last_row_index, i, j;
+   unsigned long blocknr, first_blocknr, last_blocknr;
+   unsigned int freed = 0;
+   u64 *row; /* ptr to row block */
+   u64 *col; /* ptr to column blocks */
+
+   if (start > end || !inode->i_blocks || !pi->i_type.reg.row_block)
+   return;
+
+   mutex_lock(&PRAM_I(inode)->truncate_mutex);
+
+   first_blocknr = (start + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+   last_blocknr = (end + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+   first_row_index = first_blocknr >> Nbits;
+   last_row_index  = last_blocknr >> Nbits;
+
+   row = pram_get_block(sb, be64_to_cpu(pi->i_type.reg.row_block));
+
+   for (i = first_row_index; i <= last_row_index; i++) {
+   int first_col_index = (i == first_row_index) ?
+   first_blocknr & (N-1) : 0;
+   int last_col_index = (i == last_row_index) ?
+   last_blocknr & (N-1) : N-1;
+
+   if (unlikely(!row[i]))
+   continue;
+
+   col = pram_get_block(sb, be64_to_cpu(row[i]));
+
+   for (j = first_col_index; j <= last_col_index; j++) {
+
+   if (unlikely(!col[j]))
+   continue;
+
+   blocknr = pram_get_blocknr(sb, be64_to_cpu(col[j]));
+   pram_free_block(sb, blocknr);
+   freed++;
+   pram_memunlock_block(sb, col);
+   col[j] = 0;
+   pram_memlock_block(sb, col);
+   }
+
+   if (first_col_index == 0) {
+   blocknr = pram_get_blocknr(sb, be64_to_cpu(row[i]));
+   pram_free_bl

[PATCH 04/16 v5] pramfs: file operations

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

File operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/file.c linux-2.6.36/fs/pramfs/file.c
--- linux-2.6.36-orig/fs/pramfs/file.c  1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/file.c   2010-12-15 19:19:26.0 +0100
@@ -0,0 +1,182 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * File operations for files.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "pram.h"
+#include "acl.h"
+#include "xip.h"
+#include "xattr.h"
+
+static int pram_open_file(struct inode *inode, struct file *filp)
+{
+   filp->f_flags |= O_DIRECT;
+   return generic_file_open(inode, filp);
+}
+
+ssize_t pram_direct_IO(int rw, struct kiocb *iocb,
+  const struct iovec *iov,
+  loff_t offset, unsigned long nr_segs)
+{
+   struct file *file = iocb->ki_filp;
+   struct inode *inode = file->f_mapping->host;
+   struct super_block *sb = inode->i_sb;
+   int progress = 0, hole = 0;
+   ssize_t retval = 0;
+   void *tmp = NULL;
+   unsigned long blocknr, blockoff;
+   int num_blocks, blocksize_mask, blocksize, blocksize_bits;
+   char __user *buf = iov->iov_base;
+   size_t length = iov_length(iov, nr_segs);
+
+   if (length < 0)
+   return -EINVAL;
+   if ((rw == READ) && (offset + length > inode->i_size))
+   length = inode->i_size - offset;
+   if (!length)
+   goto out;
+
+   blocksize_bits = inode->i_sb->s_blocksize_bits;
+   blocksize = 1 << blocksize_bits;
+   blocksize_mask = blocksize - 1;
+
+   /* find starting block number to access */
+   blocknr = offset >> blocksize_bits;
+   /* find starting offset within starting block */
+   blockoff = offset & blocksize_mask;
+   /* find number of blocks to access */
+   num_blocks = (blockoff + length + blocksize_mask) >> blocksize_bits;
+
+   if (rw == WRITE) {
+   /* prepare a temporary buffer to hold a user data block
+  for writing. */
+   tmp = kmalloc(blocksize, GFP_KERNEL);
+   if (!tmp)
+   return -ENOMEM;
+   /* now allocate the data blocks we'll need */
+   retval = pram_alloc_blocks(inode, blocknr, num_blocks);
+   if (retval)
+   goto fail1;
+   }
+
+   while (length) {
+   int count;
+   u8 *bp = NULL;
+   u64 block = pram_find_data_block(inode, blocknr++);
+   if (unlikely(!block && rw == READ)) {
+   /* We are falling in a hole */
+   hole = 1;
+   } else {
+   bp = (u8 *)pram_get_block(sb, block);
+   if (!bp)
+   goto fail2;
+   }
+
+   count = blockoff + length > blocksize ?
+   blocksize - blockoff : length;
+
+   if (rw == READ) {
+   if (unlikely(hole)) {
+   retval = clear_user(buf, count);
+   if (retval) {
+   retval = -EFAULT;
+   goto fail1;
+   }
+   } else {
+   retval = copy_to_user(buf, &bp[blockoff], 
count);
+   if (retval) {
+   retval = -EFAULT;
+   goto fail1;
+   }
+   }
+   } else {
+   retval = copy_from_user(tmp, buf, count);
+   if (retval) {
+   retval = -EFAULT;
+   goto fail1;
+   }
+
+   pram_memunlock_block(inode->i_sb, bp);
+   memcpy(&bp[blockoff], tmp, count);
+   pram_memlock_block(inode->i_sb, bp);
+   }
+
+   progress += count;
+   buf += count;
+   length -= count;
+   blockoff = 0;
+   hole = 0;
+   }
+
+fail2:
+   retval = progress;
+fail1:
+   kfree(tmp);
+out:
+   return retval;
+}
+
+int pram_mmap(struct file *file, struct vm_area_struct *vma)
+{
+   /* Only private mappings */
+   if (vma->vm_flags & VM_SHARED)
+   return -EINVAL;
+   return generic_file_mmap(fi

[PATCH 05/16 v5] pramfs: block allocation

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Block allocation operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/balloc.c linux-2.6.36/fs/pramfs/balloc.c
--- linux-2.6.36-orig/fs/pramfs/balloc.c1970-01-01 01:00:00.0 
+0100
+++ linux-2.6.36/fs/pramfs/balloc.c 2010-12-12 17:19:21.0 +0100
@@ -0,0 +1,147 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * The blocks allocation and deallocation routines.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include "pram.h"
+
+/*
+ * This just marks in-use the blocks that make up the bitmap.
+ * The bitmap must be writeable before calling.
+ */
+void pram_init_bitmap(struct super_block *sb)
+{
+   struct pram_super_block *ps = pram_get_super(sb);
+   unsigned long *bitmap = pram_get_bitmap(sb);
+   int blocks = be32_to_cpu(ps->s_bitmap_blocks);
+
+   memset(bitmap, 0, blocks << sb->s_blocksize_bits);
+
+   bitmap_fill(bitmap, blocks);
+}
+
+
+/* Free absolute blocknr */
+void pram_free_block(struct super_block *sb, unsigned long blocknr)
+{
+   struct pram_super_block *ps;
+   u64 bitmap_block;
+   unsigned long bitmap_bnr;
+   void *bitmap;
+   void *bp;
+
+   lock_super(sb);
+
+   bitmap = pram_get_bitmap(sb);
+   /*
+* find the block within the bitmap that contains the inuse bit
+* for the block we need to free. We need to unlock this bitmap
+* block to clear the inuse bit.
+*/
+   bitmap_bnr = blocknr >> (3 + sb->s_blocksize_bits);
+   bitmap_block = pram_get_block_off(sb, bitmap_bnr);
+   bp = pram_get_block(sb, bitmap_block);
+
+   pram_memunlock_block(sb, bp);
+   pram_clear_bit(blocknr, bitmap); /* mark the block free */
+   pram_memlock_block(sb, bp);
+   
+   ps = pram_get_super(sb);
+   pram_memunlock_super(sb, ps);
+   
+   if (blocknr < be32_to_cpu(ps->s_free_blocknr_hint))
+   ps->s_free_blocknr_hint = cpu_to_be32(blocknr);
+   be32_add_cpu(&ps->s_free_blocks_count, 1);
+   pram_memlock_super(sb, ps);
+   
+   unlock_super(sb);
+}
+
+
+/*
+ * allocate a block and return it's absolute blocknr. Zeroes out the
+ * block if zero set.
+ */
+int pram_new_block(struct super_block *sb, unsigned long *blocknr, int zero)
+{
+   struct pram_super_block *ps;
+   u64 bitmap_block;
+   unsigned long bnr, bitmap_bnr;
+   int errval;
+   void *bitmap;
+   void *bp;
+
+   lock_super(sb);
+   ps = pram_get_super(sb);
+   bitmap = pram_get_bitmap(sb);
+
+   if (ps->s_free_blocks_count) {
+   /* find the oldest unused block */
+   bnr = pram_find_next_zero_bit(bitmap,
+be32_to_cpu(ps->s_blocks_count),
+be32_to_cpu(ps->s_free_blocknr_hint));
+
+   if (bnr < be32_to_cpu(ps->s_bitmap_blocks) ||
+   bnr >= be32_to_cpu(ps->s_blocks_count)) {
+   pram_dbg("no free blocks found!\n");
+   errval = -ENOSPC;
+   goto fail;
+   }
+
+   pram_memunlock_super(sb, ps);
+   be32_add_cpu(&ps->s_free_blocks_count, -1);
+   if (bnr < (be32_to_cpu(ps->s_blocks_count)-1))
+   ps->s_free_blocknr_hint = cpu_to_be32(bnr+1);
+   else
+   ps->s_free_blocknr_hint = 0;
+   pram_memlock_super(sb, ps);
+   } else {
+   pram_dbg("all blocks allocated\n");
+   errval = -ENOSPC;
+   goto fail;
+   }
+
+   /*
+* find the block within the bitmap that contains the inuse bit
+* for the unused block we just found. We need to unlock it to
+* set the inuse bit.
+*/
+   bitmap_bnr = bnr >> (3 + sb->s_blocksize_bits);
+   bitmap_block = pram_get_block_off(sb, bitmap_bnr);
+   bp = pram_get_block(sb, bitmap_block);
+
+   pram_memunlock_block(sb, bp);
+   pram_set_bit(bnr, bitmap); /* mark the new block in use */
+   pram_memlock_block(sb, bp);
+
+   if (zero) {
+   bp = pram_get_block(sb, pram_get_block_off(sb, bnr));
+   pram_memunlock_block(sb, bp);
+   memset(bp, 0, sb->s_blocksize);
+   pram_memlock_block(sb, bp);
+   }
+
+   *blocknr = bnr;
+   pram_dbg("allocated blocknr %lu", bnr);
+   errval = 0;
+ fail:
+   unlock_super(sb);
+   return errval;
+}
+
+unsigned long pram_count_free_blocks(struct super_block *sb)
+{
+   struct pr

[PATCH 02/16 v6] pramfs: super operations

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Super block operations.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/fs/pramfs/super.c linux-2.6.36/fs/pramfs/super.c
--- linux-2.6.36-orig/fs/pramfs/super.c 1970-01-01 01:00:00.0 +0100
+++ linux-2.6.36/fs/pramfs/super.c  2010-12-12 18:30:50.0 +0100
@@ -0,0 +1,932 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Super block operations.
+ *
+ * Copyright 2009-2010 Marco Stornelli 
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "xattr.h"
+#include "pram.h"
+
+static struct super_operations pram_sops;
+static const struct export_operations pram_export_ops;
+static struct kmem_cache *pram_inode_cachep;
+
+#ifdef CONFIG_PRAMFS_TEST
+static void *first_pram_super;
+
+struct pram_super_block *get_pram_super(void)
+{
+   return (struct pram_super_block *)first_pram_super;
+}
+EXPORT_SYMBOL(get_pram_super);
+#endif
+
+void pram_error_mng(struct super_block * sb, const char * fmt, ...)
+{
+   va_list args;
+
+   va_start(args, fmt);
+   printk(KERN_ERR "pramfs error: ");
+   vprintk(fmt, args);
+   printk("\n");
+   va_end(args);
+
+   if (test_opt(sb, ERRORS_PANIC))
+   panic("pramfs: panic from previous error\n");
+   if (test_opt(sb, ERRORS_RO)) {
+   printk(KERN_CRIT "pramfs error: remounting filesystem 
read-only");
+   sb->s_flags |= MS_RDONLY;
+   }
+}
+
+static void pram_set_blocksize(struct super_block *sb, unsigned long size)
+{
+   int bits;
+
+   /*
+* We've already validated the user input and the value here must be
+* between PRAM_MAX_BLOCK_SIZE and PRAM_MIN_BLOCK_SIZE
+* and it must be a power of 2.
+*/
+   bits = fls(size) - 1;
+   sb->s_blocksize_bits = bits;
+   sb->s_blocksize = (1< MAX_LFS_FILESIZE)
+   res = MAX_LFS_FILESIZE;
+
+   pram_info("max file size %llu bytes", res);
+   return res;
+}
+
+enum {
+   Opt_addr, Opt_bpi, Opt_size,
+   Opt_num_inodes, Opt_mode, Opt_uid,
+   Opt_gid, Opt_blocksize, Opt_user_xattr,
+   Opt_nouser_xattr, Opt_noprotect,
+   Opt_acl, Opt_noacl, Opt_xip,
+   Opt_err_cont, Opt_err_panic, Opt_err_ro,
+   Opt_err
+};
+
+static const match_table_t tokens = {
+   {Opt_bpi,   "physaddr=%x"},
+   {Opt_bpi,   "bpi=%u"},
+   {Opt_size,  "init=%s"},
+   {Opt_num_inodes,"N=%u"},
+   {Opt_mode,  "mode=%o"},
+   {Opt_uid,   "uid=%u"},
+   {Opt_gid,   "gid=%u"},
+   {Opt_blocksize, "bs=%s"},
+   {Opt_user_xattr,"user_xattr"},
+   {Opt_user_xattr,"nouser_xattr"},
+   {Opt_noprotect, "noprotect"},
+   {Opt_acl,   "acl"},
+   {Opt_acl,   "noacl"},
+   {Opt_xip,   "xip"},
+   {Opt_err_cont,  "errors=continue"},
+   {Opt_err_panic, "errors=panic"},
+   {Opt_err_ro,"errors=remount-ro"},
+   {Opt_err,   NULL},
+};
+
+static phys_addr_t get_phys_addr(void **data)
+{
+   phys_addr_t phys_addr;
+   char *options = (char *) *data;
+
+   if (!options || strncmp(options, "physaddr=", 9) != 0)
+   return (phys_addr_t)ULLONG_MAX;
+   options += 9;
+   phys_addr = (phys_addr_t)simple_strtoull(options, &options, 0);
+   if (*options && *options != ',') {
+   printk(KERN_ERR "Invalid phys addr specification: %s\n",
+  (char *) *data);
+   return (phys_addr_t)ULLONG_MAX;
+   }
+   if (phys_addr & (PAGE_SIZE - 1)) {
+   printk(KERN_ERR "physical address 0x%16llx for pramfs isn't "
+ "aligned to a page boundary\n",
+ (u64)phys_addr);
+   return (phys_addr_t)ULLONG_MAX;
+   }
+   if (*options == ',')
+   options++;
+   *data = (void *) options;
+   return phys_addr;
+}
+
+static int pram_parse_options(char *options, struct pram_sb_info *sbi, bool 
remount)
+{
+   char *p, *rest;
+   substring_t args[MAX_OPT_ARGS];
+   int option;
+
+   if (!options)
+   return 0;
+
+   while ((p = strsep(&options, ",")) != NULL) {
+   int token;
+   if (!*p)
+   continue;
+
+   token = match_token(p, tokens, args);
+   switch (token) {
+   case O

[PATCH 00/16 v5] pramfs: persistent and protected RAM filesystem

2010-12-16 Thread Marco Stornelli
Hi all,

fifth round for the patch series. I summarize here the changes to
improve the review:

v5:
- removed the changelog from documentation file
- added the function pram_check_flags in the file operations
- added a check when the user uses XIP and the blocksize is different
from page size
- added i_meta_mutex to avoid race conditions in the inode update
path
- changed the lock policy during mem{lock|unlock} operations
- replaced bitmap_set with bitmap_fill
- added mount options xip, acl, noacl, noprotect, user_xattr and
nouser_xattr as required by Paul Maundt
- inserted pr_fmt in pram.h
- inserted macros IF2DT and DT2IF
- removed file name description from each file
- used min_t instead of using own check in pram_add_link()

v4:
- in bitmap init used already present bitmap_set function
- fix a possible memory leak in an error path reported by yidong zhang

v3:
- fix a possible memory leak in an error path reported by yidong zhang
- fix a warning when using XIP about not used __pram_mmap symbol
- fix test module header description and replaced TEST_MODULE with
PRAMFS_TEST_MODULE in the Kconfig and Makefile according to the comments
done by Randy Dunlap
- fix a compilation warning in super.c reported by James Hogan
- fix a compilation error when XIP was enabled
- removed not used symbol PRAM_XATTR_INDEX_LUSTRE
- fix some comment style issue

v2:
- fix documentation errors reported by Randy Dunlap and Kieran Bingham
- reworked memory write protection functions with the suggestions of
Andi Kleen

v1:
- first draft

Marco
--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/16 v5] pramfs: documentation

2010-12-16 Thread Marco Stornelli
From: Marco Stornelli 

Documentation for PRAMFS.

Signed-off-by: Marco Stornelli 
---
diff -Nurp linux-2.6.36-orig/Documentation/filesystems/pramfs.txt 
linux-2.6.36/Documentation/filesystems/pramfs.txt
--- linux-2.6.36-orig/Documentation/filesystems/pramfs.txt  1970-01-01 
01:00:00.0 +0100
+++ linux-2.6.36/Documentation/filesystems/pramfs.txt   2010-12-15 
19:41:58.0 +0100
@@ -0,0 +1,179 @@
+
+PRAMFS Overview
+===
+
+Many embedded systems have a block of non-volatile RAM separate from
+normal system memory, i.e. of which the kernel maintains no memory page
+descriptors. For such systems it would be beneficial to mount a
+fast read/write filesystem over this "I/O memory", for storing frequently
+accessed data that must survive system reboots and power cycles. An
+example usage might be system logs under /var/log, or a user address
+book in a cell phone or PDA.
+
+Linux traditionally had no support for a persistent, non-volatile RAM-based
+filesystem, persistent meaning the filesystem survives a system reboot
+or power cycle intact. The RAM-based filesystems such as tmpfs and ramfs
+have no actual backing store but exist entirely in the page and buffer
+caches, hence the filesystem disappears after a system reboot or
+power cycle.
+
+A relatively straightforward solution is to write a simple block driver
+for the non-volatile RAM, and mount over it any disk-based filesystem such
+as ext2, ext3, ext4, etc.
+
+But the disk-based fs over non-volatile RAM block driver approach has
+some drawbacks:
+
+1. Complexity of disk-based fs: disk-based filesystems such as ext2/ext3/ext4
+   were designed for optimum performance on spinning disk media, so they
+   implement features such as block groups, which attempts to group inode data
+   into a contiguous set of data blocks to minimize disk seeking when accessing
+   files. For RAM there is no such concern; a file's data blocks can be
+   scattered throughout the media with no access speed penalty at all. So block
+   groups in a filesystem mounted over RAM just adds unnecessary
+   complexity. A better approach is to use a filesystem specifically
+   tailored to RAM media which does away with these disk-based features.
+   This increases the efficient use of space on the media, i.e. more
+   space is dedicated to actual file data storage and less to meta-data
+   needed to maintain that file data.
+
+2. Different problems between disks and RAM: Because PRAMFS attempts to avoid
+   filesystem corruption caused by kernel bugs, dirty pages in the page cache
+   are not allowed to be written back to the backing-store RAM. This way, an
+   errant write into the page cache will not get written back to the 
filesystem.
+   However, if the backing-store RAM is comparable in access speed to system
+   memory, the penalty of not using caching is minimal. With this consideration
+   it's better to move file data directly between the user buffers and the 
backing
+   store RAM, i.e. use direct I/O. This prevents the unnecessary populating of
+   the page cache with dirty pages. However direct I/O has to be enabled at
+   every file open. To enable direct I/O at all times for all regular files
+   requires either that applications be modified to include the O_DIRECT flag 
on
+   all file opens, or that the filesystem used performs direct I/O by default.
+
+The Persistent/Protected RAM Special Filesystem (PRAMFS) is a read/write
+filesystem that has been designed to address these issues. PRAMFS is targeted
+to fast I/O memory, and if the memory is non-volatile, the filesystem will be
+persistent.
+
+In PRAMFS, direct I/O is enabled across all files in the filesystem, in other
+words the O_DIRECT flag is forced on every open of a PRAMFS file. Also, file
+I/O in the PRAMFS is always synchronous. There is no need to block the current
+process while the transfer to/from the PRAMFS is in progress, since one of
+the requirements of the PRAMFS is that the filesystem exists in fast RAM. So
+file I/O in PRAMFS is always direct, synchronous, and never blocks.
+
+The data organization in PRAMFS can be thought of as an extremely simplified
+version of ext2, such that the ratio of data to meta-data is very high.
+
+PRAMFS supports the execute-in-place. With XIP, instead of keeping data in the
+page cache, the need to have a page cache copy is eliminated completely.
+Read&write type operations are performed directly from/to the memory. For file
+mappings, the RAM itself is mapped directly into userspace. XIP, in addition,
+speed up the applications start-up time because it removes the needs of any
+copies.
+
+PRAMFS is write protected. The page table entries that map the backing-store
+RAM are normally marked read-only. Write operations into the filesystem
+temporarily mark the affected pages as writeable, the write operation is
+carried out with locks held, and then the page table entries is
+marked read-only again.
+This feature provides protection against fi