summaryrefslogtreecommitdiff
path: root/yaffs_vfs_single.c
diff options
context:
space:
mode:
Diffstat (limited to 'yaffs_vfs_single.c')
-rw-r--r--yaffs_vfs_single.c676
1 files changed, 222 insertions, 454 deletions
diff --git a/yaffs_vfs_single.c b/yaffs_vfs_single.c
index 1893125..f822845 100644
--- a/yaffs_vfs_single.c
+++ b/yaffs_vfs_single.c
@@ -1,7 +1,7 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002-2010 Aleph One Ltd.
+ * Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
@@ -36,7 +36,6 @@
* a single version and should not include any multi-version code.
*/
#include <linux/version.h>
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -54,27 +53,8 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/freezer.h>
-
#include <asm/div64.h>
-
#include <linux/statfs.h>
-
-#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
-
-#define YPROC_ROOT NULL
-
-#define Y_INIT_TIMER(a) init_timer_on_stack(a)
-
-#define WRITE_SIZE_STR "writesize"
-#define WRITE_SIZE(mtd) ((mtd)->writesize)
-
-static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
-{
- uint64_t result = partition_size;
- do_div(result, block_size);
- return (uint32_t) result;
-}
-
#include <linux/uaccess.h>
#include <linux/mtd/mtd.h>
@@ -82,9 +62,7 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
-
#include "yaffs_linux.h"
-
#include "yaffs_mtdif.h"
#include "yaffs_mtdif1.h"
#include "yaffs_mtdif2.h"
@@ -94,6 +72,7 @@ unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
unsigned int yaffs_auto_checkpoint = 1;
unsigned int yaffs_gc_control = 1;
unsigned int yaffs_bg_enable = 1;
+unsigned int yaffs_auto_select = 1;
/* Module Parameters */
module_param(yaffs_trace_mask, uint, 0644);
@@ -101,16 +80,27 @@ module_param(yaffs_wr_attempts, uint, 0644);
module_param(yaffs_auto_checkpoint, uint, 0644);
module_param(yaffs_gc_control, uint, 0644);
module_param(yaffs_bg_enable, uint, 0644);
+module_param(yaffs_auto_select, uint, 0644);
+
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+ uint64_t result = partition_size;
+ do_div(result, block_size);
+ return (uint32_t) result;
+}
#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
-#define yaffs_inode_to_obj(iptr) ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
+#define yaffs_inode_to_obj(iptr)\
+ ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
- } while(0)
+ } while (0)
static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
@@ -156,7 +146,6 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
yaffs_gross_lock(dev);
obj = yaffs_find_by_number(dev, inode->i_ino);
-
yaffs_fill_inode_from_obj(inode, obj);
yaffs_gross_unlock(dev);
@@ -203,13 +192,10 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
{
struct inode *inode;
-
struct yaffs_obj *obj = NULL;
struct yaffs_dev *dev;
-
struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
-
- int error = -ENOSPC;
+ int error;
uid_t uid = current->cred->fsuid;
gid_t gid =
(dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid;
@@ -217,17 +203,17 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
- if (parent) {
- yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_mknod: parent object %d type %d",
- parent->obj_id, parent->variant_type);
- } else {
+ if (!parent) {
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_mknod: could not get parent object");
return -EPERM;
}
yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod: parent object %d type %d",
+ parent->obj_id, parent->variant_type);
+
+ yaffs_trace(YAFFS_TRACE_OS,
"yaffs_mknod: making oject for %s, mode %x dev %x",
dentry->d_name.name, mode, rdev);
@@ -235,6 +221,11 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
yaffs_gross_lock(dev);
+ if (yaffs_get_n_free_chunks(dev) < 1) {
+ error = -ENOSPC;
+ goto err_out;
+ }
+
switch (mode & S_IFMT) {
default:
/* Special (socket, fifo, device...) */
@@ -259,24 +250,29 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
break;
}
+ if (!obj) {
+ error = -ENOMEM;
+ goto err_out;
+ }
+
/* Can not call yaffs_get_inode() with gross lock held */
yaffs_gross_unlock(dev);
- if (obj) {
- inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
- d_instantiate(dentry, inode);
- update_dir_time(dir);
- yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_mknod created object %d count = %d",
- obj->obj_id, atomic_read(&inode->i_count));
- error = 0;
- yaffs_fill_inode_from_obj(dir, parent);
- } else {
- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
- error = -ENOMEM;
- }
+ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_mknod created object %d count = %d",
+ obj->obj_id, atomic_read(&inode->i_count));
+ yaffs_fill_inode_from_obj(dir, parent);
+ return 0;
+
+err_out:
+ yaffs_gross_unlock(dev);
+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod error %d", error);
return error;
+
}
static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
@@ -335,6 +331,7 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
+ struct inode *inode;
uid_t uid = current->cred->fsuid;
gid_t gid =
(dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid;
@@ -347,19 +344,17 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
S_IFLNK | S_IRWXUGO, uid, gid, symname);
yaffs_gross_unlock(dev);
- if (obj) {
- struct inode *inode;
-
- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
- d_instantiate(dentry, inode);
- update_dir_time(dir);
- yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
- return 0;
- } else {
+ if (!obj) {
yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
+ return -ENOMEM;
}
- return -ENOMEM;
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ d_instantiate(dentry, inode);
+ update_dir_time(dir);
+ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
+
+ return 0;
}
static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
@@ -367,7 +362,6 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
{
struct yaffs_obj *obj;
struct inode *inode = NULL;
-
struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
if (current != yaffs_dev_to_lc(dev)->readdir_process)
@@ -411,7 +405,6 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
{
int ret_val;
-
struct yaffs_dev *dev;
struct yaffs_obj *obj;
@@ -512,6 +505,7 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode;
int error = 0;
struct yaffs_dev *dev;
+ int result;
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_setattr of object %d",
@@ -521,17 +515,15 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
error = -EINVAL;
- if (error == 0)
+ if (!error)
error = inode_change_ok(inode, attr);
- if (error == 0) {
- int result;
- if (!error) {
- setattr_copy(inode, attr);
- yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
- if (attr->ia_valid & ATTR_SIZE) {
- truncate_setsize(inode, attr->ia_size);
- inode->i_blocks = (inode->i_size + 511) >> 9;
- }
+
+ if (!error) {
+ setattr_copy(inode, attr);
+ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
+ if (attr->ia_valid & ATTR_SIZE) {
+ truncate_setsize(inode, attr->ia_size);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
}
dev = yaffs_inode_to_obj(inode)->my_dev;
if (attr->ia_valid & ATTR_SIZE) {
@@ -539,15 +531,12 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
(int)(attr->ia_size),
(int)(attr->ia_size));
}
+
yaffs_gross_lock(dev);
result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
- if (result == YAFFS_OK) {
- error = 0;
- } else {
+ if (result != YAFFS_OK)
error = -EPERM;
- }
yaffs_gross_unlock(dev);
-
}
yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
@@ -555,39 +544,31 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
return error;
}
-#ifdef CONFIG_YAFFS_XATTR
static int yaffs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
- int error = 0;
+ int error;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
- if (error == 0) {
- int result;
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- result = yaffs_set_xattrib(obj, name, value, size, flags);
- if (result == YAFFS_OK)
- error = 0;
- else if (result < 0)
- error = result;
- yaffs_gross_unlock(dev);
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_set_xattrib(obj, name, value, size, flags);
+ yaffs_gross_unlock(dev);
- }
yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
return error;
}
-static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buff,
- size_t size)
+static ssize_t yaffs_getxattr(struct dentry *dentry, const char *name,
+ void *buff, size_t size)
{
struct inode *inode = dentry->d_inode;
- int error = 0;
+ int error;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
@@ -595,13 +576,11 @@ static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *bu
"yaffs_getxattr \"%s\" from object %d",
name, obj->obj_id);
- if (error == 0) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- error = yaffs_get_xattrib(obj, name, buff, size);
- yaffs_gross_unlock(dev);
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_get_xattrib(obj, name, buff, size);
+ yaffs_gross_unlock(dev);
- }
yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
return error;
@@ -610,56 +589,45 @@ static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *bu
static int yaffs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
- int error = 0;
+ int error;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_removexattr of object %d", obj->obj_id);
- if (error == 0) {
- int result;
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- result = yaffs_remove_xattrib(obj, name);
- if (result == YAFFS_OK)
- error = 0;
- else if (result < 0)
- error = result;
- yaffs_gross_unlock(dev);
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_remove_xattrib(obj, name);
+ yaffs_gross_unlock(dev);
- }
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_removexattr done returning %d", error);
return error;
}
-static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
+static ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
{
struct inode *inode = dentry->d_inode;
- int error = 0;
+ int error;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_listxattr of object %d", obj->obj_id);
- if (error == 0) {
- dev = obj->my_dev;
- yaffs_gross_lock(dev);
- error = yaffs_list_xattrib(obj, buff, size);
- yaffs_gross_unlock(dev);
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ error = yaffs_list_xattrib(obj, buff, size);
+ yaffs_gross_unlock(dev);
- }
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_listxattr done returning %d", error);
return error;
}
-#endif
-
static const struct inode_operations yaffs_dir_inode_operations = {
.create = yaffs_create,
.lookup = yaffs_lookup,
@@ -671,12 +639,10 @@ static const struct inode_operations yaffs_dir_inode_operations = {
.mknod = yaffs_mknod,
.rename = yaffs_rename,
.setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
.listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
-#endif
};
/*-----------------------------------------------------------------*/
/* Directory search context allows us to unlock access to yaffs during
@@ -715,18 +681,21 @@ static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
struct yaffs_dev *dev = dir->my_dev;
struct yaffs_search_context *sc =
kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
- if (sc) {
- sc->dir_obj = dir;
- sc->dev = dev;
- if (list_empty(&sc->dir_obj->variant.dir_variant.children))
- sc->next_return = NULL;
- else
- sc->next_return =
- list_entry(dir->variant.dir_variant.children.next,
- struct yaffs_obj, siblings);
- INIT_LIST_HEAD(&sc->others);
- list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
- }
+
+ if (!sc)
+ return NULL;
+
+ sc->dir_obj = dir;
+ sc->dev = dev;
+ if (list_empty(&sc->dir_obj->variant.dir_variant.children))
+ sc->next_return = NULL;
+ else
+ sc->next_return =
+ list_entry(dir->variant.dir_variant.children.next,
+ struct yaffs_obj, siblings);
+ INIT_LIST_HEAD(&sc->others);
+ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
+
return sc;
}
@@ -799,7 +768,6 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
unsigned long offset, curoffs;
struct yaffs_obj *l;
int ret_val = 0;
-
char name[YAFFS_MAX_NAME_LENGTH + 1];
obj = yaffs_dentry_to_obj(f->f_dentry);
@@ -909,11 +877,10 @@ static const struct file_operations yaffs_dir_operations = {
static int yaffs_file_flush(struct file *file, fl_owner_t id)
{
struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
-
struct yaffs_dev *dev = obj->my_dev;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_file_flush object %d (%s)",
+ "yaffs_file_flush object %d (%s)",
obj->obj_id, obj->dirty ? "dirty" : "clean");
yaffs_gross_lock(dev);
@@ -991,7 +958,6 @@ struct dentry *yaffs2_get_parent(struct dentry *dentry)
}
}
}
-
return parent;
}
@@ -1013,7 +979,6 @@ static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
{
unsigned char *alias;
int ret;
-
struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
yaffs_gross_lock(dev);
@@ -1127,7 +1092,6 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg)
struct yaffs_obj *obj;
unsigned char *pg_buf;
int ret;
-
struct yaffs_dev *dev;
yaffs_trace(YAFFS_TRACE_OS,
@@ -1172,6 +1136,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg)
static int yaffs_readpage_unlock(struct file *f, struct page *pg)
{
int ret = yaffs_readpage_nolock(f, pg);
+
unlock_page(pg);
return ret;
}
@@ -1268,18 +1233,17 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
return (n_written == n_bytes) ? 0 : -ENOSPC;
}
-/* Space holding and freeing is done to ensure we have space available for
+/* Space holding and freeing is done to ensure we have space available for
* write_begin/end.
* For now we just assume few parallel writes and check against a small
* number.
- * Todo: need to do this with a counter to handle parallel reads better.
+ * Todo: need to do this with a counter to handle parallel reads better
*/
static ssize_t yaffs_hold_space(struct file *f)
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
-
int n_free_chunks;
obj = yaffs_dentry_to_obj(f->f_dentry);
@@ -1315,7 +1279,6 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
{
struct page *pg = NULL;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-
int ret = 0;
int space_held = 0;
@@ -1365,7 +1328,7 @@ out:
}
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
- loff_t * pos)
+ loff_t *pos)
{
struct yaffs_obj *obj;
int n_written, ipos;
@@ -1375,11 +1338,11 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
obj = yaffs_dentry_to_obj(f->f_dentry);
if (!obj) {
- /* This should not happen */
+ /* This should not happen */
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_file_write: hey obj is null!");
- return -ENINVAL;
- }
+ return -EINVAL;
+ }
dev = obj->my_dev;
@@ -1415,7 +1378,6 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
"yaffs_file_write size updated to %d bytes, %d blocks",
ipos, (int)(inode->i_blocks));
}
-
}
yaffs_gross_unlock(dev);
return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
@@ -1474,11 +1436,12 @@ static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
bytes_in_dev =
((uint64_t)
- ((dev->param.end_block - dev->param.start_block +
- 1))) * ((uint64_t) (dev->param.chunks_per_block *
+ ((dev->param.end_block - dev->param.start_block + 1))) *
+ ((uint64_t) (dev->param.chunks_per_block *
dev->data_bytes_per_chunk));
- do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
+ do_div(bytes_in_dev, sb->s_blocksize);
+ /* bytes_in_dev becomes the number of blocks */
buf->f_blocks = bytes_in_dev;
bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
@@ -1534,6 +1497,7 @@ static void yaffs_flush_inodes(struct super_block *sb)
static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
{
struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+
if (!dev)
return;
@@ -1602,7 +1566,7 @@ static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
* yaffs_bg_start() launches the background thread.
* yaffs_bg_stop() cleans up the background thread.
*
- * NB:
+ * NB:
* The thread should only run after the yaffs is initialised
* The thread should be stopped before yaffs is unmounted.
* The thread should not do any writing while the fs is in read only.
@@ -1622,7 +1586,6 @@ static int yaffs_bg_thread_fn(void *data)
unsigned long next_gc = now;
unsigned long expires;
unsigned int urgency;
-
int gc_result;
struct timer_list timer;
@@ -1659,12 +1622,12 @@ static int yaffs_bg_thread_fn(void *data)
else
next_gc = now + HZ * 2;
} else {
- /*
+ /*
* gc not running so set to next_dir_update
* to cut down on wake ups
*/
next_gc = next_dir_update;
- }
+ }
}
yaffs_gross_unlock(dev);
expires = next_dir_update;
@@ -1673,7 +1636,7 @@ static int yaffs_bg_thread_fn(void *data)
if (time_before(expires, now))
expires = now + HZ;
- Y_INIT_TIMER(&timer);
+ init_timer_on_stack(&timer);
timer.expires = expires + 1;
timer.data = (unsigned long)current;
timer.function = yaffs_background_waker;
@@ -1745,12 +1708,9 @@ static int yaffs_sync_fs(struct super_block *sb, int wait)
return 0;
}
-
static LIST_HEAD(yaffs_context_list);
struct mutex yaffs_context_lock;
-
-
struct yaffs_options {
int inband_tags;
int skip_checkpoint_read;
@@ -1766,7 +1726,7 @@ struct yaffs_options {
#define MAX_OPT_LEN 30
static int yaffs_parse_options(struct yaffs_options *options,
- const char *options_str)
+ const char *options_str)
{
char cur_opt[MAX_OPT_LEN + 1];
int p;
@@ -1824,11 +1784,10 @@ static int yaffs_parse_options(struct yaffs_options *options,
error = 1;
}
}
-
return error;
}
-static struct address_space_operations yaffs_file_address_operations = {
+static const struct address_space_operations yaffs_file_address_operations = {
.readpage = yaffs_readpage,
.writepage = yaffs_writepage,
.write_begin = yaffs_write_begin,
@@ -1839,12 +1798,10 @@ static struct address_space_operations yaffs_file_address_operations = {
static const struct inode_operations yaffs_file_inode_operations = {
.setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
.listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
-#endif
};
static const struct inode_operations yaffs_symlink_inode_operations = {
@@ -1852,104 +1809,97 @@ static const struct inode_operations yaffs_symlink_inode_operations = {
.follow_link = yaffs_follow_link,
.put_link = yaffs_put_link,
.setattr = yaffs_setattr,
-#ifdef CONFIG_YAFFS_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
.listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
-#endif
};
static void yaffs_fill_inode_from_obj(struct inode *inode,
struct yaffs_obj *obj)
{
- if (inode && obj) {
-
- /* Check mode against the variant type and attempt to repair if broken. */
- u32 mode = obj->yst_mode;
- switch (obj->variant_type) {
- case YAFFS_OBJECT_TYPE_FILE:
- if (!S_ISREG(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFREG;
- }
+ u32 mode;
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- if (!S_ISLNK(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFLNK;
- }
+ if (!inode || !obj) {
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_fill_inode invalid parameters");
+ return;
+ }
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- if (!S_ISDIR(mode)) {
- obj->yst_mode &= ~S_IFMT;
- obj->yst_mode |= S_IFDIR;
- }
+ /* Check mode against the variant type
+ * and attempt to repair if broken. */
+ mode = obj->yst_mode;
- break;
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- case YAFFS_OBJECT_TYPE_HARDLINK:
- case YAFFS_OBJECT_TYPE_SPECIAL:
- default:
- /* TODO? */
- break;
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (!S_ISREG(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFREG;
}
-
- inode->i_flags |= S_NOATIME;
-
- inode->i_ino = obj->obj_id;
- inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
-
- inode->i_rdev = old_decode_dev(obj->yst_rdev);
-
- inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
- inode->i_atime.tv_nsec = 0;
- inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
- inode->i_mtime.tv_nsec = 0;
- inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
- inode->i_ctime.tv_nsec = 0;
- inode->i_size = yaffs_get_obj_length(obj);
- inode->i_blocks = (inode->i_size + 511) >> 9;
-
- inode->i_nlink = yaffs_get_obj_link_count(obj);
-
- yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_fill_inode mode %x uid %d gid %d size %d count %d",
- inode->i_mode, inode->i_uid, inode->i_gid,
- (int)inode->i_size, atomic_read(&inode->i_count));
-
- switch (obj->yst_mode & S_IFMT) {
- default: /* fifo, device or socket */
- init_special_inode(inode, obj->yst_mode,
- old_decode_dev(obj->yst_rdev));
- break;
- case S_IFREG: /* file */
- inode->i_op = &yaffs_file_inode_operations;
- inode->i_fop = &yaffs_file_operations;
- inode->i_mapping->a_ops =
- &yaffs_file_address_operations;
- break;
- case S_IFDIR: /* directory */
- inode->i_op = &yaffs_dir_inode_operations;
- inode->i_fop = &yaffs_dir_operations;
- break;
- case S_IFLNK: /* symlink */
- inode->i_op = &yaffs_symlink_inode_operations;
- break;
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ if (!S_ISLNK(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFLNK;
+ }
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ if (!S_ISDIR(mode)) {
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFDIR;
}
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ default:
+ /* TODO? */
+ break;
+ }
- yaffs_inode_to_obj_lv(inode) = obj;
+ inode->i_flags |= S_NOATIME;
+ inode->i_ino = obj->obj_id;
+ inode->i_mode = obj->yst_mode;
+ inode->i_uid = obj->yst_uid;
+ inode->i_gid = obj->yst_gid;
- obj->my_inode = inode;
+ inode->i_rdev = old_decode_dev(obj->yst_rdev);
- } else {
- yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_fill_inode invalid parameters");
+ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_size = yaffs_get_obj_length(obj);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+ inode->i_nlink = yaffs_get_obj_link_count(obj);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_fill_inode mode %x uid %d gid %d size %d count %d",
+ inode->i_mode, inode->i_uid, inode->i_gid,
+ (int)inode->i_size, atomic_read(&inode->i_count));
+
+ switch (obj->yst_mode & S_IFMT) {
+ default: /* fifo, device or socket */
+ init_special_inode(inode, obj->yst_mode,
+ old_decode_dev(obj->yst_rdev));
+ break;
+ case S_IFREG: /* file */
+ inode->i_op = &yaffs_file_inode_operations;
+ inode->i_fop = &yaffs_file_operations;
+ inode->i_mapping->a_ops = &yaffs_file_address_operations;
+ break;
+ case S_IFDIR: /* directory */
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+ break;
+ case S_IFLNK: /* symlink */
+ inode->i_op = &yaffs_symlink_inode_operations;
+ break;
}
+
+ yaffs_inode_to_obj_lv(inode) = obj;
+ obj->my_inode = inode;
}
static void yaffs_put_super(struct super_block *sb)
@@ -2018,11 +1968,8 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
char *data_str = (char *)data;
struct yaffs_linux_context *context = NULL;
struct yaffs_param *param;
-
int read_only = 0;
-
struct yaffs_options options;
-
unsigned mount_id;
int found;
struct yaffs_linux_context *context_iterator;
@@ -2031,7 +1978,7 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
if (!sb) {
printk(KERN_INFO "yaffs: sb is NULL\n");
return NULL;
- }
+ }
sb->s_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops;
@@ -2057,10 +2004,9 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
memset(&options, 0, sizeof(options));
- if (yaffs_parse_options(&options, data_str)) {
+ if (yaffs_parse_options(&options, data_str))
/* Option parsing failed */
return NULL;
- }
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -2102,25 +2048,21 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
yaffs_trace(YAFFS_TRACE_OS, " writeoob %p", mtd->write_oob);
yaffs_trace(YAFFS_TRACE_OS, " block_isbad %p", mtd->block_isbad);
yaffs_trace(YAFFS_TRACE_OS, " block_markbad %p", mtd->block_markbad);
- yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
+ yaffs_trace(YAFFS_TRACE_OS, " writesize %d", mtd->writesize);
yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
-#ifdef CONFIG_YAFFS_AUTO_YAFFS2
-
- if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
+ if (yaffs_auto_select && yaffs_version == 1 && mtd->writesize >= 2048) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
yaffs_version = 2;
}
- /* Added NCB 26/5/2006 for completeness */
- if (yaffs_version == 2 && !options.inband_tags
- && WRITE_SIZE(mtd) == 512) {
+ if (yaffs_auto_select && yaffs_version == 2 && !options.inband_tags &&
+ mtd->writesize == 512) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
yaffs_version = 1;
}
-#endif
if (yaffs_version == 2) {
/* Check for version 2 style functions */
@@ -2134,7 +2076,7 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
return NULL;
}
- if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+ if ((mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
!options.inband_tags) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
@@ -2151,7 +2093,7 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
return NULL;
}
- if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+ if (mtd->writesize < YAFFS_BYTES_PER_CHUNK ||
mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"MTD device does not support have the right page sizes");
@@ -2175,10 +2117,8 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
if (!dev || !context) {
- if (dev)
- kfree(dev);
- if (context)
- kfree(context);
+ kfree(dev);
+ kfree(context);
dev = NULL;
context = NULL;
}
@@ -2219,40 +2159,19 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
param->n_caches = (options.no_cache) ? 0 : 10;
param->inband_tags = options.inband_tags;
-#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
param->disable_lazy_load = 1;
-#endif
-#ifdef CONFIG_YAFFS_XATTR
param->enable_xattr = 1;
-#endif
if (options.lazy_loading_overridden)
param->disable_lazy_load = !options.lazy_loading_enabled;
-#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
- param->no_tags_ecc = 1;
-#endif
-
-#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
-#else
param->defered_dir_update = 1;
-#endif
if (options.tags_ecc_overridden)
param->no_tags_ecc = !options.tags_ecc_on;
-#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
param->empty_lost_n_found = 1;
-#endif
-#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
- param->refresh_period = 0;
-#else
param->refresh_period = 500;
-#endif
-
-#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
- param->always_check_erased = 1;
-#endif
if (options.empty_lost_and_found_overridden)
param->empty_lost_n_found = options.empty_lost_and_found;
@@ -2263,8 +2182,8 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
param->bad_block_fn = nandmtd2_mark_block_bad;
param->query_block_fn = nandmtd2_query_block;
- yaffs_dev_to_lc(dev)->spare_buffer =
- kmalloc(mtd->oobsize, GFP_NOFS);
+ yaffs_dev_to_lc(dev)->spare_buffer =
+ kmalloc(mtd->oobsize, GFP_NOFS);
param->is_yaffs2 = 1;
param->total_bytes_per_chunk = mtd->writesize;
param->chunks_per_block = mtd->erasesize / mtd->writesize;
@@ -2291,22 +2210,19 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
yaffs_dev_to_lc(dev)->super = sb;
-#ifndef CONFIG_YAFFS_DOES_ECC
param->use_nand_ecc = 1;
-#endif
param->skip_checkpt_rd = options.skip_checkpoint_read;
param->skip_checkpt_wr = options.skip_checkpoint_write;
mutex_lock(&yaffs_context_lock);
/* Get a mount id */
- found = 0;
- for (mount_id = 0; !found; mount_id++) {
+ for (mount_id = 0, found = 0; !found; mount_id++) {
found = 1;
list_for_each(l, &yaffs_context_list) {
context_iterator =
- list_entry(l, struct yaffs_linux_context,
- context_list);
+ list_entry(l, struct yaffs_linux_context,
+ context_list);
if (context_iterator->mount_id == mount_id)
found = 0;
}
@@ -2393,8 +2309,6 @@ static struct file_system_type yaffs_fs_type = {
.fs_flags = FS_REQUIRES_DEV,
};
-#ifdef CONFIG_YAFFS_YAFFS2
-
static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
int silent)
{
@@ -2416,13 +2330,14 @@ static struct file_system_type yaffs2_fs_type = {
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
-#endif /* CONFIG_YAFFS_YAFFS2 */
+
static struct proc_dir_entry *my_proc_entry;
static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
{
struct yaffs_param *param = &dev->param;
+
buf += sprintf(buf, "start_block........... %d\n", param->start_block);
buf += sprintf(buf, "end_block............. %d\n", param->end_block);
buf += sprintf(buf, "total_bytes_per_chunk. %d\n",
@@ -2476,7 +2391,7 @@ static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
buf += sprintf(buf, "n_gc_blocks........... %u\n", dev->n_gc_blocks);
buf += sprintf(buf, "bg_gcs................ %u\n", dev->bg_gcs);
buf +=
- sprintf(buf, "n_retired_writes...... %u\n", dev->n_retired_writes);
+ sprintf(buf, "n_retried_writes...... %u\n", dev->n_retried_writes);
buf +=
sprintf(buf, "n_retired_blocks...... %u\n", dev->n_retired_blocks);
buf += sprintf(buf, "n_ecc_fixed........... %u\n", dev->n_ecc_fixed);
@@ -2524,7 +2439,8 @@ static int yaffs_proc_read(char *page,
mutex_lock(&yaffs_context_lock);
- /* Locate and print the Nth entry. Order N-squared but N is small. */
+ /* Locate and print the Nth entry.
+ * Order N-squared but N is small. */
list_for_each(item, &yaffs_context_list) {
struct yaffs_linux_context *dc =
list_entry(item, struct yaffs_linux_context,
@@ -2542,7 +2458,7 @@ static int yaffs_proc_read(char *page,
buf = yaffs_dump_dev_part0(buf, dev);
} else {
buf = yaffs_dump_dev_part1(buf, dev);
- }
+ }
break;
}
@@ -2553,149 +2469,6 @@ static int yaffs_proc_read(char *page,
}
-/**
- * Set the verbosity of the warnings and error messages.
- *
- * Note that the names can only be a..z or _ with the current code.
- */
-
-static struct {
- char *mask_name;
- unsigned mask_bitfield;
-} mask_flags[] = {
- {"allocate", YAFFS_TRACE_ALLOCATE},
- {"always", YAFFS_TRACE_ALWAYS},
- {"background", YAFFS_TRACE_BACKGROUND},
- {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
- {"buffers", YAFFS_TRACE_BUFFERS},
- {"bug", YAFFS_TRACE_BUG},
- {"checkpt", YAFFS_TRACE_CHECKPOINT},
- {"deletion", YAFFS_TRACE_DELETION},
- {"erase", YAFFS_TRACE_ERASE},
- {"error", YAFFS_TRACE_ERROR},
- {"gc_detail", YAFFS_TRACE_GC_DETAIL},
- {"gc", YAFFS_TRACE_GC},
- {"lock", YAFFS_TRACE_LOCK},
- {"mtd", YAFFS_TRACE_MTD},
- {"nandaccess", YAFFS_TRACE_NANDACCESS},
- {"os", YAFFS_TRACE_OS},
- {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
- {"scan", YAFFS_TRACE_SCAN},
- {"mount", YAFFS_TRACE_MOUNT},
- {"tracing", YAFFS_TRACE_TRACING},
- {"sync", YAFFS_TRACE_SYNC},
- {"write", YAFFS_TRACE_WRITE},
- {"verify", YAFFS_TRACE_VERIFY},
- {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
- {"verify_full", YAFFS_TRACE_VERIFY_FULL},
- {"verify_all", YAFFS_TRACE_VERIFY_ALL},
- {"all", 0xffffffff},
- {"none", 0},
- {NULL, 0},
-};
-
-#define MAX_MASK_NAME_LENGTH 40
-static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
- unsigned long count, void *data)
-{
- unsigned rg = 0, mask_bitfield;
- char *end;
- char *mask_name;
- const char *x;
- char substring[MAX_MASK_NAME_LENGTH + 1];
- int i;
- int done = 0;
- int add, len = 0;
- int pos = 0;
-
- rg = yaffs_trace_mask;
-
- while (!done && (pos < count)) {
- done = 1;
- while ((pos < count) && isspace(buf[pos]))
- pos++;
-
- switch (buf[pos]) {
- case '+':
- case '-':
- case '=':
- add = buf[pos];
- pos++;
- break;
-
- default:
- add = ' ';
- break;
- }
- mask_name = NULL;
-
- mask_bitfield = simple_strtoul(buf + pos, &end, 0);
-
- if (end > buf + pos) {
- mask_name = "numeral";
- len = end - (buf + pos);
- pos += len;
- done = 0;
- } else {
- for (x = buf + pos, i = 0;
- (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
- i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
- substring[i] = *x;
- substring[i] = '\0';
-
- for (i = 0; mask_flags[i].mask_name != NULL; i++) {
- if (strcmp(substring, mask_flags[i].mask_name)
- == 0) {
- mask_name = mask_flags[i].mask_name;
- mask_bitfield =
- mask_flags[i].mask_bitfield;
- done = 0;
- break;
- }
- }
- }
-
- if (mask_name != NULL) {
- done = 0;
- switch (add) {
- case '-':
- rg &= ~mask_bitfield;
- break;
- case '+':
- rg |= mask_bitfield;
- break;
- case '=':
- rg = mask_bitfield;
- break;
- default:
- rg |= mask_bitfield;
- break;
- }
- }
- }
-
- yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
-
- printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
-
- if (rg & YAFFS_TRACE_ALWAYS) {
- for (i = 0; mask_flags[i].mask_name != NULL; i++) {
- char flag;
- flag = ((rg & mask_flags[i].mask_bitfield) ==
- mask_flags[i].mask_bitfield) ? '+' : '-';
- printk(KERN_DEBUG "%c%s\n", flag,
- mask_flags[i].mask_name);
- }
- }
-
- return count;
-}
-
-static int yaffs_proc_write(struct file *file, const char *buf,
- unsigned long count, void *data)
-{
- return yaffs_proc_write_trace_options(file, buf, count, data);
-}
/* Stuff to handle installation of file systems */
struct file_system_to_install {
@@ -2717,24 +2490,19 @@ static int __init init_yaffs_fs(void)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs built " __DATE__ " " __TIME__ " Installing.");
-#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
- yaffs_trace(YAFFS_TRACE_ALWAYS,
- "\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n");
-#endif
-
mutex_init(&yaffs_context_lock);
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
- S_IRUGO | S_IFREG, YPROC_ROOT);
+ S_IRUGO | S_IFREG, NULL);
if (my_proc_entry) {
- my_proc_entry->write_proc = yaffs_proc_write;
+ my_proc_entry->write_proc = NULL;
my_proc_entry->read_proc = yaffs_proc_read;
my_proc_entry->data = NULL;
} else {
return -ENOMEM;
- }
+ }
/* Now add the file system entries */
@@ -2772,7 +2540,7 @@ static void __exit exit_yaffs_fs(void)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs built " __DATE__ " " __TIME__ " removing.");
- remove_proc_entry("yaffs", YPROC_ROOT);
+ remove_proc_entry("yaffs", NULL);
fsinst = fs_to_install;
@@ -2786,8 +2554,8 @@ static void __exit exit_yaffs_fs(void)
}
module_init(init_yaffs_fs)
- module_exit(exit_yaffs_fs)
+module_exit(exit_yaffs_fs)
- MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
-MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
MODULE_LICENSE("GPL");