[PATCH 01/16 v4] pramfs: documentation
From: Marco Stornelli marco.storne...@gmail.com Documentation for PRAMFS. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-10-23 09:04:32.0 +0200 @@ -0,0 +1,296 @@ + +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
[PATCH 03/26 v4] pramfs: inode operations
From: Marco Stornelli marco.storne...@gmail.com Inode methods (allocate/free/read/write). Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-26 18:04:38.0 +0200 @@ -0,0 +1,710 @@ +/* + * FILE NAME fs/pramfs/inode.c + * + * 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/quotaops.h +#include linux/module.h +#include linux/mpage.h +#include linux/backing-dev.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(pi); + pi-i_blocks = cpu_to_be32(inode-i_blocks); + pram_memlock_inode(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, int 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; + int i_row, i_col; + int N = sb-s_blocksize 3; /* num block ptrs per block */ + 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) { +
[PATCH 04/16 v4] pramfs: file operations
From: Marco Stornelli marco.storne...@gmail.com File operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-24 18:34:03.0 +0200 @@ -0,0 +1,166 @@ +/* + * FILE NAME fs/pramfs/file.c + * + * 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 + +static int pram_open_file(struct inode *inode, struct file *filp) +{ +#ifndef CONFIG_PRAMFS_XIP + /* Without XIP we force to use Direct IO */ + filp-f_flags |= O_DIRECT; +#endif + 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: +
[PATCH 05/16 v4] pramfs: block allocation
From: Marco Stornelli marco.storne...@gmail.com Block allocation operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-26 18:05:06.0 +0200 @@ -0,0 +1,149 @@ +/* + * FILE NAME fs/pramfs/balloc.c + * + * BRIEF MODULE DESCRIPTION + * + * The blocks allocation and deallocation routines. + * + * 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/bitops.h +#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_set(bitmap, 0, 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(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(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_err(no free blocks found!\n); + errval = -ENOSPC; + goto fail; + } + + pram_dbg(allocating blocknr %lu\n, bnr); + pram_memunlock_super(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(ps); + } else { + pram_err(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: +
[PATCH 06/16 v4] pramfs: Inode operations for directories
From: Marco Stornelli marco.storne...@gmail.com Inode operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-18 12:00:35.0 +0200 @@ -0,0 +1,363 @@ +/* + * FILE NAME fs/pramfs/namei.c + * + * 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 + +/* + * 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; + 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); + if (IS_ERR(inode)) + goto out; + + inode-i_op = pram_symlink_inode_operations; + inode-i_mapping-a_ops = pram_aops; + +
[PATCH 07/16 v4] pramfs: symbolic links
From: Marco Stornelli marco.storne...@gmail.com Symlink operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,78 @@ +/* + * FILE NAME fs/pramfs/symlink.c + * + * BRIEF DESCRIPTION + * + * Symlink 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/fs.h +#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 08/16 v4] pramfs: headers
From: Marco Stornelli marco.storne...@gmail.com Definitions for the PRAMFS filesystem. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-10-30 12:02:45.0 +0200 @@ -0,0 +1,317 @@ +/* + * FILE NAME pram.h + * + * 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 + +/* + * Debug code + */ +#define pram_dbg(s, args...) pr_debug(PRAMFS: s, ## args) +#define pram_err(s, args...) pr_err(PRAMFS: s, ## args) +#define pram_warn(s, args...) pr_warning(PRAMFS: s, ## args) +#define pram_info(s, args...) pr_info(PRAMFS: s, ## args) + +/* Function Prototypes */ + +#ifdef CONFIG_PRAMFS_XIP + +#define pram_read xip_file_read +#define pram_write xip_file_write +#define pram_mmap xip_file_mmap +#define pram_aio_read NULL +#define pram_aio_write NULL +#define pram_readpage NULL +#define pram_direct_IO NULL + +#else + +#define pram_read do_sync_read +#define pram_write do_sync_write +#define pram_mmap __pram_mmap +#define pram_aio_read generic_file_aio_read +#define pram_aio_write generic_file_aio_write +#define pram_direct_IO __pram_direct_IO +#define pram_readpage __pram_readpage + +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); + +#endif /* CONFIG_PRAMFS_XIP */ + +#define pram_set_bit ext2_set_bit +#define pram_clear_bit ext2_clear_bit +#define pram_find_next_zero_bitext2_find_next_zero_bit + +/* 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, +int 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); + + +#ifdef CONFIG_PRAMFS_WRITE_PROTECT +extern void pram_writeable(void *vaddr, unsigned long size, int rw); + +#define wrprotect(addr, size) pram_writeable(addr, size, 0) + +#else + +#define wrprotect(addr, size) do {} while (0) + +#endif /* CONFIG PRAMFS_WRITE_PROTECT */ + +/* Inline functions start here */ + +static inline int pram_calc_checksum(u8 *data, int n) +{ + u16 crc = 0; + crc = crc16(~0, (__u8 *)data +
[PATCH 09/16 v4] pramfs: dir operations
From: Marco Stornelli marco.storne...@gmail.com File operations for directories. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-17 19:08:54.0 +0200 @@ -0,0 +1,215 @@ +/* + * FILE NAME fs/pramfs/dir.c + * + * 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 = dentry-d_name.len PRAM_NAME_LEN ? + PRAM_NAME_LEN : dentry-d_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(pitail); + pitail-i_d.d_next = cpu_to_be64(inode-i_ino); + pram_memlock_inode(pitail); + + prev_ino = tail_ino; + + pram_memunlock_inode(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(pidir); + } else { + /* the directory is empty */ + prev_ino = 0; + + pram_memunlock_inode(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(pidir); + } + + + pram_memunlock_inode(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(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(next); + next-i_d.d_prev = 0; + pram_memlock_inode(next); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = pi-i_d.d_next; + } else { + pram_memunlock_inode(pidir); + pidir-i_type.dir.head = 0; + pidir-i_type.dir.tail = 0; + } + pram_memlock_inode(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(prev); + prev-i_d.d_next = 0; + pram_memlock_inode(prev); + + pram_memunlock_inode(pidir); + pidir-i_type.dir.tail = pi-i_d.d_prev; + pram_memlock_inode(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(prev); + prev-i_d.d_next = pi-i_d.d_next; + pram_memlock_inode(prev); + + pram_memunlock_inode(next); + next-i_d.d_prev = pi-i_d.d_prev; +
[PATCH 10/16 v4] pramfs: xip operations
From: Marco Stornelli marco.storne...@gmail.com XIP operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,90 @@ +/* + * FILE NAME fs/pramfs/xip.c + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-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/mm.h +#include linux/fs.h +#include linux/genhd.h +#include linux/buffer_head.h +#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 int __pram_get_block(struct inode *inode, pgoff_t pgoff, int create, + sector_t *result) +{ + int rc = 0; + sector_t iblock; + + /* find starting block number to access */ + iblock = (sector_t)pgoff (PAGE_CACHE_SHIFT - inode-i_blkbits); + + rc = pram_find_and_alloc_blocks(inode, iblock, 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,24 @@ +/* + * FILE NAME fs/pramfs/xip.h + * + * BRIEF DESCRIPTION + * + * XIP operations. + * + * Copyright 2009-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. + */ + +#ifdef CONFIG_PRAMFS_XIP + +int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **, + unsigned long *); + +#else + +#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 11/16 v4] pramfs: ACL management
From: Marco Stornelli marco.storne...@gmail.com ACL operations. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,418 @@ +/* + * FILE NAME fs/pramfs/acl.c + * + * BRIEF MODULE 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
[PATCH 13/16 v4] pramfs: xattr block descriptors tree
From: Marco Stornelli marco.storne...@gmail.com Extended attributes block descriptors tree. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,183 @@ +/* + * FILE NAME fs/pramfs/desctree.c + * + * 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)) { +
[PATCH 14/16 v4] pramfs: write protection
From: Marco Stornelli marco.storne...@gmail.com Memory write protection. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-10-30 11:59:54.0 +0200 @@ -0,0 +1,41 @@ +/* + * FILE NAME fs/pramfs/wprotect.c + * + * 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 + +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); +} -- 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 15/16 v4] pramfs: test module
From: Marco Stornelli marco.storne...@gmail.com Test module. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-09-14 18:49:52.0 +0200 @@ -0,0 +1,49 @@ +/* + * FILE NAME fs/pramfs/pramfs_test.c + * + * 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
[PATCH 16/16 v4] pramfs: makefile and Kconfig
From: Marco Stornelli marco.storne...@gmail.com Makefile and Kconfig. Signed-off-by: Marco Stornelli marco.storne...@gmail.com --- 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-10-30 10:30:19.0 +0200 @@ -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 file:Documentation/filesystems/pramfs.txt. + + To compile this as a module, choose M here: the module will be + called pramfs. + +config PRAMFS_XIP + bool Enable Execute-in-place in PRAMFS + depends on PRAMFS !PRAMFS_WRITE_PROTECT + help + Say Y here to enable XIP feature of PRAMFS. + +config PRAMFS_WRITE_PROTECT + bool Enable 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 + http://acl.bestbits.at/ 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 http://acl.bestbits.at/. + + 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/fs/pramfs/Makefile linux-2.6.36/fs/pramfs/Makefile --- linux-2.6.36-orig/fs/pramfs/Makefile1970-01-01 01:00:00.0 +0100 +++ linux-2.6.36/fs/pramfs/Makefile 2010-09-14 18:49:52.0 +0200 @@ -0,0 +1,14 @@ +# +# Makefile for the