[PATCH] Move an assert under DEBUG_KERNEL.

2011-01-06 Thread Rob Landley

From: Rob Landley rland...@parallels.com

Move an assert under DEBUG_KERNEL.

Signed-off-by: Rob Landley rland...@parallels.com
---

Saves about 3k from x86-64 defconfig according to scripts/bloat-o-meter.

 include/linux/rtnetlink.h |4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index bbad657..28c4025 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -782,6 +782,7 @@ extern struct netdev_queue 
*dev_ingress_queue_create(struct net_device *dev);

 extern void rtnetlink_init(void);
 extern void __rtnl_unlock(void);

+#ifdef CONFIG_DEBUG_KERNEL
 #define ASSERT_RTNL() do { \
if (unlikely(!rtnl_is_locked())) { \
printk(KERN_ERR RTNL: assertion failed at %s (%d)\n, \
@@ -789,6 +790,9 @@ extern void __rtnl_unlock(void);
dump_stack(); \
} \
 } while(0)
+#else
+#define ASSERT_RTNL()
+#endif

 static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
 {
--
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 00/17] pramfs: persistent and protected RAM filesystem

2011-01-06 Thread Marco Stornelli
Hi all,

after several reviews is time to submit the code for mainline. Thanks to
CELF to believe and support actively the project and thanks to Tim Bird.

Here the stats:

 Documentation/filesystems/pramfs.txt |  179 ++
 Documentation/filesystems/xip.txt|2 +
 arch/Kconfig |3 +
 arch/x86/Kconfig |1 +
 fs/Kconfig   |8 +-
 fs/Makefile  |1 +
 fs/pramfs/Kconfig|   72 +++
 fs/pramfs/Makefile   |   14 +
 fs/pramfs/acl.c  |  433 +
 fs/pramfs/acl.h  |   86 +++
 fs/pramfs/balloc.c   |  147 +
 fs/pramfs/desctree.c |  181 ++
 fs/pramfs/desctree.h |   44 ++
 fs/pramfs/dir.c  |  208 +++
 fs/pramfs/file.c |  326 ++
 fs/pramfs/inode.c|  848 ++
 fs/pramfs/ioctl.c|  121 
 fs/pramfs/namei.c|  371 
 fs/pramfs/pram.h |  269 +
 fs/pramfs/pramfs_test.c  |   47 ++
 fs/pramfs/super.c|  940 +
 fs/pramfs/symlink.c  |   76 +++
 fs/pramfs/wprotect.c |   41 ++
 fs/pramfs/wprotect.h |  151 +
 fs/pramfs/xattr.c| 1104 ++
 fs/pramfs/xattr.h|  131 
 fs/pramfs/xattr_security.c   |   78 +++
 fs/pramfs/xattr_trusted.c|   65 ++
 fs/pramfs/xattr_user.c   |   68 +++
 fs/pramfs/xip.c  |   83 +++
 fs/pramfs/xip.h  |   28 +
 include/linux/magic.h|1 +
 include/linux/pram_fs.h  |  130 
 include/linux/pram_fs_sb.h   |   45 ++
 34 files changed, 6299 insertions(+), 3 deletions(-)


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/17] pramfs: documentation

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Documentation for PRAMFS.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/Documentation/filesystems/pramfs.txt 
b/Documentation/filesystems/pramfs.txt
new file mode 100644
index 000..2ad536f
--- /dev/null
+++ b/Documentation/filesystems/pramfs.txt
@@ -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.
+Readwrite 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 filesystem corruption caused by errant
+writes into the RAM due to kernel 

[PATCH 02/17] pramfs: super operations

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Super block operations.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/super.c b/fs/pramfs/super.c
new file mode 100644
index 000..0157b35
--- /dev/null
+++ b/fs/pramfs/super.c
@@ -0,0 +1,940 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Super block operations.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/module.h
+#include linux/string.h
+#include linux/slab.h
+#include linux/init.h
+#include linux/blkdev.h
+#include linux/parser.h
+#include linux/vfs.h
+#include linux/uaccess.h
+#include linux/io.h
+#include linux/seq_file.h
+#include linux/mount.h
+#include linux/mm.h
+#include linux/ctype.h
+#include linux/bitops.h
+#include linux/magic.h
+#include linux/exportfs.h
+#include linux/random.h
+#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 = (1bits);
+}
+
+static inline void *pram_ioremap(phys_addr_t phys_addr, ssize_t size, bool 
protect)
+{
+   void *retval;
+
+   /*
+* NOTE: Userland may not map this resource, we will mark the region so
+* /dev/mem and the sysfs MMIO access will not be allowed. This
+* restriction depends on STRICT_DEVMEM option. If this option is
+* disabled or not available we mark the region only as busy.
+*/
+   retval = request_mem_region_exclusive(phys_addr, size, pramfs);
+   if (!retval)
+   goto fail;
+
+   retval = ioremap_nocache(phys_addr, size);
+
+   if (retval  protect)
+   pram_writeable(retval, size, 0);
+fail:
+   return retval;
+}
+
+static loff_t pram_max_size(int bits)
+{
+   loff_t res;
+   res = (1ULL  (3*bits - 6)) - 1;
+
+   if (res  MAX_LFS_FILESIZE)
+   res = MAX_LFS_FILESIZE;
+
+   pram_info(max file size %llu bytes\n, 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 

[PATCH 03/17] pramfs: inode operations

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

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

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/inode.c b/fs/pramfs/inode.c
new file mode 100644
index 000..e5ee072
--- /dev/null
+++ b/fs/pramfs/inode.c
@@ -0,0 +1,848 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Inode methods (allocate/free/read/write).
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/fs.h
+#include linux/smp_lock.h
+#include linux/sched.h
+#include linux/highuid.h
+#include linux/module.h
+#include linux/mpage.h
+#include linux/backing-dev.h
+#include linux/falloc.h
+#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 */
+
+   mutex_lock(PRAM_I(inode)-truncate_mutex);
+
+   if (start  end || !inode-i_blocks || !pi-i_type.reg.row_block) {
+   mutex_unlock(PRAM_I(inode)-truncate_mutex);
+   return;
+   }
+
+   first_blocknr = (start + sb-s_blocksize - 1)  sb-s_blocksize_bits;
+
+   if ((be32_to_cpu(pi-i_flags)  PRAM_EOFBLOCKS_FL)  start == 0)
+   last_blocknr = (1UL  (2*sb-s_blocksize_bits - 6)) - 1;
+   else
+   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]));
+   

[PATCH 04/17] pramfs: file operations

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

File operations.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/file.c b/fs/pramfs/file.c
new file mode 100644
index 000..05a4af4
--- /dev/null
+++ b/fs/pramfs/file.c
@@ -0,0 +1,326 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * File operations for files.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/fs.h
+#include linux/sched.h
+#include linux/slab.h
+#include linux/uio.h
+#include linux/mm.h
+#include linux/uaccess.h
+#include pram.h
+#include acl.h
+#include xip.h
+#include xattr.h
+
+/*
+ * The following functions are helper routines to copy to/from
+ * user space and iter over io vectors (mainly for readv/writev).
+ * They are used in the direct IO path.
+ */
+static size_t __pram_iov_copy_from(char *vaddr,
+   const struct iovec *iov, size_t base, size_t bytes)
+{
+   size_t copied = 0, left = 0;
+
+   while (bytes) {
+   char __user *buf = iov-iov_base + base;
+   int copy = min(bytes, iov-iov_len - base);
+
+   base = 0;
+   left = __copy_from_user(vaddr, buf, copy);
+   copied += copy;
+   bytes -= copy;
+   vaddr += copy;
+   iov++;
+
+   if (unlikely(left))
+   break;
+   }
+   return copied - left;
+}
+
+static size_t __pram_iov_copy_to(char *vaddr,
+   const struct iovec *iov, size_t base, size_t bytes)
+{
+   size_t copied = 0, left = 0;
+
+   while (bytes) {
+   char __user *buf = iov-iov_base + base;
+   int copy = min(bytes, iov-iov_len - base);
+
+   base = 0;
+   left = __copy_to_user(buf, vaddr, copy);
+   copied += copy;
+   bytes -= copy;
+   vaddr += copy;
+   iov++;
+
+   if (unlikely(left))
+   break;
+   }
+   return copied - left;
+}
+
+static size_t pram_iov_copy_from(void *to, struct iov_iter *i, size_t bytes)
+{
+   size_t copied;
+
+   if (likely(i-nr_segs == 1)) {
+   int left;
+   char __user *buf = i-iov-iov_base + i-iov_offset;
+   left = __copy_from_user(to, buf, bytes);
+   copied = bytes - left;
+   } else {
+   copied = __pram_iov_copy_from(to, i-iov, i-iov_offset, bytes);
+   }
+
+   return copied;
+}
+
+static size_t pram_iov_copy_to(void *from, struct iov_iter *i, size_t bytes)
+{
+   size_t copied;
+
+   if (likely(i-nr_segs == 1)) {
+   int left;
+   char __user *buf = i-iov-iov_base + i-iov_offset;
+   left = __copy_to_user(buf, from, bytes);
+   copied = bytes - left;
+   } else {
+   copied = __pram_iov_copy_to(from, i-iov, i-iov_offset, bytes);
+   }
+
+   return copied;
+}
+
+static size_t __pram_clear_user(const struct iovec *iov, size_t base, size_t 
bytes)
+{
+   size_t claened = 0, left = 0;
+
+   while (bytes) {
+   char __user *buf = iov-iov_base + base;
+   int clear = min(bytes, iov-iov_len - base);
+
+   base = 0;
+   left = __clear_user(buf, clear);
+   claened += clear;
+   bytes -= clear;
+   iov++;
+
+   if (unlikely(left))
+   break;
+   }
+   return claened - left;
+}
+
+static size_t pram_clear_user(struct iov_iter *i, size_t bytes)
+{
+   size_t clear;
+
+   if (likely(i-nr_segs == 1)) {
+   int left;
+   char __user *buf = i-iov-iov_base + i-iov_offset;
+   left = __clear_user(buf, bytes);
+   clear = bytes - left;
+   } else {
+   clear = __pram_clear_user(i-iov, i-iov_offset, bytes);
+   }
+
+   return clear;
+}
+
+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, alloc_once = 1;
+   ssize_t retval = 0;
+   void *tmp = NULL;
+   unsigned long blocknr, blockoff, blocknr_start;
+   struct iov_iter iter;
+   int num_blocks, blocksize_mask;
+  

[PATCH 06/17] pramfs: inode operations for directories

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Inode operations for directories.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/namei.c b/fs/pramfs/namei.c
new file mode 100644
index 000..bedc43a
--- /dev/null
+++ b/fs/pramfs/namei.c
@@ -0,0 +1,371 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Inode operations for directories.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/fs.h
+#include linux/pagemap.h
+#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 (unlikely(IS_ERR(inode))) {
+   if (PTR_ERR(inode) == -ESTALE) {
+   pram_err(dir-i_sb, deleted inode referenced: 
%lu,
+   (unsigned long) ino);
+   return ERR_PTR(-EIO);
+   } else {
+   return ERR_CAST(inode);
+   }
+   }
+   }
+
+   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,
+  

[PATCH 08/17] pramfs: headers

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Definitions for the PRAMFS filesystem.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/pram.h b/fs/pramfs/pram.h
new file mode 100644
index 000..85169c4
--- /dev/null
+++ b/fs/pramfs/pram.h
@@ -0,0 +1,269 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Definitions for the PRAMFS filesystem.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/buffer_head.h
+#include linux/pram_fs.h
+#include linux/pram_fs_sb.h
+#include linux/crc16.h
+#include linux/mutex.h
+#include linux/types.h
+#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)
+
+#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)
+
+/*
+ * Pram inode flags
+ *
+ * PRAM_EOFBLOCKS_FL   There are blocks allocated beyond eof
+ */
+#define PRAM_EOFBLOCKS_FL  0x2000
+/* Flags that should be inherited by new inodes from their parent. */
+#define PRAM_FL_INHERITED (FS_SECRM_FL | FS_UNRM_FL | FS_COMPR_FL |\
+  FS_SYNC_FL | FS_IMMUTABLE_FL | FS_APPEND_FL |\
+  FS_NODUMP_FL | FS_NOATIME_FL | FS_COMPRBLK_FL|\
+  FS_NOCOMP_FL | FS_JOURNAL_DATA_FL |\
+  FS_NOTAIL_FL | FS_DIRSYNC_FL)
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define PRAM_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
+/* Flags that are appropriate for non-directories/regular files. */
+#define PRAM_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
+
+/* 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);
+
+/* 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,
+   unsigned 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);
+extern long pram_fallocate(struct inode *inode, int mode, loff_t offset,
+ loff_t len);
+extern void pram_set_inode_flags(struct inode *inode, struct pram_inode *pi);
+extern void pram_get_inode_flags(struct inode *inode, struct pram_inode *pi);
+
+/* ioctl.c */
+extern long pram_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+extern long 

[PATCH 09/17] pramfs: dir operations

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

File operations for directories.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/dir.c b/fs/pramfs/dir.c
new file mode 100644
index 000..cf0bcba
--- /dev/null
+++ b/fs/pramfs/dir.c
@@ -0,0 +1,208 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * File operations for directories.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/fs.h
+#include linux/pagemap.h
+#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;
+   pram_memlock_inode(sb, next);
+   }
+

[PATCH 11/17] pramfs: ACL management

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

ACL operations.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/acl.c b/fs/pramfs/acl.c
new file mode 100644
index 000..53090a5
--- /dev/null
+++ b/fs/pramfs/acl.c
@@ -0,0 +1,433 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * POSIX ACL operations
+ *
+ * Copyright 2010 Marco Stornelli marco.storne...@gmail.com
+ *
+ * based on fs/ext2/acl.c with the following copyright:
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, agr...@suse.de
+ *
+ * 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 linux/capability.h
+#include linux/init.h
+#include linux/sched.h
+#include linux/slab.h
+#include linux/fs.h
+#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, 

[PATCH 12/17] pramfs: extended attributes

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Extended attributes operations.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/xattr.c b/fs/pramfs/xattr.c
new file mode 100644
index 000..44d158e
--- /dev/null
+++ b/fs/pramfs/xattr.c
@@ -0,0 +1,1104 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes operations.
+ *
+ * Copyright 2010 Marco Stornelli marco.storne...@gmail.com
+ *
+ * based on fs/ext2/xattr.c with the following copyright:
+ *
+ * Fix by Harrison Xing harri...@mountainviewdata.com.
+ * Extended attributes for symlinks and special files added per
+ *  suggestion of Luka Renko luka.re...@hermes.si.
+ * xattr consolidation Copyright (c) 2004 James Morris jmor...@redhat.com,
+ *  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 aligned 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 linux/module.h
+#include linux/init.h
+#include linux/mbcache.h
+#include linux/rwsem.h
+#include linux/security.h
+#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 

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

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Extended attributes block descriptors tree.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/desctree.c b/fs/pramfs/desctree.c
new file mode 100644
index 000..4508e70
--- /dev/null
+++ b/fs/pramfs/desctree.c
@@ -0,0 +1,181 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Extended attributes block descriptors tree.
+ *
+ * Copyright 2010 Marco Stornelli marco.storne...@gmail.com
+ *
+ * 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 linux/spinlock.h
+#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-node, sbi-desc_tree);
+   pram_dbg(erasing desc 

[PATCH 14/17] pramfs: memory protection

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Memory write protection.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/wprotect.c b/fs/pramfs/wprotect.c
new file mode 100644
index 000..d0f0508
--- /dev/null
+++ b/fs/pramfs/wprotect.c
@@ -0,0 +1,41 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Write protection for the filesystem pages.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/module.h
+#include linux/fs.h
+#include linux/mm.h
+#include linux/io.h
+#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 --git a/fs/pramfs/wprotect.h b/fs/pramfs/wprotect.h
new file mode 100644
index 000..0aa1e33
--- /dev/null
+++ b/fs/pramfs/wprotect.h
@@ -0,0 +1,151 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Memory protection definitions for the PRAMFS filesystem.
+ *
+ * Copyright 2010 Marco Stornelli marco.storne...@gmail.com
+ * 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
+
+#include linux/pram_fs.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,
+   struct pram_inode *pi)
+{
+   

[PATCH 15/17] pramfs: test module

2011-01-06 Thread Marco Stornelli
From: Marco Stornelli marco.storne...@gmail.com

Test module.

Signed-off-by: Marco Stornelli marco.storne...@gmail.com
---
diff --git a/fs/pramfs/pramfs_test.c b/fs/pramfs/pramfs_test.c
new file mode 100644
index 000..24e016f
--- /dev/null
+++ b/fs/pramfs/pramfs_test.c
@@ -0,0 +1,47 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Pramfs test module.
+ *
+ * Copyright 2009-2010 Marco Stornelli marco.storne...@gmail.com
+ * 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 linux/module.h
+#include linux/version.h
+#include linux/init.h
+#include linux/fs.h
+#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


Re: [PATCH 00/17] pramfs: persistent and protected RAM filesystem

2011-01-06 Thread Peter Zijlstra
On Thu, 2011-01-06 at 13:00 +0100, Marco Stornelli wrote:
 Hi all,
 
 after several reviews is time to submit the code for mainline. Thanks to
 CELF to believe and support actively the project and thanks to Tim Bird.

Tony Luck was also playing with something like this I believe.
--
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


Re: [PATCH 00/17] pramfs: persistent and protected RAM filesystem

2011-01-06 Thread Marco Stornelli
Il 06/01/2011 15:03, Peter Zijlstra ha scritto:
 On Thu, 2011-01-06 at 13:00 +0100, Marco Stornelli wrote:
 Hi all,

 after several reviews is time to submit the code for mainline. Thanks to
 CELF to believe and support actively the project and thanks to Tim Bird.
 
 Tony Luck was also playing with something like this I believe.
 

Yes, I know. Even if the approach is different. He is trying to use a
persistent space record-based and with a simple fs interface to store
oops or something like this. The idea here is a little bit different,
i.e. to have a place (a generic piece of memory) to write not sensible
and temporary information with a complete fs structure. However we are
on the same road :)

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


RE: [PATCH 00/17] pramfs: persistent and protected RAM filesystem

2011-01-06 Thread Luck, Tony
 Errata corrige: maybe I used the wrong term, I meant volatile instead
 of temporary information, i.e. I'd like to save this info to re-read
 it later but I don't want to store it in flash, a simple log, run-time
 information for debug like a flight-recorder or whatever you want.

I'm puzzled by the use of a generic piece of memory to store persistent
things (Perhaps this is made clear in the 17 parts of the patch? I haven't
read them yet).  On x86 f/w typically clears all of memory on reset ... so
you only get persistence if you use kexec to get from the old kernel to
the new one.

-Tony
--
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


Re: [PATCH 00/17] pramfs: persistent and protected RAM filesystem

2011-01-06 Thread Marco Stornelli
Il 06/01/2011 19:22, Luck, Tony ha scritto:
 Errata corrige: maybe I used the wrong term, I meant volatile instead
 of temporary information, i.e. I'd like to save this info to re-read
 it later but I don't want to store it in flash, a simple log, run-time
 information for debug like a flight-recorder or whatever you want.
 
 I'm puzzled by the use of a generic piece of memory to store persistent
 things (Perhaps this is made clear in the 17 parts of the patch? I haven't
 read them yet).  On x86 f/w typically clears all of memory on reset ... so
 you only get persistence if you use kexec to get from the old kernel to
 the new one.
 
 -Tony
 

First of all, you can find a lot of information on the web site where
there is an overview and a page with implementation details, benchmark
and so on. With a generic piece of memory I mean a generic memory
device directly addressable. Usually this generic device is an NVRAM, so
we have a persistent store. If you haven't got this hw you can use other
devices or the classic RAM, in this case you have a fs persistent only
over reboot. The use of this fs is mainly for embedded systems, fw can
be configured to not clear *all* the memory. Pramfs is indeed supported
by U-Boot, you can see CONFIG_PRAM in the Das U-Boot manual. x86 in this
case can be a strange world for this fs, but however if the user wants
it can be used without problems because there aren't neither strict arch
or hw dependency.

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


Re: [PATCH] Move an assert under DEBUG_KERNEL.

2011-01-06 Thread Andrew Morton
On Thu, 6 Jan 2011 02:13:38 -0600
Rob Landley rland...@parallels.com wrote:

 From: Rob Landley rland...@parallels.com
 
 Move an assert under DEBUG_KERNEL.
 
 Signed-off-by: Rob Landley rland...@parallels.com
 ---
 
 Saves about 3k from x86-64 defconfig according to scripts/bloat-o-meter.
 
   include/linux/rtnetlink.h |4 
   1 file changed, 4 insertions(+)
 
 diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
 index bbad657..28c4025 100644
 --- a/include/linux/rtnetlink.h
 +++ b/include/linux/rtnetlink.h
 @@ -782,6 +782,7 @@ extern struct netdev_queue 
 *dev_ingress_queue_create(struct net_device *dev);
   extern void rtnetlink_init(void);
   extern void __rtnl_unlock(void);
 
 +#ifdef CONFIG_DEBUG_KERNEL
   #define ASSERT_RTNL() do { \
   if (unlikely(!rtnl_is_locked())) { \
   printk(KERN_ERR RTNL: assertion failed at %s (%d)\n, \
 @@ -789,6 +790,9 @@ extern void __rtnl_unlock(void);
   dump_stack(); \
   } \
   } while(0)
 +#else
 +#define ASSERT_RTNL()
 +#endif
 
   static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
   {

Probably a worthwhile thing to do, IMO.  If there's some net-specific
CONFIG_DEBUG_ setting then that wold be a better thing to use.

However the patch was a) wordwrapped, b) space-stuffed and c) not cc'ed
to the networking list.  So its prospects are dim.
--
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