* Re: [PATCH 04/14] Pramfs: Mounting as root filesystem
From: Arnd Bergmann @ 2009-06-13 23:04 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel, Daniel Walker
In-Reply-To: <4A33A7D7.3040008@gmail.com>
On Saturday 13 June 2009, Marco wrote:
> void __init mount_root(void)
> {
> +#ifdef CONFIG_ROOT_PRAMFS
> + if (MAJOR(ROOT_DEV) == MEM_MAJOR) {
> + if (mount_pramfs_root())
> + return;
> +
> + printk(KERN_ERR "VFS: Unable to mount root fs via PRAMFS, trying floppy.\n");
> + ROOT_DEV = Root_FD0;
> + }
> +#endif
AFAICT, this will prevent booting from /dev/ram0 with a regular file system,
because that also uses MAJOR(ROOT_DEV) == 1.
Arnd <><
^ permalink raw reply
* Re: [PATCH 06/14] Pramfs: Include files
From: Arnd Bergmann @ 2009-06-13 22:59 UTC (permalink / raw)
To: Sam Ravnborg
Cc: Marco, Linux FS Devel, Linux Embedded, Linux Kernel,
Daniel Walker
In-Reply-To: <20090613140459.GC30053@uranus.ravnborg.org>
On Saturday 13 June 2009, Sam Ravnborg wrote:
> > + union {
> > + struct {
> > + /*
> > + * ptr to row block of 2D block pointer array,
> > + * file block #'s 0 to (blocksize/4)^2 - 1.
> > + */
> > + off_t row_block;
>
> It is my understanding that we shall use: __kernel_off_t
> in exported headers.
That is a correct understanding in general, however this case is
different, because it describes an on-disk data structure,
not a kernel to user space interface. Here, __kernel_off_t is just
as wrong as off_t, because it will differ between 32 and 64 bit
architectures, making the fs layout incompatible. I'd suggest
simply defining this as __u64.
Moreover, file system layout should be described in terms of
big-endian or little-endian types (e.g. __be64 or __le64),
together with the right accessor functions.
Arnd <><
^ permalink raw reply
* Re: Kernel crashing and log buffers...
From: Wolfgang Denk @ 2009-06-13 18:59 UTC (permalink / raw)
To: Russell King
Cc: Robin Getz, Mike Frysinger, Greg Ungerer, Paul Mundt, Tim Bird,
Grant Erickson, linux-embedded
In-Reply-To: <20090613102642.GB7976@flint.arm.linux.org.uk>
Dear Russell King,
In message <20090613102642.GB7976@flint.arm.linux.org.uk> you wrote:
>
> The other way I've seen people read out crash messages is using a
> debugger to dump the kernel's log buffer directly. That seems to work
> as well as any other method, and has the advantage that it doesn't
> require any kernel modifications.
This works well in the lab during hardware bringup or BSP development.
But we are also interested in a solution that allows to get more or
less automatic access to the log buffer content after a crash - when
you have several ten thousand systems in the field, such a feature
can save you a lot of money.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
^ permalink raw reply
* Re: [PATCH 1/2] MMC Agressive clocking framework v2
From: Pierre Ossman @ 2009-06-13 18:27 UTC (permalink / raw)
To: Linus Walleij; +Cc: linux-arm-kernel, linux-embedded, Linus Walleij
In-Reply-To: <63386a3d0906130545i4d2227a2h25e9b55df6954a1@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 905 bytes --]
On Sat, 13 Jun 2009 14:45:09 +0200
Linus Walleij <linus.ml.walleij@gmail.com> wrote:
> 2009/6/2 Linus Walleij <linus.ml.walleij@gmail.com>:
>
> > This patch modified the MMC core code to optionally call the
> > set_ios() operation on the driver with the clock frequency set
> > to 0 to gate the hardware block clock (and thus the MCI clock)
>
> have you had a chance to look at this for the current merge
> window Pierre?
>
Not yet, but I plan to. Sorry about the delay.
Rgds
--
-- Pierre Ossman
Linux kernel, MMC maintainer http://www.kernel.org
rdesktop, core developer http://www.rdesktop.org
TigerVNC, core developer http://www.tigervnc.org
WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: Kernel crashing and log buffers...
From: Jamie Lokier @ 2009-06-13 16:49 UTC (permalink / raw)
To: Robin Getz
Cc: David VomLehn, Mike Frysinger, Greg Ungerer, Russell King,
Paul Mundt, Tim Bird, Wolfgang Denk, Grant Erickson,
linux-embedded
In-Reply-To: <200906120054.46965.rgetz@blackfin.uclinux.org>
Robin Getz wrote:
> - late crash analysis - Sometimes - even after the kernel is up
> and running properly - a device driver does a bad thing.
> Normally - complete kernel dumps can come out a serial
> console, and you can you your favourite serial application
> to scroll back and determine what is going on.
>
> In many embedded devices - this is not a possibility, since
> all the serial ports are in use (Irda, Bluetooth, GPS, etc).
There's another thing with serial ports:
In embedded devices, I've seen serial drivers hooked up to the console
output either synchronously or asynchronously.
Synchronously, every printk() waits to be sent to the serial port, and
this slows the kernel down in normal operation, and especially boot
time.
Asynchronously, every printk() does into the log buffer without delay,
and is sent over the serial port as fast as that can. It doesn't slow
the kernel down much.
When it's done asynchronously, if the kernel crashes you don't always
get the last output prior to the crash, even with a serial terminal
listening in your lab. But if you do it synchronously, it slows
things down.
-- Jamie
^ permalink raw reply
* Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
From: Jamie Lokier @ 2009-06-13 15:59 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, linux-kernel, Daniel Walker
In-Reply-To: <4A33A7A2.1050608@gmail.com>
Marco wrote:
> 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.
Why is a ramdisk not sufficient for this?
Why is an entire filesystem needed, instead of simply a block driver
if the ramdisk driver cannot be used?
It just struck me as a lot of code which might be completely
unnecessary for the desired functionality.
-- Jamie
^ permalink raw reply
* Re: [PATCH 14/14] Pramfs: XIP operations
From: Sam Ravnborg @ 2009-06-13 14:06 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel, Daniel Walker
In-Reply-To: <4A33A841.6080902@gmail.com>
On Sat, Jun 13, 2009 at 03:23:13PM +0200, Marco wrote:
> From: Marco Stornelli <marco.stornelli@gmail.com>
>
> XIP operations.
>
> Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
> ---
>
> diff -uprN linux-2.6.30-orig/fs/pramfs/xip.c linux-2.6.30/fs/pramfs/xip.c
> --- linux-2.6.30-orig/fs/pramfs/xip.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.30/fs/pramfs/xip.c 2009-06-13 12:54:26.000000000 +0200
> @@ -0,0 +1,90 @@
> +/*
> + * FILE NAME fs/pramfs/xip.c
> + *
> + * BRIEF DESCRIPTION
> + *
> + * XIP operations.
> + *
> + * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.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;
> + off_t block;
> +
> + lock_kernel();
Can we find other solutions than taking the BKL?
We are trying to get rid of it.
> +
> + 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:
> + unlock_kernel();
> + return err;
> +}
> +
^ permalink raw reply
* Re: [PATCH 06/14] Pramfs: Include files
From: Sam Ravnborg @ 2009-06-13 14:04 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel, Daniel Walker
In-Reply-To: <4A33A7EC.6070008@gmail.com>
On Sat, Jun 13, 2009 at 03:21:48PM +0200, Marco wrote:
> From: Marco Stornelli <marco.stornelli@gmail.com>
>
> Include files.
>
> Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
> ---
>
> diff -uprN linux-2.6.30-orig/fs/pramfs/pram_fs.h linux-2.6.30/fs/pramfs/pram_fs.h
> --- linux-2.6.30-orig/fs/pramfs/pram_fs.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.30/fs/pramfs/pram_fs.h 2009-06-13 12:58:49.000000000 +0200
> @@ -0,0 +1,388 @@
> +/*
> + * FILE NAME include/linux/pram_fs.h
> + *
> + * BRIEF DESCRIPTION
> + *
> + * Definitions for the PRAMFS filesystem.
> + *
> + * Copyright 2009 Marco Stornelli <marco.stornelli@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 _LINUX_PRAM_FS_H
> +#define _LINUX_PRAM_FS_H
> +
> +#include <linux/types.h>
> +
> +#ifdef __KERNEL__
> +#include <linux/sched.h>
> +#include <linux/buffer_head.h>
> +#include "pram_fs_sb.h"
> +#endif
The only reason to have this header file in include/linux/
is that it is used by userspace.
So please split it up so we have one header suitable for exporting
and another header with all the promfs local stuff.
The latter should be in fs/pramsfs/
> +
> +/*
> + * The PRAM filesystem constants/structures
> + */
> +
> +/*
> + * Define PRAMFS_DEBUG to produce debug messages
> + */
> +#define PRAMFS_DEBUG
> +
> +/*
> + * Debug code
> + */
> +#ifdef __KERNEL__
> +#define PFX "pramfs"
> +#ifdef PRAMFS_DEBUG
> +#define pram_dbg(format, arg...) \
> + printk(KERN_DEBUG PFX ": " format , ## arg)
> +#else
> +#define pram_dbg(format, arg...) do {} while (0)
> +#endif
> +#define pram_err(format, arg...) \
> + printk(KERN_ERR PFX ": " format , ## arg)
> +#define pram_info(format, arg...) \
> + printk(KERN_INFO PFX ": " format , ## arg)
> +#define pram_warn(format, arg...) \
> + printk(KERN_WARNING PFX ": " format , ## arg)
> +#endif
For a typical drivers we have some pr_* to avoid the above.
Can they be used for a filesystem too?
> +
> +/*
> + * The PRAM file system magic number
> + */
> +#define PRAM_SUPER_MAGIC 0xEFFA
Move to include/linux/magic.h
> +
> +/*
> + * Structure of an inode in PRAMFS
> + */
> +struct pram_inode {
> + __u32 i_sum; /* checksum of this inode */
> + __u32 i_uid; /* Owner Uid */
> + __u32 i_gid; /* Group Id */
> + __u16 i_mode; /* File mode */
> + __u16 i_links_count; /* Links count */
> + __u32 i_blocks; /* Blocks count */
> + __u32 i_size; /* Size of data in bytes */
> + __u32 i_atime; /* Access time */
> + __u32 i_ctime; /* Creation time */
> + __u32 i_mtime; /* Modification time */
> + __u32 i_dtime; /* Deletion Time */
> +
> + union {
> + struct {
> + /*
> + * ptr to row block of 2D block pointer array,
> + * file block #'s 0 to (blocksize/4)^2 - 1.
> + */
> + off_t row_block;
It is my understanding that we shall use: __kernel_off_t
in exported headers.
The headers are not added to Kbuild - so it is not exported.
I assume thats an oversight.
Sam
^ permalink raw reply
* Re: [PATCH 08/14] Pramfs: Makefile and Kconfig
From: Daniel Walker @ 2009-06-13 14:02 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel
In-Reply-To: <4A33A802.8040507@gmail.com>
On Sat, 2009-06-13 at 15:22 +0200, Marco wrote:
> From: Marco Stornelli <marco.stornelli@gmail.com>
>
> Makefile and Kconfig.
>
> Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
> ---
>
You should move this patch to 11 of 14, as I think that is the point
when the filesystem can actually be enabled and function. If this series
is only applied up to this patch you can get build failures if you
enabled PRAMFS, XIP, or any of the other features. Also breaking out the
individual features menuconfig options like XIP, and write protect, etc,
into their respective patches would be nice.
Daniel
^ permalink raw reply
* Re: [PATCH 08/14] Pramfs: Makefile and Kconfig
From: Sam Ravnborg @ 2009-06-13 13:56 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel, Daniel Walker
In-Reply-To: <4A33A802.8040507@gmail.com>
> +
> +config PRAMFS_NOWP
> + bool "Disable PRAMFS write protection"
> + depends on PRAMFS
> + default n
> + help
> + Say Y here to disable the write protect feature of PRAMFS.
n is default so "default n" is not needed.
If you reverse the logic (and add a default y) then..
> +ifneq ($(CONFIG_PRAMFS_NOWP),y)
> +pramfs-objs += wprotect.o
> +endif
This is a trivial:
pramfs-$(PRAMFS_WRITE_PROTECT) += wprotect.o
(I renamed the option to something more descriptive - please do so in the abvoe).
> +++ linux-2.6.30/fs/pramfs/Makefile 2009-04-19 11:58:51.000000000 +0200
> @@ -0,0 +1,13 @@
> +#
> +# Makefile for the linux pram-filesystem routines.
> +#
> +
> +obj-$(CONFIG_PRAMFS) += pramfs.o
> +obj-$(CONFIG_TEST_MODULE) += pramfs_test.o
> +
> +pramfs-objs := balloc.o dir.o file.o inode.o namei.o super.o symlink.o
Use:
pramfs-y := balloc.o ...
This match usa later in this file.
> +
> +ifneq ($(CONFIG_PRAMFS_NOWP),y)
> +pramfs-objs += wprotect.o
> +endif
> +pramfs-$(CONFIG_PRAMFS_XIP) += xip.o
Sam
^ permalink raw reply
* Re: [PATCH 05/14] Pramfs: File operations for files
From: Daniel Walker @ 2009-06-13 13:47 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, Linux Kernel
In-Reply-To: <4A33A7E2.9020803@gmail.com>
On Sat, 2009-06-13 at 15:21 +0200, Marco wrote:
> From: Marco Stornelli <marco.stornelli@gmail.com>
>
> File operations for files.
>
> Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
> ---
>
> diff -uprN linux-2.6.30-orig/fs/pramfs/file.c linux-2.6.30/fs/pramfs/file.c
> --- linux-2.6.30-orig/fs/pramfs/file.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.30/fs/pramfs/file.c 2009-06-13 12:52:56.000000000 +0200
> @@ -0,0 +1,141 @@
> +/*
> + * FILE NAME fs/pramfs/file.c
> + *
> + * BRIEF DESCRIPTION
> + *
> + * File operations for files.
> + *
> + * Copyright 2009 Marco Stornelli <marco.stornelli@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/uaccess.h>
> +#include "pram_fs.h"
> +#include "xip.h"
It would be cleaner if the xip.h include was added in patch 14 of 14,
since that's the XIP support patch.
> +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
Same as above .. It's better to have all the support for a given feature
all in the same patch. The rest of your patches are dotted with these
bits of code that should really be refactored into other patches.
Daniel
^ permalink raw reply
* Re: [PATCH 00/14] Pramfs: Persistent and protected ram filesystem
From: Daniel Walker @ 2009-06-13 13:41 UTC (permalink / raw)
To: Marco; +Cc: Linux FS Devel, Linux Embedded, linux-kernel
In-Reply-To: <4A33A7A2.1050608@gmail.com>
On Sat, 2009-06-13 at 15:20 +0200, Marco wrote:
> Are there any pending patents on this code?
>
> NO, there aren't patents pending on this code. MontaVista had a pending
> patent application but now it has abandoned this way. Daniel Walker can
> confirm that.
Confirmed , there are no patents on this code.
Daniel
^ permalink raw reply
* [PATCH 14/14] Pramfs: XIP operations
From: Marco @ 2009-06-13 13:23 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
XIP operations.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/xip.c linux-2.6.30/fs/pramfs/xip.c
--- linux-2.6.30-orig/fs/pramfs/xip.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/xip.c 2009-06-13 12:54:26.000000000 +0200
@@ -0,0 +1,90 @@
+/*
+ * FILE NAME fs/pramfs/xip.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * XIP operations.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.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;
+ off_t block;
+
+ lock_kernel();
+
+ 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:
+ unlock_kernel();
+ 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 -uprN linux-2.6.30-orig/fs/pramfs/xip.h linux-2.6.30/fs/pramfs/xip.h
--- linux-2.6.30-orig/fs/pramfs/xip.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/xip.h 2009-03-28 14:59:13.000000000 +0100
@@ -0,0 +1,25 @@
+/*
+ * FILE NAME fs/pramfs/xip.h
+ *
+ * BRIEF DESCRIPTION
+ *
+ * XIP operations.
+ *
+ * Author: Marco Stornelli <marco.stornelli@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
+
^ permalink raw reply
* [PATCH 13/14] Pramfs: Write protection
From: Marco @ 2009-06-13 13:23 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Write protection.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/wprotect.c linux-2.6.30/fs/pramfs/wprotect.c
--- linux-2.6.30-orig/fs/pramfs/wprotect.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/wprotect.c 2009-06-13 12:54:16.000000000 +0200
@@ -0,0 +1,84 @@
+/*
+ * FILE NAME fs/pramfs/wprotect.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Write protection for the filesystem pages.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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 <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include "pram_fs.h"
+
+/* init_mm.page_table_lock must be held before calling! */
+static void pram_page_writeable(unsigned long addr, int rw)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ pgdp = pgd_offset_k(addr);
+ if (!pgd_none(*pgdp)) {
+ pudp = pud_offset(pgdp, addr);
+ if (!pud_none(*pudp)) {
+ pmdp = pmd_offset(pudp, addr);
+ if (!pmd_none(*pmdp)) {
+ pte_t pte;
+ ptep = pte_offset_kernel(pmdp, addr);
+ pte = *ptep;
+ if (pte_present(pte)) {
+ pte = rw ? pte_mkwrite(pte) :
+ pte_wrprotect(pte);
+ set_pte(ptep, pte);
+ }
+ }
+ }
+ }
+}
+
+/* init_mm.page_table_lock must be held before calling! */
+void pram_writeable(void *vaddr, unsigned long size, int rw)
+{
+ unsigned long addr = (unsigned long)vaddr & PAGE_MASK;
+ unsigned long end = (unsigned long)vaddr + size;
+ unsigned long start = addr;
+
+ do {
+ pram_page_writeable(addr, rw);
+ addr += PAGE_SIZE;
+ } while (addr && (addr < end));
+
+
+ /*
+ * NOTE: we will always flush just one page (one TLB
+ * entry) except possibly in one case: when a new
+ * filesystem is initialized at mount time, when pram_read_super
+ * calls pram_lock_range to make the super block, inode
+ * table, and bitmap writeable.
+ */
+#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_H8300) || \
+ defined(CONFIG_BLACKFIN)
+ /*
+ * FIXME: so far only these archs have flush_tlb_kernel_page(),
+ * for the rest just use flush_tlb_kernel_range(). Not ideal
+ * to use _range() because many archs just flush the whole TLB.
+ */
+ if (end <= start + PAGE_SIZE)
+ flush_tlb_kernel_page(start);
+ else
+#endif
+ flush_tlb_kernel_range(start, end);
+}
^ permalink raw reply
* [PATCH 12/14] Pramfs: test module
From: Marco @ 2009-06-13 13:22 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Test module.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/pramfs_test.c linux-2.6.30/fs/pramfs/pramfs_test.c
--- linux-2.6.30-orig/fs/pramfs/pramfs_test.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/pramfs_test.c 2009-06-13 13:07:38.000000000 +0200
@@ -0,0 +1,50 @@
+/*
+ * FILE NAME fs/pramfs/namei.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Inode operations for directories.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.h"
+
+int __init test_pramfs_write(void)
+{
+ struct pram_super_block *psb;
+ char *ptr;
+
+ 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 all information in the superblock,
+ * this should cause a kernel page protection fault.
+ */
+ printk("%s: writing to kernel VA %p\n", __func__, psb);
+ memset(psb, 0 , PRAM_SB_SIZE);
+
+ return 0;
+}
+
+void test_pramfs_write_cleanup(void) {}
+
+/* Module information */
+MODULE_LICENSE("GPL");
+module_init(test_pramfs_write);
+module_exit(test_pramfs_write_cleanup);
^ permalink raw reply
* [PATCH 11/14] Pramfs: Symbolic link operations
From: Marco @ 2009-06-13 13:22 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Symbolic link operations.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/symlink.c linux-2.6.30/fs/pramfs/symlink.c
--- linux-2.6.30-orig/fs/pramfs/symlink.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/symlink.c 2009-06-13 12:54:07.000000000 +0200
@@ -0,0 +1,73 @@
+/*
+ * FILE NAME fs/pramfs/symlink.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Symlink operations
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.h"
+
+int pram_block_symlink(struct inode *inode, const char *symname, int len)
+{
+ struct super_block *sb = inode->i_sb;
+ off_t block;
+ char *blockp;
+ int err;
+ unsigned long flags;
+
+ flags = 0;
+
+ 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_lock_block(sb, blockp, flags);
+ memcpy(blockp, symname, len);
+ blockp[len] = '\0';
+ pram_unlock_block(sb, blockp, flags);
+ 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;
+ off_t 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,
+};
^ permalink raw reply
* [PATCH 10/14] Pramfs: Superblock operations
From: Marco @ 2009-06-13 13:22 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Superblock operations.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/super.c linux-2.6.30/fs/pramfs/super.c
--- linux-2.6.30-orig/fs/pramfs/super.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/super.c 2009-06-13 13:07:53.000000000 +0200
@@ -0,0 +1,580 @@
+/*
+ * FILE NAME fs/pramfs/super.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Super block operations.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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 "pram_fs.h"
+
+static struct super_operations pram_sops;
+
+#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
+
+static void pram_set_blocksize(struct super_block *sb, unsigned long size)
+{
+ int bits;
+
+ /*
+ * We've already validated the user input and the value here must be
+ * between PRAM_MAX_BLOCK_SIZE and PRAM_MIN_BLOCK_SIZE
+ * and it must be a power of 2.
+ */
+ bits = fls(size) - 1;
+ sb->s_blocksize_bits = bits;
+ sb->s_blocksize = (1<<bits);
+}
+
+static inline void *pram_ioremap(phys_addr_t phys_addr, size_t size)
+{
+ 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)
+ wrprotect(retval, size);
+fail:
+ return retval;
+}
+
+enum {
+ Opt_addr, Opt_bpi, Opt_size,
+ Opt_num_inodes, Opt_mode, Opt_uid,
+ Opt_gid, Opt_blocksize, 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_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 != ',') {
+ pram_err("Invalid phys addr specification: %s\n",
+ (char *) *data);
+ return (phys_addr_t)ULLONG_MAX;
+ }
+ if (phys_addr & (PAGE_SIZE - 1)) {
+ pram_err("physical address 0x%16llx for pramfs isn't "
+ "aligned to a page boundary\n",
+ (u64)phys_addr);
+ return (phys_addr_t)ULLONG_MAX;
+ }
+ if (*options == ',')
+ options++;
+ *data = (void *) options;
+ return phys_addr;
+}
+
+static int pram_parse_options(char *options, struct pram_sb_info *sbi)
+{
+ char *p, *rest;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
+
+ if (!options)
+ return 0;
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_addr: {
+ /* physaddr managed in get_phys_addr() */
+ break;
+ }
+ case Opt_bpi: {
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ sbi->bpi = option;
+ break;
+ }
+ case Opt_uid: {
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ sbi->uid = option;
+ break;
+ }
+ case Opt_gid: {
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ sbi->gid = option;
+ break;
+ }
+ case Opt_mode: {
+ if (match_octal(&args[0], &option))
+ goto bad_val;
+ sbi->mode = option & 01777U;
+ break;
+ }
+ case Opt_size: {
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ sbi->initsize = memparse(args[0].from, &rest);
+ break;
+ }
+ case Opt_num_inodes: {
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ sbi->num_inodes = option;
+ break;
+ }
+ case Opt_blocksize: {
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ sbi->blocksize = memparse(args[0].from, &rest);
+ if (sbi->blocksize < PRAM_MIN_BLOCK_SIZE ||
+ sbi->blocksize > PRAM_MAX_BLOCK_SIZE ||
+ !is_power_of_2(sbi->blocksize))
+ goto bad_val;
+ break;
+ }
+ default: {
+ pram_err("Bad mount option: \"%s\"\n", p);
+ return -EINVAL;
+ break;
+ }
+ }
+ }
+
+ return 0;
+
+bad_val:
+ pram_err("Bad value '%s' for mount option '%s'\n", args[0].from, p);
+ return -EINVAL;
+}
+
+static struct pram_inode *pram_init(struct super_block *sb, unsigned long size)
+{
+ unsigned long bpi, num_inodes, bitmap_size, blocksize, num_blocks;
+ off_t bitmap_start;
+ struct pram_inode *root_i;
+ struct pram_super_block *super;
+ struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+ unsigned long flags;
+
+ flags = 0;
+
+ pram_info("creating an empty pramfs of size %lu\n", size);
+#ifdef CONFIG_PRAMFS_XIP
+ pram_info("pramfs with xip enabled\n");
+#endif
+
+ sbi->virt_addr = pram_ioremap(sbi->phys_addr, size);
+ if (!sbi->virt_addr) {
+ pram_err("ioremap of the pramfs image failed\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+#ifdef CONFIG_PRAMFS_TEST
+ if (!first_pram_super)
+ first_pram_super = sbi->virt_addr;
+#endif
+
+ if (!sbi->blocksize)
+ blocksize = PRAM_DEF_BLOCK_SIZE;
+ else
+ blocksize = sbi->blocksize;
+
+ pram_set_blocksize(sb, blocksize);
+ blocksize = sb->s_blocksize;
+
+ if (sbi->blocksize && sbi->blocksize != blocksize)
+ sbi->blocksize = blocksize;
+
+ if (size < blocksize) {
+ pram_err("size smaller then block size\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!sbi->bpi)
+ /* default is that 5% of the filesystem is
+ devoted to the inode table */
+ bpi = 20 * PRAM_INODE_SIZE;
+ else
+ bpi = sbi->bpi;
+
+ if (!sbi->num_inodes)
+ num_inodes = size / bpi;
+ else
+ num_inodes = sbi->num_inodes;
+
+ /* up num_inodes such that the end of the inode table
+ (and start of bitmap) is on a block boundary */
+ bitmap_start = PRAM_SB_SIZE + (num_inodes<<PRAM_INODE_BITS);
+ if (bitmap_start & (blocksize - 1))
+ bitmap_start = (bitmap_start + blocksize) &
+ ~(blocksize-1);
+ num_inodes = (bitmap_start - PRAM_SB_SIZE) >> PRAM_INODE_BITS;
+
+ if (sbi->num_inodes && num_inodes != sbi->num_inodes)
+ sbi->num_inodes = num_inodes;
+
+ num_blocks = (size - bitmap_start) >> sb->s_blocksize_bits;
+
+ if (!num_blocks) {
+ pram_err("num blocks equals to zero\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* calc the data blocks in-use bitmap size in bytes */
+ if (num_blocks & 7)
+ bitmap_size = ((num_blocks + 8) & ~7) >> 3;
+ else
+ bitmap_size = num_blocks >> 3;
+ /* round it up to the nearest blocksize boundary */
+ if (bitmap_size & (blocksize - 1))
+ bitmap_size = (bitmap_size + blocksize) & ~(blocksize-1);
+
+ pram_info("blocksize %lu, num inodes %lu, num blocks %lu\n",
+ blocksize, num_inodes, num_blocks);
+ pram_dbg("bitmap start 0x%08x, bitmap size %lu\n",
+ (unsigned int)bitmap_start, bitmap_size);
+ pram_dbg("max name length %d\n", PRAM_NAME_LEN);
+
+ super = pram_get_super(sb);
+ pram_lock_range(super, bitmap_start + bitmap_size, flags);
+
+ /* clear out super-block and inode table */
+ memset(super, 0, bitmap_start);
+ super->s_size = size;
+ super->s_blocksize = blocksize;
+ super->s_inodes_count = num_inodes;
+ super->s_blocks_count = num_blocks;
+ super->s_free_inodes_count = num_inodes - 1;
+ super->s_bitmap_blocks = bitmap_size >> sb->s_blocksize_bits;
+ super->s_free_blocks_count = num_blocks - super->s_bitmap_blocks;
+ super->s_free_inode_hint = 1;
+ super->s_bitmap_start = bitmap_start;
+ super->s_magic = PRAM_SUPER_MAGIC;
+ pram_sync_super(super);
+
+ root_i = pram_get_inode(sb, PRAM_ROOT_INO);
+
+ root_i->i_mode = sbi->mode;
+ root_i->i_mode |= S_IFDIR;
+ root_i->i_uid = sbi->uid;
+ root_i->i_gid = sbi->gid;
+ root_i->i_links_count = 2;
+ root_i->i_d.d_parent = PRAM_ROOT_INO;
+ pram_sync_inode(root_i);
+
+ pram_init_bitmap(sb);
+
+ pram_unlock_range(super, bitmap_start + bitmap_size, flags);
+
+ return root_i;
+}
+
+static int pram_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct pram_super_block *super;
+ struct pram_inode *root_i;
+ struct pram_sb_info *sbi = NULL;
+ off_t root_offset;
+ unsigned long blocksize, initsize = 0;
+ int retval = -EINVAL;
+ unsigned long flags;
+
+ flags = 0;
+
+ sbi = kzalloc(sizeof(struct pram_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+
+ sbi->phys_addr = get_phys_addr(&data);
+ if (sbi->phys_addr == (phys_addr_t)ULLONG_MAX)
+ goto out;
+
+ /* Init with default values */
+ sbi->mode = (S_IRWXUGO | S_ISVTX);
+ sbi->uid = current_fsuid();
+ sbi->gid = current_fsgid();
+
+ if (pram_parse_options(data, sbi))
+ goto out;
+
+ initsize = sbi->initsize;
+
+ /* Init a new pramfs istance */
+ if (initsize) {
+ root_i = pram_init(sb, initsize);
+
+ if (IS_ERR(root_i))
+ goto out;
+
+ super = pram_get_super(sb);
+
+ goto setup_sb;
+ }
+
+ pram_dbg("checking physical address 0x%016llx for pramfs image\n",
+ (u64)sbi->phys_addr);
+
+ /* Map only one page for now. Will remap it when fs size is known. */
+ initsize = PAGE_SIZE;
+ sbi->virt_addr = pram_ioremap(sbi->phys_addr, initsize);
+ if (!sbi->virt_addr) {
+ pram_err("ioremap of the pramfs image failed\n");
+ goto out;
+ }
+
+ super = pram_get_super(sb);
+
+ /* Do sanity checks on the superblock */
+ if (super->s_magic != PRAM_SUPER_MAGIC) {
+ if (!silent)
+ pram_err("Can't find a valid pramfs partition\n");
+ goto out;
+ }
+
+ /* Read the superblock */
+ if (pram_calc_checksum((u32 *)super, PRAM_SB_SIZE>>2)) {
+ pram_err("checksum error in super block\n");
+ goto out;
+ }
+
+ blocksize = super->s_blocksize;
+ pram_set_blocksize(sb, blocksize);
+
+ initsize = super->s_size;
+ pram_info("pramfs image appears to be %lu KB in size\n", initsize>>10);
+ pram_info("blocksize %lu\n", blocksize);
+
+ /* Read the root inode */
+ root_i = pram_get_inode(sb, PRAM_ROOT_INO);
+
+ /* Check that the root inode is in a sane state */
+ if (pram_calc_checksum((u32 *)root_i, PRAM_INODE_SIZE>>2)) {
+ pram_err("checksum error in root inode!\n");
+ goto out;
+ }
+
+ if (root_i->i_d.d_next) {
+ pram_err("root->next not NULL??!!\n");
+ goto out;
+ }
+
+ if (!S_ISDIR(root_i->i_mode)) {
+ pram_err("root is not a directory!\n");
+ goto out;
+ }
+
+ root_offset = root_i->i_type.dir.head;
+ if (root_offset == 0)
+ pram_dbg("empty filesystem\n");
+
+ /* Remap the whole filesystem now */
+ iounmap(sbi->virt_addr);
+ release_mem_region(sbi->phys_addr, initsize);
+ sbi->virt_addr = pram_ioremap(sbi->phys_addr, initsize);
+ if (!sbi->virt_addr) {
+ pram_err("ioremap of the pramfs image failed\n");
+ goto out;
+ }
+ super = pram_get_super(sb);
+ root_i = pram_get_inode(sb, PRAM_ROOT_INO);
+
+#ifdef CONFIG_PRAMFS_TEST
+ if (!first_pram_super)
+ first_pram_super = sbi->virt_addr;
+#endif
+
+ /* Set it all up.. */
+ setup_sb:
+ sb->s_magic = super->s_magic;
+ sb->s_op = &pram_sops;
+ sb->s_root = d_alloc_root(pram_fill_new_inode(sb, root_i));
+
+ retval = 0;
+ out:
+ if (retval && sbi->virt_addr) {
+ iounmap(sbi->virt_addr);
+ release_mem_region(sbi->phys_addr, initsize);
+ }
+
+ return retval;
+}
+
+int pram_statfs(struct dentry *d, struct kstatfs *buf)
+{
+ struct super_block *sb = d->d_sb;
+ struct pram_super_block *ps = pram_get_super(sb);
+
+ buf->f_type = PRAM_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = ps->s_blocks_count;
+ buf->f_bfree = buf->f_bavail = ps->s_free_blocks_count;
+ buf->f_files = ps->s_inodes_count;
+ buf->f_ffree = ps->s_free_inodes_count;
+ buf->f_namelen = PRAM_NAME_LEN;
+ return 0;
+}
+
+static int pram_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct pram_sb_info *sbi = (struct pram_sb_info *)vfs->mnt_sb->s_fs_info;
+
+ seq_printf(seq, ",physaddr=0x%016llx", (u64)sbi->phys_addr);
+ if (sbi->initsize)
+ seq_printf(seq, ",init=%luk", sbi->initsize >> 10);
+ if (sbi->blocksize)
+ seq_printf(seq, ",bs=%lu", sbi->blocksize);
+ if (sbi->bpi)
+ seq_printf(seq, ",bpi=%lu", sbi->bpi);
+ if (sbi->num_inodes)
+ seq_printf(seq, ",N=%lu", sbi->num_inodes);
+ if (sbi->mode != (S_IRWXUGO | S_ISVTX))
+ seq_printf(seq, ",mode=%03o", sbi->mode);
+ if (sbi->uid != 0)
+ seq_printf(seq, ",uid=%u", sbi->uid);
+ if (sbi->gid != 0)
+ seq_printf(seq, ",gid=%u", sbi->gid);
+
+ return 0;
+}
+
+int pram_remount(struct super_block *sb, int *mntflags, char *data)
+{
+ struct pram_super_block *ps;
+ unsigned long flags;
+
+ flags = 0;
+
+ if ((*mntflags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+ ps = pram_get_super(sb);
+ pram_lock_super(ps, flags);
+ ps->s_mtime = get_seconds(); /* update mount time */
+ pram_unlock_super(ps, flags);
+ }
+
+ return 0;
+}
+
+void pram_put_super(struct super_block *sb)
+{
+ struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+ struct pram_super_block *ps = pram_get_super(sb);
+
+#ifdef CONFIG_PRAMFS_TEST
+ if (first_pram_super == sbi->virt_addr)
+ first_pram_super = NULL;
+#endif
+
+ /* It's unmount time, so unmap the pramfs memory */
+ if (sbi->virt_addr) {
+ iounmap(sbi->virt_addr);
+ sbi->virt_addr = NULL;
+ release_mem_region(sbi->phys_addr, ps->s_size);
+ }
+
+ sb->s_fs_info = NULL;
+ kfree(sbi);
+}
+
+/*
+ * the super block writes are all done "on the fly", so the
+ * super block is never in a "dirty" state, so there's no need
+ * for write_super.
+ */
+static struct super_operations pram_sops = {
+ .write_inode = pram_write_inode,
+ .dirty_inode = pram_dirty_inode,
+ .delete_inode = pram_delete_inode,
+ .put_super = pram_put_super,
+ .statfs = pram_statfs,
+ .remount_fs = pram_remount,
+ .show_options = pram_show_options,
+};
+
+static int pram_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_nodev(fs_type, flags, data, pram_fill_super, mnt);
+}
+
+static struct file_system_type pram_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "pramfs",
+ .get_sb = pram_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
+static int __init init_pram_fs(void)
+{
+ return register_filesystem(&pram_fs_type);
+}
+
+static void __exit exit_pram_fs(void)
+{
+ unregister_filesystem(&pram_fs_type);
+}
+
+MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
+MODULE_DESCRIPTION("Protected/Persistent RAM Filesystem");
+MODULE_LICENSE("GPL");
+
+module_init(init_pram_fs)
+module_exit(exit_pram_fs)
^ permalink raw reply
* [PATCH 09/14] Pramfs: Inode operations for directories
From: Marco @ 2009-06-13 13:22 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Inode operations for directories.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/namei.c linux-2.6.30/fs/pramfs/namei.c
--- linux-2.6.30-orig/fs/pramfs/namei.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/namei.c 2009-06-13 12:53:15.000000000 +0200
@@ -0,0 +1,328 @@
+/*
+ * FILE NAME fs/pramfs/namei.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Inode operations for directories.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.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);
+ return 0;
+ }
+ pram_dec_count(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 = 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 = 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) {
+ struct pram_inode *pi = pram_get_inode(dir->i_sb, ino);
+ inode = pram_fill_new_inode(dir->i_sb, pi);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+
+ d_add(dentry, inode);
+ 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;
+
+ err = pram_block_symlink(inode, symname, len);
+ if (err)
+ goto out_fail;
+
+ inode->i_size = len;
+ pram_write_inode(inode, 0);
+
+ err = pram_add_nondir(dir, dentry, inode);
+out:
+ return err;
+
+out_fail:
+ pram_dec_count(inode);
+ iput(inode);
+ goto out;
+}
+
+static int pram_link(struct dentry *dest_dentry,
+ struct inode *dir,
+ struct dentry *dentry)
+{
+ pram_dbg("hard links not supported\n");
+ return -ENOSYS;
+}
+
+static int pram_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ inode->i_ctime = dir->i_ctime;
+ pram_dec_count(inode);
+
+ return 0;
+}
+
+static int pram_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct inode *inode;
+ struct pram_inode *pi;
+ int err = -EMLINK;
+ unsigned long flags;
+
+ flags = 0;
+
+ if (dir->i_nlink >= PRAM_LINK_MAX)
+ goto out;
+
+ pram_inc_count(dir);
+
+ inode = pram_new_inode(dir, S_IFDIR | mode);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ goto out_dir;
+
+ inode->i_op = &pram_dir_inode_operations;
+ inode->i_fop = &pram_dir_operations;
+ inode->i_mapping->a_ops = &pram_aops;
+
+ pram_inc_count(inode);
+
+ /* make the new directory empty */
+ pi = pram_get_inode(dir->i_sb, inode->i_ino);
+ pram_lock_inode(pi, flags);
+ pi->i_type.dir.head = pi->i_type.dir.tail = 0;
+ pram_unlock_inode(pi, flags);
+
+ err = pram_add_link(dentry, inode);
+ if (err)
+ goto out_fail;
+
+ d_instantiate(dentry, inode);
+out:
+ return err;
+
+out_fail:
+ pram_dec_count(inode);
+ pram_dec_count(inode);
+ iput(inode);
+out_dir:
+ pram_dec_count(dir);
+ goto out;
+}
+
+static int pram_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct pram_inode *pi;
+ int err = -ENOTEMPTY;
+
+ if (!inode)
+ return -ENOENT;
+
+ pi = pram_get_inode(dir->i_sb, inode->i_ino);
+
+ /* directory to delete is empty? */
+ if (pi->i_type.dir.tail == 0) {
+ inode->i_ctime = dir->i_ctime;
+ inode->i_size = 0;
+ inode->i_nlink = 0;
+ pram_write_inode(inode, 0);
+ pram_dec_count(dir);
+ err = 0;
+ } else {
+ pram_dbg("dir not empty\n");
+ }
+
+ return err;
+}
+
+static int pram_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct inode *new_dir,
+ struct dentry *new_dentry)
+{
+ struct inode *old_inode = old_dentry->d_inode;
+ struct inode *new_inode = new_dentry->d_inode;
+ struct pram_inode *pi_new;
+ int err = -ENOENT;
+
+ if (new_inode) {
+ err = -ENOTEMPTY;
+ pi_new = pram_get_inode(new_dir->i_sb, new_inode->i_ino);
+ if (S_ISDIR(old_inode->i_mode)) {
+ if (pi_new->i_type.dir.tail != 0)
+ goto out;
+ if (new_inode->i_nlink)
+ new_inode->i_nlink--;
+ }
+
+ new_inode->i_ctime = CURRENT_TIME;
+ pram_dec_count(new_inode);
+ } else {
+ if (S_ISDIR(old_inode->i_mode)) {
+ err = -EMLINK;
+ if (new_dir->i_nlink >= PRAM_LINK_MAX)
+ goto out;
+ pram_dec_count(old_dir);
+ pram_inc_count(new_dir);
+ }
+ }
+
+ /* unlink the inode from the old directory ... */
+ err = pram_remove_link(old_inode);
+ if (err)
+ goto out;
+
+ /* and link it into the new directory. */
+ err = pram_add_link(new_dentry, old_inode);
+ if (err)
+ goto out;
+
+ err = 0;
+ out:
+ return err;
+}
+
+struct inode_operations pram_dir_inode_operations = {
+ .create = pram_create,
+ .lookup = pram_lookup,
+ .link = pram_link,
+ .unlink = pram_unlink,
+ .symlink = pram_symlink,
+ .mkdir = pram_mkdir,
+ .rmdir = pram_rmdir,
+ .mknod = pram_mknod,
+ .rename = pram_rename,
+};
^ permalink raw reply
* [PATCH 08/14] Pramfs: Makefile and Kconfig
From: Marco @ 2009-06-13 13:22 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Makefile and Kconfig.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/Kconfig linux-2.6.30/fs/Kconfig
--- linux-2.6.30-orig/fs/Kconfig 2009-06-10 05:05:27.000000000 +0200
+++ linux-2.6.30/fs/Kconfig 2009-06-13 10:01:41.000000000 +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"
@@ -176,6 +176,7 @@ source "fs/romfs/Kconfig"
source "fs/sysv/Kconfig"
source "fs/ufs/Kconfig"
source "fs/exofs/Kconfig"
+source "fs/pramfs/Kconfig"
config NILFS2_FS
tristate "NILFS2 file system support (EXPERIMENTAL)"
diff -uprN linux-2.6.30-orig/fs/Makefile linux-2.6.30/fs/Makefile
--- linux-2.6.30-orig/fs/Makefile 2009-06-10 05:05:27.000000000 +0200
+++ linux-2.6.30/fs/Makefile 2009-06-13 10:00:26.000000000 +0200
@@ -124,3 +124,5 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
+obj-$(CONFIG_PRAMFS) += pramfs/
+
diff -uprN linux-2.6.30-orig/fs/pramfs/Kconfig linux-2.6.30/fs/pramfs/Kconfig
--- linux-2.6.30-orig/fs/pramfs/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/Kconfig 2009-04-22 15:22:54.000000000 +0200
@@ -0,0 +1,51 @@
+config PRAMFS
+ tristate "Persistent and Protected RAM file system support"
+ select PRAMFS_NOWP if PRAMFS=m
+ 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
+ select PRAMFS_NOWP
+ help
+ Say Y here to enable xip feature of PRAMFS.
+
+config PRAMFS_NOWP
+ bool "Disable PRAMFS write protection"
+ depends on PRAMFS
+ default n
+ help
+ Say Y here to disable the write protect feature of PRAMFS.
+
+config ROOT_PRAMFS
+ bool "Root file system on PRAMFS"
+ depends on PRAMFS && !ROOT_NFS
+ help
+ Say Y if you have enabled PRAMFS, and you want to be
+ able to use PRAMFS as the root filesystem. To actually
+ have the kernel mount PRAMFS as a root file system, you
+ must also pass the command line parameter
+ "root=/dev/null rootflags=physaddr=0x********" to the kernel
+ (replace 0x******** with the physical address location of the
+ previously initialized PRAMFS memory to boot with).
+
+config PRAMFS_TEST
+ boolean
+ depends on PRAMFS
+ default n
+
+config TEST_MODULE
+ tristate "PRAMFS Test"
+ depends on PRAMFS && m && !PRAMFS_NOWP
+ select PRAMFS_TEST
+ default n
+ help
+ Say Y here to build a simple module to test the protection of
+ PRAMFS. The module will be called pramfs_test.ko.
diff -uprN linux-2.6.30-orig/fs/pramfs/Makefile linux-2.6.30/fs/pramfs/Makefile
--- linux-2.6.30-orig/fs/pramfs/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/Makefile 2009-04-19 11:58:51.000000000 +0200
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux pram-filesystem routines.
+#
+
+obj-$(CONFIG_PRAMFS) += pramfs.o
+obj-$(CONFIG_TEST_MODULE) += pramfs_test.o
+
+pramfs-objs := balloc.o dir.o file.o inode.o namei.o super.o symlink.o
+
+ifneq ($(CONFIG_PRAMFS_NOWP),y)
+pramfs-objs += wprotect.o
+endif
+pramfs-$(CONFIG_PRAMFS_XIP) += xip.o
^ permalink raw reply
* [PATCH 07/14] Pramfs: Inode operations
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Inode operations.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/inode.c linux-2.6.30/fs/pramfs/inode.c
--- linux-2.6.30-orig/fs/pramfs/inode.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/inode.c 2009-06-13 12:58:27.000000000 +0200
@@ -0,0 +1,620 @@
+/*
+ * FILE NAME fs/pramfs/inode.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Inode methods (allocate/free/read/write).
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.h"
+#include "xip.h"
+
+static struct backing_dev_info pram_backing_dev_info = {
+ .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, int *blocknr, int zero)
+{
+ unsigned long flags;
+
+ int errval = pram_new_block(inode->i_sb, blocknr, zero);
+
+ flags = 0;
+
+ if (!errval) {
+ struct pram_inode *pi = pram_get_inode(inode->i_sb,
+ inode->i_ino);
+ inode->i_blocks++;
+ pram_lock_inode(pi, flags);
+ pi->i_blocks = inode->i_blocks;
+ pram_unlock_inode(pi, flags);
+ }
+
+ return errval;
+}
+
+/*
+ * find the offset to the block represented by the given inode's file
+ * relative block number.
+ */
+off_t pram_find_data_block(struct inode *inode, int file_blocknr)
+{
+ struct super_block *sb = inode->i_sb;
+ struct pram_inode *pi;
+ off_t *row; /* ptr to row block */
+ off_t *col; /* ptr to column blocks */
+ off_t bp = 0;
+ int i_row, i_col;
+ int N = sb->s_blocksize >> 2; /* num block ptrs per block */
+ int Nbits = sb->s_blocksize_bits - 2;
+
+ pi = pram_get_inode(sb, inode->i_ino);
+
+ i_row = file_blocknr >> Nbits;
+ i_col = file_blocknr & (N-1);
+
+ row = pram_get_block(sb, pi->i_type.reg.row_block);
+ if (row) {
+ col = pram_get_block(sb, row[i_row]);
+ if (col)
+ bp = col[i_col];
+ }
+
+ return bp;
+}
+
+
+/*
+ * Free data blocks from inode starting at first_trunc_block.
+ */
+static void
+pram_truncate_blocks(struct inode *inode, int first_trunc_block)
+{
+ struct super_block *sb = inode->i_sb;
+ struct pram_inode *pi = pram_get_inode(sb, inode->i_ino);
+ int N = sb->s_blocksize >> 2; /* num block ptrs per block */
+ int Nbits = sb->s_blocksize_bits - 2;
+ int first_row_index, last_row_index;
+ int i, j, first_blocknr, last_blocknr, blocknr;
+ unsigned long flags;
+ off_t *row; /* ptr to row block */
+ off_t *col; /* ptr to column blocks */
+
+ flags = 0;
+
+ if (first_trunc_block >= inode->i_blocks ||
+ !inode->i_blocks || !pi->i_type.reg.row_block) {
+ return;
+ }
+
+ first_blocknr = first_trunc_block;
+ last_blocknr = inode->i_blocks - 1;
+ first_row_index = first_blocknr >> Nbits;
+ last_row_index = last_blocknr >> Nbits;
+
+ row = pram_get_block(sb, 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;
+
+ col = pram_get_block(sb, row[i]);
+ for (j = first_col_index; j <= last_col_index; j++) {
+ blocknr = pram_get_blocknr(sb, col[j]);
+ pram_free_block(sb, blocknr);
+ pram_lock_block(sb, col, flags);
+ col[j] = 0;
+ pram_unlock_block(sb, col, flags);
+ }
+
+ if (first_col_index == 0) {
+ blocknr = pram_get_blocknr(sb, row[i]);
+ pram_free_block(sb, blocknr);
+ pram_lock_block(sb, row, flags);
+ row[i] = 0;
+ pram_unlock_block(sb, row, flags);
+ }
+ }
+
+ inode->i_blocks -= (last_blocknr - first_blocknr + 1);
+
+ if (first_row_index == 0) {
+ blocknr = pram_get_blocknr(sb, pi->i_type.reg.row_block);
+ pram_free_block(sb, blocknr);
+ pram_lock_inode(pi, flags);
+ pi->i_type.reg.row_block = 0;
+ pram_unlock_inode(pi, flags);
+ }
+ pram_lock_inode(pi, flags);
+ pi->i_blocks = inode->i_blocks;
+ pram_unlock_inode(pi, flags);
+}
+
+/*
+ * Allocate num data blocks for inode, starting at given file-relative
+ * block number. Any unallocated file blocks before file_blocknr
+ * are allocated. All blocks except the last are zeroed out.
+ */
+int pram_alloc_blocks(struct inode *inode, int file_blocknr, int num)
+{
+ struct super_block *sb = inode->i_sb;
+ struct pram_inode *pi = pram_get_inode(sb, inode->i_ino);
+ int N = sb->s_blocksize >> 2; /* num block ptrs per block */
+ int Nbits = sb->s_blocksize_bits - 2;
+ int first_file_blocknr;
+ int last_file_blocknr;
+ int first_row_index, last_row_index;
+ int i, j, blocknr, errval;
+ unsigned long flags;
+ off_t *row;
+ off_t *col;
+
+ flags = 0;
+
+ if (!pi->i_type.reg.row_block) {
+ /* alloc the 2nd order array block */
+ errval = pram_new_block(sb, &blocknr, 1);
+ if (errval) {
+ pram_err("failed to alloc 2nd order array block\n");
+ goto fail;
+ }
+ pram_lock_inode(pi, flags);
+ pi->i_type.reg.row_block = pram_get_block_off(sb, blocknr);
+ pram_unlock_inode(pi, flags);
+ }
+
+ row = pram_get_block(sb, pi->i_type.reg.row_block);
+
+ first_file_blocknr = (file_blocknr > inode->i_blocks) ?
+ inode->i_blocks : file_blocknr;
+ last_file_blocknr = file_blocknr + num - 1;
+
+ first_row_index = first_file_blocknr >> Nbits;
+ last_row_index = last_file_blocknr >> Nbits;
+
+ for (i = first_row_index; i <= last_row_index; i++) {
+ int first_col_index, last_col_index;
+ /*
+ * we are starting a new row, so make sure
+ * there is a block allocated for the row.
+ */
+ if (!row[i]) {
+ /* allocate the row block */
+ errval = pram_new_block(sb, &blocknr, 1);
+ if (errval) {
+ pram_err("failed to alloc row block\n");
+ goto fail;
+ }
+ pram_lock_block(sb, row, flags);
+ row[i] = pram_get_block_off(sb, blocknr);
+ pram_unlock_block(sb, row, flags);
+ }
+ col = pram_get_block(sb, row[i]);
+
+ first_col_index = (i == first_row_index) ?
+ first_file_blocknr & (N-1) : 0;
+
+ last_col_index = (i == last_row_index) ?
+ last_file_blocknr & (N-1) : N-1;
+
+ for (j = first_col_index; j <= last_col_index; j++) {
+ int last_block =
+ (i == last_row_index) && (j == last_col_index);
+ if (!col[j]) {
+ errval = pram_new_data_block(inode,
+ &blocknr,
+ !last_block);
+ if (errval) {
+ pram_err("failed to alloc "
+ "data block\n");
+ goto fail;
+ }
+ pram_lock_block(sb, col, flags);
+ col[j] = pram_get_block_off(sb, blocknr);
+ pram_unlock_block(sb, col, flags);
+ }
+ }
+ }
+
+ errval = 0;
+ fail:
+ return errval;
+}
+
+static int
+pram_fill_inode(struct inode *inode, struct pram_inode *pi)
+{
+ int ret = -EIO;
+
+ if (pram_calc_checksum((u32 *)pi, PRAM_INODE_SIZE>>2)) {
+ pram_err("checksum error in inode %08x\n",
+ (u32)inode->i_ino);
+ goto bad_inode;
+ }
+
+ inode->i_mode = pi->i_mode;
+ inode->i_uid = pi->i_uid;
+ inode->i_gid = pi->i_gid;
+ inode->i_nlink = pi->i_links_count;
+ inode->i_size = pi->i_size;
+ inode->i_atime.tv_sec = pi->i_atime;
+ inode->i_ctime.tv_sec = pi->i_ctime;
+ inode->i_mtime.tv_sec = pi->i_mtime;
+ inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec =
+ inode->i_ctime.tv_nsec = 0;
+
+ /* check if the inode is active. */
+ if (inode->i_nlink == 0 && (inode->i_mode == 0 || pi->i_dtime)) {
+ /* this inode is deleted */
+ ret = -EINVAL;
+ goto bad_inode;
+ }
+
+ inode->i_blocks = pi->i_blocks;
+ inode->i_ino = pram_get_inodenr(inode->i_sb, pi);
+ inode->i_mapping->a_ops = &pram_aops;
+ inode->i_mapping->backing_dev_info = &pram_backing_dev_info;
+
+ insert_inode_hash(inode);
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_op = &pram_file_inode_operations;
+ inode->i_fop = &pram_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &pram_dir_inode_operations;
+ inode->i_fop = &pram_dir_operations;
+ break;
+ case S_IFLNK:
+ inode->i_op = &pram_symlink_inode_operations;
+ break;
+ default:
+ inode->i_size = 0;
+ init_special_inode(inode, inode->i_mode,
+ pi->i_type.dev.rdev);
+ break;
+ }
+
+ return 0;
+
+ bad_inode:
+ make_bad_inode(inode);
+ return ret;
+}
+
+static int pram_update_inode(struct inode *inode)
+{
+ struct pram_inode *pi;
+ int retval = 0;
+ unsigned long flags;
+
+ flags = 0;
+
+ pi = pram_get_inode(inode->i_sb, inode->i_ino);
+
+ pram_lock_inode(pi, flags);
+ pi->i_mode = inode->i_mode;
+ pi->i_uid = inode->i_uid;
+ pi->i_gid = inode->i_gid;
+ pi->i_links_count = inode->i_nlink;
+ pi->i_size = inode->i_size;
+ pi->i_blocks = inode->i_blocks;
+ pi->i_atime = inode->i_atime.tv_sec;
+ pi->i_ctime = inode->i_ctime.tv_sec;
+ pi->i_mtime = inode->i_mtime.tv_sec;
+
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ pi->i_type.dev.rdev = inode->i_rdev;
+
+ pram_unlock_inode(pi, flags);
+ return retval;
+}
+
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ */
+static void pram_free_inode(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct pram_super_block *ps;
+ struct pram_inode *pi;
+ unsigned long inode_nr;
+ unsigned long flags;
+
+ flags = 0;
+
+ /*
+ * Note: we must free any quota before locking the superblock,
+ * as writing the quota to disk may need the lock as well.
+ */
+ if (!is_bad_inode(inode)) {
+ /* Quota is already initialized in iput() */
+ vfs_dq_free_inode(inode);
+ vfs_dq_drop(inode);
+ }
+
+ lock_super(sb);
+ clear_inode(inode);
+
+ inode_nr = (inode->i_ino - PRAM_ROOT_INO) >> PRAM_INODE_BITS;
+
+ pi = pram_get_inode(sb, inode->i_ino);
+ pram_lock_inode(pi, flags);
+ pi->i_dtime = get_seconds();
+ pi->i_type.reg.row_block = 0;
+ pram_unlock_inode(pi, flags);
+
+ /* increment s_free_inodes_count */
+ ps = pram_get_super(sb);
+ pram_lock_super(ps, flags);
+ if (inode_nr < ps->s_free_inode_hint)
+ ps->s_free_inode_hint = inode_nr;
+ ps->s_free_inodes_count++;
+ if (ps->s_free_inodes_count == ps->s_inodes_count - 1) {
+ /* filesystem is empty */
+ pram_dbg("fs is empty!\n");
+ ps->s_free_inode_hint = 1;
+ }
+ pram_unlock_super(ps, flags);
+
+ unlock_super(sb);
+}
+
+
+struct inode *
+pram_fill_new_inode(struct super_block *sb,
+ struct pram_inode *pi)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode)
+ pram_fill_inode(inode, pi);
+
+ return inode;
+}
+
+
+/*
+ * Called at the last iput() if i_nlink is zero.
+ */
+void pram_delete_inode(struct inode *inode)
+{
+ lock_kernel();
+
+ if (is_bad_inode(inode))
+ goto no_delete;
+
+ /* unlink from chain in the inode's directory */
+ pram_remove_link(inode);
+ inode->i_size = 0;
+ if (inode->i_blocks)
+ pram_truncate(inode);
+ pram_free_inode(inode);
+
+ unlock_kernel();
+ return;
+ no_delete:
+ unlock_kernel();
+ clear_inode(inode); /* We must guarantee clearing of inode... */
+}
+
+
+struct inode *pram_new_inode(const struct inode *dir, int mode)
+{
+ struct super_block *sb;
+ struct pram_super_block *ps;
+ struct inode *inode;
+ struct pram_inode *pi = NULL;
+ int i, errval;
+ ino_t ino = 0;
+ unsigned long flags;
+
+ flags = 0;
+
+ sb = dir->i_sb;
+ inode = new_inode(sb);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ lock_super(sb);
+ ps = pram_get_super(sb);
+
+ if (ps->s_free_inodes_count) {
+ /* find the oldest unused pram inode */
+ for (i = ps->s_free_inode_hint; i < ps->s_inodes_count; i++) {
+ ino = PRAM_ROOT_INO + (i << PRAM_INODE_BITS);
+ pi = pram_get_inode(sb, ino);
+ /* check if the inode is active. */
+ if (pi->i_links_count == 0 && (pi->i_mode == 0 ||
+ pi->i_dtime)) {
+ /* this inode is deleted */
+ break;
+ }
+ }
+
+ if (i >= ps->s_inodes_count) {
+ pram_err("s_free_inodes_count!=0 but none free!?\n");
+ errval = -ENOSPC;
+ goto fail;
+ }
+
+ pram_dbg("allocating inode %lu\n", ino);
+ pram_lock_super(ps, flags);
+ ps->s_free_inodes_count--;
+ ps->s_free_inode_hint = (i < ps->s_inodes_count-1) ? i+1 : 0;
+ pram_unlock_super(ps, flags);
+ } else {
+ pram_err("no space left to create new inode!\n");
+ errval = -ENOSPC;
+ goto fail;
+ }
+
+ /* chosen inode is in ino */
+
+ inode->i_ino = ino;
+ inode->i_uid = current_fsuid();
+
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ } else
+ inode->i_gid = current_fsgid();
+ inode->i_mode = mode;
+
+ inode->i_blocks = inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ pram_lock_inode(pi, flags);
+ pi->i_d.d_next = 0;
+ pi->i_d.d_prev = 0;
+ pram_unlock_inode(pi, flags);
+
+ insert_inode_hash(inode);
+ pram_write_inode(inode, 0);
+
+ unlock_super(sb);
+
+ if (vfs_dq_alloc_inode(inode)) {
+ vfs_dq_drop(inode);
+ inode->i_flags |= S_NOQUOTA;
+ inode->i_nlink = 0;
+ iput(inode);
+ return ERR_PTR(-EDQUOT);
+ }
+ return inode;
+
+fail:
+ unlock_super(sb);
+ make_bad_inode(inode);
+ iput(inode);
+ return ERR_PTR(errval);
+}
+
+void pram_truncate(struct inode *inode)
+{
+ int blocksize, blocksize_bits;
+ int blocknr;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+
+ blocksize_bits = inode->i_sb->s_blocksize_bits;
+ blocksize = 1 << blocksize_bits;
+ blocknr = (inode->i_size + blocksize-1) >> blocksize_bits;
+
+ lock_kernel();
+ pram_truncate_blocks(inode, blocknr);
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ pram_update_inode(inode);
+ unlock_kernel();
+}
+
+int pram_write_inode(struct inode *inode, int wait)
+{
+ int ret = 0;
+
+ lock_kernel();
+ ret = pram_update_inode(inode);
+ unlock_kernel();
+
+ return ret;
+}
+
+/*
+ * dirty_inode() is called from __mark_inode_dirty()
+ */
+void pram_dirty_inode(struct inode *inode)
+{
+ pram_write_inode(inode, 0);
+}
+
+int pram_get_and_update_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh, int create)
+{
+ struct super_block *sb = inode->i_sb;
+ unsigned int blocksize = 1 << inode->i_blkbits;
+ int err = -EIO;
+ off_t block;
+ void *bp;
+ unsigned long flags;
+
+ flags = 0;
+
+ lock_kernel();
+
+ block = pram_find_data_block(inode, iblock);
+
+ if (!block) {
+ if (!create)
+ goto out;
+
+ err = pram_alloc_blocks(inode, iblock, 1);
+ if (err)
+ goto out;
+ block = pram_find_data_block(inode, iblock);
+ if (!block) {
+ err = -EIO;
+ goto out;
+ }
+ set_buffer_new(bh);
+ }
+
+ bh->b_blocknr = block;
+ set_buffer_mapped(bh);
+
+ /* now update the buffer synchronously */
+ bp = pram_get_block(sb, block);
+ if (buffer_new(bh)) {
+ pram_lock_block(sb, bp, flags);
+ memset(bp, 0, blocksize);
+ pram_unlock_block(sb, bp, flags);
+ memset(bh->b_data, 0, blocksize);
+ } else {
+ memcpy(bh->b_data, bp, blocksize);
+ }
+
+ set_buffer_uptodate(bh);
+ err = 0;
+
+ out:
+ unlock_kernel();
+ return err;
+}
+
+struct address_space_operations pram_aops = {
+ .readpage = pram_readpage,
+ .direct_IO = pram_direct_IO,
+ .get_xip_mem = pram_get_xip_mem,
+};
^ permalink raw reply
* [PATCH 06/14] Pramfs: Include files
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Include files.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/pram_fs.h linux-2.6.30/fs/pramfs/pram_fs.h
--- linux-2.6.30-orig/fs/pramfs/pram_fs.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/pram_fs.h 2009-06-13 12:58:49.000000000 +0200
@@ -0,0 +1,388 @@
+/*
+ * FILE NAME include/linux/pram_fs.h
+ *
+ * BRIEF DESCRIPTION
+ *
+ * Definitions for the PRAMFS filesystem.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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 _LINUX_PRAM_FS_H
+#define _LINUX_PRAM_FS_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+#include <linux/sched.h>
+#include <linux/buffer_head.h>
+#include "pram_fs_sb.h"
+#endif
+
+/*
+ * The PRAM filesystem constants/structures
+ */
+
+/*
+ * Define PRAMFS_DEBUG to produce debug messages
+ */
+#define PRAMFS_DEBUG
+
+/*
+ * Debug code
+ */
+#ifdef __KERNEL__
+#define PFX "pramfs"
+#ifdef PRAMFS_DEBUG
+#define pram_dbg(format, arg...) \
+ printk(KERN_DEBUG PFX ": " format , ## arg)
+#else
+#define pram_dbg(format, arg...) do {} while (0)
+#endif
+#define pram_err(format, arg...) \
+ printk(KERN_ERR PFX ": " format , ## arg)
+#define pram_info(format, arg...) \
+ printk(KERN_INFO PFX ": " format , ## arg)
+#define pram_warn(format, arg...) \
+ printk(KERN_WARNING PFX ": " format , ## arg)
+#endif
+
+/*
+ * The PRAM file system magic number
+ */
+#define PRAM_SUPER_MAGIC 0xEFFA
+
+/*
+ * Maximal count of links to a file
+ */
+#define PRAM_LINK_MAX 32000
+
+#define PRAM_MIN_BLOCK_SIZE 512
+#define PRAM_MAX_BLOCK_SIZE 4096
+#define PRAM_DEF_BLOCK_SIZE 2048
+
+#define PRAM_INODE_SIZE 128 /* must be power of two */
+#define PRAM_INODE_BITS 7
+
+/*
+ * Structure of a directory entry in PRAMFS.
+ * Offsets are to the inode that holds the referenced dentry.
+ */
+struct pram_dentry {
+ off_t d_next; /* next dentry in this directory */
+ off_t d_prev; /* previous dentry in this directory */
+ off_t d_parent; /* parent directory */
+ char d_name[0];
+};
+
+
+/*
+ * Structure of an inode in PRAMFS
+ */
+struct pram_inode {
+ __u32 i_sum; /* checksum of this inode */
+ __u32 i_uid; /* Owner Uid */
+ __u32 i_gid; /* Group Id */
+ __u16 i_mode; /* File mode */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_size; /* Size of data in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+
+ union {
+ struct {
+ /*
+ * ptr to row block of 2D block pointer array,
+ * file block #'s 0 to (blocksize/4)^2 - 1.
+ */
+ off_t row_block;
+ } reg; /* regular file or symlink inode */
+ struct {
+ off_t head; /* first entry in this directory */
+ off_t tail; /* last entry in this directory */
+ } dir;
+ struct {
+ __u32 rdev; /* major/minor # */
+ } dev; /* device inode */
+ } i_type;
+
+ struct pram_dentry i_d;
+};
+
+#define PRAM_NAME_LEN \
+ (PRAM_INODE_SIZE - offsetof(struct pram_inode, i_d.d_name) - 1)
+
+
+#define PRAM_SB_SIZE 128 /* must be power of two */
+#define PRAM_SB_BITS 7
+
+/*
+ * Structure of the super block in PRAMFS
+ */
+struct pram_super_block {
+ __u32 s_size; /* total size of fs in bytes */
+ __u32 s_blocksize; /* blocksize in bytes */
+ __u32 s_inodes_count; /* total inodes count (used or free) */
+ __u32 s_free_inodes_count;/* free inodes count */
+ __u32 s_free_inode_hint; /* start hint for locating free inodes */
+ __u32 s_blocks_count; /* total data blocks count (used or free) */
+ __u32 s_free_blocks_count;/* free data blocks count */
+ __u32 s_free_blocknr_hint;/* free data blocks count */
+ off_t s_bitmap_start; /* data block in-use bitmap location */
+ __u32 s_bitmap_blocks;/* size of bitmap in number of blocks */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_magic; /* Magic signature */
+ char s_volume_name[16]; /* volume name */
+ __u32 s_sum; /* checksum of this sb, including padding */
+};
+
+/* The root inode follows immediately after the redundant super block */
+#define PRAM_ROOT_INO PRAM_SB_SIZE
+
+#ifdef __KERNEL__
+
+/* 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 generic_file_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);
+
+
+#endif /* CONFIG_PRAMFS_XIP */
+
+/* balloc.c */
+extern void pram_init_bitmap(struct super_block *sb);
+extern void pram_free_block(struct super_block *sb, int blocknr);
+extern int pram_new_block(struct super_block *sb, int *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);
+
+/* inode.c */
+extern int pram_alloc_blocks(struct inode *inode, int file_blocknr, int num);
+extern off_t pram_find_data_block(struct inode *inode,
+ int file_blocknr);
+extern struct inode *pram_fill_new_inode(struct super_block *sb,
+ struct pram_inode *raw_inode);
+extern void pram_put_inode(struct inode *inode);
+extern void pram_delete_inode(struct inode *inode);
+extern struct inode *pram_new_inode(const struct inode *dir, int mode);
+extern void pram_read_inode(struct inode *inode);
+extern void pram_truncate(struct inode *inode);
+extern int pram_write_inode(struct inode *inode, int wait);
+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);
+
+
+#ifndef CONFIG_PRAMFS_NOWP
+extern void pram_writeable(void *vaddr, unsigned long size, int rw);
+
+#define wrprotect(addr, size) {\
+ spin_lock(&init_mm.page_table_lock);\
+ pram_writeable(addr, size, 0);\
+ spin_unlock(&init_mm.page_table_lock);\
+}
+
+#else
+
+#define wrprotect(addr, size) do {} while (0)
+
+#endif /* CONFIG PRAMFS_NOWP */
+
+/* Inline functions start here */
+
+static inline u32 pram_calc_checksum(u32 *buf, int n)
+{
+ u32 sum = 0;
+ while (n--)
+ sum += *buf++;
+ return sum;
+}
+
+/* If this is part of a read-modify-write of the super block,
+ pram_lock_super() before calling! */
+static inline struct pram_super_block *
+pram_get_super(struct super_block *sb)
+{
+ struct pram_sb_info *sbi = (struct pram_sb_info *)sb->s_fs_info;
+ return (struct pram_super_block *)sbi->virt_addr;
+}
+
+/* pram_lock_super() before calling! */
+static inline void pram_sync_super(struct pram_super_block *ps)
+{
+ ps->s_wtime = get_seconds();
+ ps->s_sum = 0;
+ ps->s_sum -= pram_calc_checksum((u32 *)ps, PRAM_SB_SIZE>>2);
+}
+
+/* pram_lock_inode() before calling! */
+static inline void pram_sync_inode(struct pram_inode *pi)
+{
+ /* pi->i_mtime = CURRENT_TIME; */
+ pi->i_sum = 0;
+ pi->i_sum -= pram_calc_checksum((u32 *)pi, PRAM_INODE_SIZE>>2);
+}
+
+#ifndef CONFIG_PRAMFS_NOWP
+#define pram_lock_range(p, len, flags) {\
+ spin_lock_irqsave(&init_mm.page_table_lock, flags);\
+ pram_writeable((p), (len), 1);\
+}
+
+#define pram_unlock_range(p, len, flags) {\
+ pram_writeable((p), (len), 0);\
+ spin_unlock_irqrestore(&init_mm.page_table_lock, flags);\
+}
+#else
+#define pram_lock_range(p, len, flags) do {} while (0)
+#define pram_unlock_range(p, len, flags) do {} while (0)
+#endif
+
+/* write protection for super block */
+#define pram_lock_super(ps, flags) \
+ pram_lock_range((ps), PRAM_SB_SIZE, flags)
+#define pram_unlock_super(ps, flags) {\
+ pram_sync_super(ps);\
+ pram_unlock_range((ps), PRAM_SB_SIZE, flags);\
+}
+
+/* write protection for inode metadata */
+#define pram_lock_inode(pi, flags) \
+ pram_lock_range((pi), PRAM_INODE_SIZE, flags)
+#define pram_unlock_inode(pi, flags) {\
+ pram_sync_inode(pi);\
+ pram_unlock_range((pi), PRAM_SB_SIZE, flags);\
+}
+
+/* write protection for a data block */
+#define pram_lock_block(sb, bp, flags) \
+ pram_lock_range((bp), (sb)->s_blocksize, flags)
+#define pram_unlock_block(sb, bp, flags) \
+ pram_unlock_range((bp), (sb)->s_blocksize, flags)
+
+static inline void *
+pram_get_bitmap(struct super_block *sb)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return (void *)ps + ps->s_bitmap_start;
+}
+
+/* If this is part of a read-modify-write of the inode metadata,
+ pram_lock_inode() before calling! */
+static inline struct pram_inode *
+pram_get_inode(struct super_block *sb, off_t ino)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return ino ? (struct pram_inode *)((void *)ps + ino) : NULL;
+}
+
+static inline ino_t
+pram_get_inodenr(struct super_block *sb, struct pram_inode *pi)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return (ino_t)((unsigned long)pi - (unsigned long)ps);
+}
+
+static inline off_t
+pram_get_block_off(struct super_block *sb, unsigned long blocknr)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return (off_t)(ps->s_bitmap_start +
+ (blocknr << sb->s_blocksize_bits));
+}
+
+static inline unsigned long
+pram_get_blocknr(struct super_block *sb, off_t block)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return (block - ps->s_bitmap_start) >> sb->s_blocksize_bits;
+}
+
+/* If this is part of a read-modify-write of the block,
+ pram_lock_block() before calling! */
+static inline void *
+pram_get_block(struct super_block *sb, off_t block)
+{
+ struct pram_super_block *ps = pram_get_super(sb);
+ return block ? ((void *)ps + block) : NULL;
+}
+
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct file_operations pram_dir_operations;
+
+/* file.c */
+extern struct inode_operations pram_file_inode_operations;
+extern struct file_operations pram_file_operations;
+
+/* inode.c */
+extern struct address_space_operations pram_aops;
+
+/* namei.c */
+extern struct inode_operations pram_dir_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations pram_symlink_inode_operations;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PRAM_FS_H */
diff -uprN linux-2.6.30-orig/fs/pramfs/pram_fs_sb.h linux-2.6.30/fs/pramfs/pram_fs_sb.h
--- linux-2.6.30-orig/fs/pramfs/pram_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/pram_fs_sb.h 2009-06-13 12:59:17.000000000 +0200
@@ -0,0 +1,40 @@
+/*
+ * FILE NAME include/linux/pram_fs_sb.h
+ *
+ * Definitions for the PRAM filesystem.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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 _LINUX_PRAM_FS_SB
+#define _LINUX_PRAM_FS_SB
+
+/*
+ * PRAM filesystem super-block data in memory
+ */
+struct pram_sb_info {
+ /*
+ * base physical and virtual address of PRAMFS (which is also
+ * the pointer to the super block)
+ */
+ phys_addr_t phys_addr;
+ void *virt_addr;
+
+ /* Mount options */
+ unsigned long bpi;
+ unsigned long num_inodes;
+ unsigned long blocksize;
+ unsigned long initsize;
+ uid_t uid; /* Mount uid for root directory */
+ gid_t gid; /* Mount gid for root directory */
+ mode_t mode; /* Mount mode for root directory */
+};
+
+#endif /* _LINUX_PRAM_FS_SB */
+
^ permalink raw reply
* [PATCH 05/14] Pramfs: File operations for files
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
File operations for files.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/file.c linux-2.6.30/fs/pramfs/file.c
--- linux-2.6.30-orig/fs/pramfs/file.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/file.c 2009-06-13 12:52:56.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * FILE NAME fs/pramfs/file.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * File operations for files.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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/uaccess.h>
+#include "pram_fs.h"
+#include "xip.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);
+}
+
+/*
+ * Called when an inode is released. Note that this is different
+ * from pram_open_file: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+static int pram_release_file(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+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;
+ ssize_t retval = 0;
+ struct pram_inode *pi;
+ void *tmp = NULL;
+ unsigned long flags;
+ unsigned long blocknr, blockoff;
+ int num_blocks, blocksize_mask, blocksize, blocksize_bits;
+ char __user *buf = iov->iov_base;
+ size_t length = iov->iov_len;
+
+ flags = 0;
+
+ 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 fail;
+ }
+
+ pi = pram_get_inode(inode->i_sb, inode->i_ino);
+
+ while (length) {
+ int count;
+ off_t block = pram_find_data_block(inode, blocknr++);
+ u8 *bp = (u8 *)pram_get_block(sb, block);
+ if (!bp)
+ goto fail;
+
+ count = blockoff + length > blocksize ?
+ blocksize - blockoff : length;
+
+ if (rw == READ) {
+ copy_to_user(buf, &bp[blockoff], count);
+ } else {
+ copy_from_user(tmp, buf, count);
+
+ pram_lock_block(inode->i_sb, bp, flags);
+ memcpy(&bp[blockoff], tmp, count);
+ pram_unlock_block(inode->i_sb, bp, flags);
+ }
+
+ progress += count;
+ buf += count;
+ length -= count;
+ blockoff = 0;
+ }
+
+ retval = progress;
+ fail:
+ kfree(tmp);
+ out:
+ return retval;
+}
+
+struct file_operations pram_file_operations = {
+ .llseek = generic_file_llseek,
+ .read = pram_read,
+ .write = pram_write,
+ .aio_read = pram_aio_read,
+ .aio_write = pram_aio_write,
+ .mmap = pram_mmap,
+ .open = pram_open_file,
+ .release = pram_release_file,
+ .fsync = simple_sync_file,
+};
+
+struct inode_operations pram_file_inode_operations = {
+ .truncate = pram_truncate,
+};
^ permalink raw reply
* [PATCH 04/14] Pramfs: Mounting as root filesystem
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Pramfs can be used even as root filesystem.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/init/do_mounts.c linux-2.6.30/init/do_mounts.c
--- linux-2.6.30-orig/init/do_mounts.c 2009-06-10 05:05:27.000000000 +0200
+++ linux-2.6.30/init/do_mounts.c 2009-06-13 12:50:36.000000000 +0200
@@ -299,6 +299,17 @@ static int __init mount_nfs_root(void)
}
#endif
+#ifdef CONFIG_ROOT_PRAMFS
+static int __init mount_pramfs_root(void)
+{
+ create_dev("/dev/root", ROOT_DEV);
+ if (do_mount_root("/dev/root", "pramfs",
+ root_mountflags, root_mount_data) == 0)
+ return 1;
+ return 0;
+}
+#endif
+
#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
void __init change_floppy(char *fmt, ...)
{
@@ -331,6 +342,15 @@ void __init change_floppy(char *fmt, ...
void __init mount_root(void)
{
+#ifdef CONFIG_ROOT_PRAMFS
+ if (MAJOR(ROOT_DEV) == MEM_MAJOR) {
+ if (mount_pramfs_root())
+ return;
+
+ printk(KERN_ERR "VFS: Unable to mount root fs via PRAMFS, trying floppy.\n");
+ ROOT_DEV = Root_FD0;
+ }
+#endif
#ifdef CONFIG_ROOT_NFS
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
if (mount_nfs_root())
^ permalink raw reply
* [PATCH 03/14] Pramfs: Documentation
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
Documentation.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/Documentation/filesystems/pramfs.txt linux-2.6.30/Documentation/filesystems/pramfs.txt
--- linux-2.6.30-orig/Documentation/filesystems/pramfs.txt 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/Documentation/filesystems/pramfs.txt 2009-06-13 12:57:32.000000000 +0200
@@ -0,0 +1,227 @@
+
+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 straight-forward 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, reiserfs, etc.
+
+But the disk-based fs over non-volatile RAM block driver approach has
+some drawbacks:
+
+1. Disk-based filesystems such as ext2/ext3 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. If the backing-store RAM is comparable in access speed to system memory,
+ there's really no point in caching the file I/O data in the page
+ cache. 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 a new filesystem be used that always performs direct
+ I/O by default.
+
+The Persistent/Protected RAM Special Filesystem (PRAMFS) is a
+full-featured 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 exist 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 is also 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 pte is
+marked read-only again. This feature provides some protection against
+filesystem corruption caused by errant writes into the RAM due to
+kernel bugs for instance. In case there are systems where the write
+protection is not possible (for instance the RAM cannot be mapped
+with page tables), this feature can be disabled with the CONFIG_PRAMFS_NOWP
+config option.
+
+In summary, PRAMFS is a light-weight, full-featured, and space-efficient
+special filesystem that is ideal for systems with a block of fast
+non-volatile RAM that need to access data on it using a standard
+filesytem interface.
+
+
+Supported mount options
+=======================
+
+The PRAMFS currently requires one mount option, and there are several
+optional mount options:
+
+physaddr= Required. It tells PRAMFS the physical address of the
+ start of the RAM that makes up the filesystem. The
+ physical address must be located on a page boundary.
+
+init= Optional. It is used to initialize the memory to an
+ empty filesystem. Any data in an existing filesystem
+ will be lost if this option is given. The parameter to
+ "init=" is the RAM in kilo/mega/giga bytes.
+
+bs= Optional. It is used to specify a block size. It is
+ ignored if the "init=" option is not specified, since
+ otherwise the block size is read from the PRAMFS
+ super-block. The default blocksize is 2048 bytes,
+ and the allowed block sizes are 512, 1024, 2048, and
+ 4096.
+
+bpi= Optional. It is used to specify the bytes per inode
+ ratio, i.e. For every N bytes in the filesystem, an
+ inode will be created. This behaves the same as the "-i"
+ option to mke2fs. It is ignored if the "init=" option is
+ not specified.
+
+N= Optional. It is used to specify the number of inodes to
+ allocate in the inode table. If the option is not
+ specified, the bytes-per-inode ratio is used the
+ calculate the number of inodes. If neither the "N=" or
+ "bpi=" options are specified, the default behavior is to
+ reserve 5% of the total space in the filesystem for the
+ inode table. This option behaves the same as the "-N"
+ option to mke2fs. It is ignored if the "init=" option is
+ not specified.
+
+Examples:
+
+mount -t pramfs -o physaddr=0x20000000,init=1M,bs=1k none /mnt/pram
+
+This example locates the filesystem at physical address 0x20000000, and
+also requests an empty filesystem be initialized, of total size of one
+megabytes and blocksize of one kilobytes. The mount point is /mnt/pram.
+
+mount -t pramfs -o physaddr=0x20000000 none /mnt/pram
+
+This example locates the filesystem at physical address 0x20000000 as in
+the first example, but uses the intact filesystem that already exists.
+
+
+Current Limitations
+===================
+
+- The RAM used for PRAMFS must be directly addressable.
+
+- PRAMFS does not support hard links.
+
+- PRAMFS supports only private memory mappings. This allows most
+ executables to run, but programs that attempt shared memory
+ mappings, such as X apps that use X shared memory, will fail.
+
+Further Documentation
+=====================
+
+If you are interested in the internal design of PRAMFS, there is
+documentation available at the Sourceforge PRAMFS home page at
+http://pramfs.sourceforge.net.
+
+Please send bug reports/comments/feed back to the pramfs development
+list at sourceforge: pramfs-devel@lists.sourceforge.net.
+
+
+ChangeLog
+=========
+
+1.1.3:
+ - kernel 2.6.30
+ - replaced DQUOT macros with vfs_dq_* functions in inode.c
+
+1.1.2:
+ - kernel 2.6.29
+ - replaced current->fsuid and current->fsgid in inode.c with
+ current_fsuid() and current_fsgid() macro
+ - replaced pram_fsync with simple_file_sync (deleted fsync.c)
+ - removed ioctl.c
+ - fix the minus inside pram_sync_super and pram_sync_inode
+ inline functions
+ - now flags must be explicit in pram_lock/unlock_inode,
+ pram_lock/unlock_super and in pram_lock/unlock_block
+ - fix compiler warning about unused flags variable
+ - now multiple instances of pramfs are allowed
+ - added management of mode, uid and gid mount options
+ - renamed find_pramfs_super() in pram_get_super() and changed its
+ behaviour to remove the dependecy from a kernel symbol not exported
+ - added superblock operation pram_show_options
+ - added pram_parse_options function
+ - added checks for some mount parameters to avoid kernel crashes
+ - now a physical address of zero is allowed
+ - added the use of request_mem_region_exclusive
+ - now phys_addr in the struct pram_sb_info is phys_addr_t type
+
+1.1.1:
+ - kernel 2.6.28.1
+ - now the code is compliant to kernel coding style
+ - replaced typedef pram_off_t with the standard off_t
+
+1.1.0
+ - kernel 2.6.27
+ - added xip feature.
+
+1.0.4:
+ - kernel 2.6.10
+ - include <asm/tlbflush.h> in wprotect.c for
+ flush_tlb_kernel_range().
+ - fixed a bug in pram_mknod(). The pramfs inode needs
+ updating after calling init_special_inode() to update
+ the rdev.
+1.0.3:
+ - kernel 2.6.9.
+ - __ioremap() definition not consistent across archs, use
+ ioremap() instead.
+ - flush_tlb_kernel_page() is only available on some archs.
+ - fixed bug in pram_fill_super(): root inode pointer needs
+ to be recalculated after remapping whole fs.
+1.0.2:
+ - kernel 2.6.4.
+ - use pram_truncate() in pram_delete_inode().
+ - dangling pram_lock_inode() removed in pram_truncate_blocks().
+ - edits to this README
+
+1.0.1:
+ - port to kernel 2.6.3.
+ - implement direct_IO() method instead of custom file read/write
+ methods.
+ - do away with __ioremap_readonly() requirement.
+ - implement inode truncate() method.
+
+1.0.0:
+ - Started ChangeLog (kernel 2.4.22).
+
+
^ permalink raw reply
* [PATCH 02/14] Pramfs: File operations for directories
From: Marco @ 2009-06-13 13:21 UTC (permalink / raw)
To: Linux FS Devel; +Cc: Linux Embedded, Linux Kernel, Daniel Walker
From: Marco Stornelli <marco.stornelli@gmail.com>
File operations for directories.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.30-orig/fs/pramfs/dir.c linux-2.6.30/fs/pramfs/dir.c
--- linux-2.6.30-orig/fs/pramfs/dir.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.30/fs/pramfs/dir.c 2009-06-13 12:51:46.000000000 +0200
@@ -0,0 +1,220 @@
+/*
+ * FILE NAME fs/pramfs/dir.c
+ *
+ * BRIEF DESCRIPTION
+ *
+ * File operations for directories.
+ *
+ * Copyright 2009 Marco Stornelli <marco.stornelli@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_fs.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;
+ off_t tail_ino, prev_ino;
+ unsigned long flags;
+
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len > PRAM_NAME_LEN ?
+ PRAM_NAME_LEN : dentry->d_name.len;
+
+ flags = 0;
+
+ 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 = pidir->i_type.dir.tail;
+ if (tail_ino != 0) {
+ pitail = pram_get_inode(dir->i_sb, tail_ino);
+ pram_lock_inode(pitail, flags);
+ pitail->i_d.d_next = inode->i_ino;
+ pram_unlock_inode(pitail, flags);
+
+ prev_ino = tail_ino;
+
+ pram_lock_inode(pidir, flags);
+ pidir->i_type.dir.tail = inode->i_ino;
+ pidir->i_mtime = dir->i_mtime.tv_sec;
+ pidir->i_ctime = dir->i_ctime.tv_sec;
+ pram_unlock_inode(pidir, flags);
+ } else {
+ /* the directory is empty */
+ prev_ino = 0;
+
+ pram_lock_inode(pidir, flags);
+ pidir->i_type.dir.head = pidir->i_type.dir.tail = inode->i_ino;
+ pidir->i_mtime = dir->i_mtime.tv_sec;
+ pidir->i_ctime = dir->i_ctime.tv_sec;
+ pram_unlock_inode(pidir, flags);
+ }
+
+
+ pram_lock_inode(pi, flags);
+ pi->i_d.d_prev = prev_ino;
+ pi->i_d.d_parent = dir->i_ino;
+ memcpy(pi->i_d.d_name, name, namelen);
+ pi->i_d.d_name[namelen] = '\0';
+ pram_unlock_inode(pi, flags);
+ 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;
+ unsigned long flags;
+
+ flags = 0;
+
+ pi = pram_get_inode(sb, inode->i_ino);
+ pidir = pram_get_inode(sb, pi->i_d.d_parent);
+ if (!pidir)
+ return -EACCES;
+
+ if (inode->i_ino == pidir->i_type.dir.head) {
+ /* first inode in directory */
+ next = pram_get_inode(sb, pi->i_d.d_next);
+
+ if (next) {
+ pram_lock_inode(next, flags);
+ next->i_d.d_prev = 0;
+ pram_unlock_inode(next, flags);
+
+ pram_lock_inode(pidir, flags);
+ pidir->i_type.dir.head = pi->i_d.d_next;
+ } else {
+ pram_lock_inode(pidir, flags);
+ pidir->i_type.dir.head = pidir->i_type.dir.tail = 0;
+ }
+ pram_unlock_inode(pidir, flags);
+ } else if (inode->i_ino == pidir->i_type.dir.tail) {
+ /* last inode in directory */
+ prev = pram_get_inode(sb, pi->i_d.d_prev);
+
+ pram_lock_inode(prev, flags);
+ prev->i_d.d_next = 0;
+ pram_unlock_inode(prev, flags);
+
+ pram_lock_inode(pidir, flags);
+ pidir->i_type.dir.tail = pi->i_d.d_prev;
+ pram_unlock_inode(pidir, flags);
+ } else {
+ /* somewhere in the middle */
+ prev = pram_get_inode(sb, pi->i_d.d_prev);
+ next = pram_get_inode(sb, pi->i_d.d_next);
+
+ if (prev && next) {
+ pram_lock_inode(prev, flags);
+ prev->i_d.d_next = pi->i_d.d_next;
+ pram_unlock_inode(prev, flags);
+
+ pram_lock_inode(next, flags);
+ next->i_d.d_prev = pi->i_d.d_prev;
+ pram_unlock_inode(next, flags);
+ }
+ }
+
+ pram_lock_inode(pi, flags);
+ pi->i_d.d_next = pi->i_d.d_prev = pi->i_d.d_parent = 0;
+ pram_unlock_inode(pi, flags);
+
+ return 0;
+}
+
+#define S_SHIFT 12
+static unsigned int dtype_by_mode[S_IFMT >> S_SHIFT] = {
+ [S_IFREG >> S_SHIFT] DT_REG,
+ [S_IFDIR >> S_SHIFT] DT_DIR,
+ [S_IFCHR >> S_SHIFT] DT_CHR,
+ [S_IFBLK >> S_SHIFT] DT_BLK,
+ [S_IFIFO >> S_SHIFT] DT_FIFO,
+ [S_IFSOCK >> S_SHIFT] DT_SOCK,
+ [S_IFLNK >> S_SHIFT] DT_LNK,
+};
+
+static int
+pram_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct pram_inode *pi;
+ int namelen, ret = 0;
+ char *name;
+ ino_t ino;
+
+ if (filp->f_pos >> 32)
+ return 0;
+
+ pi = pram_get_inode(sb, inode->i_ino);
+
+ switch ((unsigned long)filp->f_pos) {
+ case 0:
+ ret = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR);
+ filp->f_pos++;
+ return ret;
+ case 1:
+ ret = filldir(dirent, "..", 2, 1, pi->i_d.d_parent, DT_DIR);
+ ino = pi->i_type.dir.head;
+ filp->f_pos = ino ? ino : 2;
+ return ret;
+ case 2:
+ ino = pi->i_type.dir.head;
+ if (ino) {
+ filp->f_pos = ino;
+ pi = pram_get_inode(sb, ino);
+ break;
+ } else {
+ /* the directory is empty */
+ filp->f_pos = 2;
+ return 0;
+ }
+ case 3:
+ return 0;
+ default:
+ ino = filp->f_pos;
+ pi = pram_get_inode(sb, ino);
+ break;
+ }
+
+ while (pi && !pi->i_links_count) {
+ ino = filp->f_pos = pi->i_d.d_next;
+ pi = pram_get_inode(sb, ino);
+ }
+
+ if (pi) {
+ name = pi->i_d.d_name;
+ namelen = strlen(name);
+
+ ret = filldir(dirent, name, namelen,
+ filp->f_pos, ino,
+ dtype_by_mode[(pi->i_mode & S_IFMT)>>S_SHIFT]);
+ filp->f_pos = pi->i_d.d_next ? pi->i_d.d_next : 3;
+ } else
+ filp->f_pos = 3;
+
+ return ret;
+}
+
+struct file_operations pram_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = pram_readdir,
+ .fsync = simple_sync_file,
+};
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox