/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002-2007 Aleph One Ltd.
+ * Copyright (C) 2002-2009 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*/
const char *yaffs_fs_c_version =
- "$Id: yaffs_fs.c,v 1.76 2009-03-06 17:20:51 wookey Exp $";
+ "$Id: yaffs_fs.c,v 1.85 2009-10-15 00:45:46 charles Exp $";
extern const char *yaffs_guts_c_version;
#include <linux/version.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
#include <linux/statfs.h> /* Added NCB 15-8-2003 */
-#include <asm/statfs.h>
+#include <linux/statfs.h>
#define UnlockPage(p) unlock_page(p)
#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
#define YCALCBLOCKS(s, b) ((s)/(b))
#endif
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "yportenv.h"
#include "yaffs_guts.h"
#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
#endif
+
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while(0)
+
static void yaffs_put_super(struct super_block *sb);
static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
};
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
-static struct file_operations yaffs_file_operations = {
+static const struct file_operations yaffs_file_operations = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
-static struct file_operations yaffs_file_operations = {
+static const struct file_operations yaffs_file_operations = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
#else
-static struct file_operations yaffs_file_operations = {
+static const struct file_operations yaffs_file_operations = {
.read = generic_file_read,
.write = generic_file_write,
.mmap = generic_file_mmap,
};
#endif
-static struct inode_operations yaffs_file_inode_operations = {
+static const struct inode_operations yaffs_file_inode_operations = {
.setattr = yaffs_setattr,
};
-static struct inode_operations yaffs_symlink_inode_operations = {
+static const struct inode_operations yaffs_symlink_inode_operations = {
.readlink = yaffs_readlink,
.follow_link = yaffs_follow_link,
.setattr = yaffs_setattr,
};
-static struct inode_operations yaffs_dir_inode_operations = {
+static const struct inode_operations yaffs_dir_inode_operations = {
.create = yaffs_create,
.lookup = yaffs_lookup,
.link = yaffs_link,
.setattr = yaffs_setattr,
};
-static struct file_operations yaffs_dir_operations = {
+static const struct file_operations yaffs_dir_operations = {
.read = generic_read_dir,
.readdir = yaffs_readdir,
.fsync = yaffs_sync_object,
};
-static struct super_operations yaffs_super_ops = {
+static const struct super_operations yaffs_super_ops = {
.statfs = yaffs_statfs,
#ifndef YAFFS_USE_OWN_IGET
kfree(alias);
out:
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
- return ERR_PTR (ret);
+ return ERR_PTR(ret);
#else
return ret;
#endif
d_add(dentry, inode);
return NULL;
- /* return (ERR_PTR(-EIO)); */
-
}
yaffs_GrossUnlock(dev);
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
- truncate_inode_pages (&inode->i_data, 0);
+ truncate_inode_pages(&inode->i_data, 0);
#endif
clear_inode(inode);
}
yaffs_GrossLock(dev);
- yaffs_FlushFile(obj, 1);
+ yaffs_FlushFile(obj, 1,0);
yaffs_GrossUnlock(dev);
yaffs_GrossLock(dev);
- ret =
- yaffs_ReadDataFromFile(obj, pg_buf,
+ ret = yaffs_ReadDataFromFile(obj, pg_buf,
pg->index << PAGE_CACHE_SHIFT,
PAGE_CACHE_SIZE);
end_index = inode->i_size >> PAGE_CACHE_SHIFT;
/* easy case */
- if (page->index < end_index) {
+ if (page->index < end_index)
nBytes = PAGE_CACHE_SIZE;
- } else {
+ else
nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
- }
get_page(page);
T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
/* Get a page */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
pg = grab_cache_page_write_begin(mapping, index, flags);
#else
pg = __grab_cache_page(mapping, index);
out:
T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
- if (space_held) {
+ if (space_held)
yaffs_release_space(filp);
- }
if (pg) {
unlock_page(pg);
page_cache_release(pg);
inode = f->f_dentry->d_inode;
- if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
+ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
ipos = inode->i_size;
- } else {
+ else
ipos = *pos;
- }
- if (!obj) {
+ if (!obj)
T(YAFFS_TRACE_OS,
("yaffs_file_write: hey obj is null!\n"));
- } else {
+ else
T(YAFFS_TRACE_OS,
("yaffs_file_write about to write writing %zu bytes"
"to object %d at %d\n",
n, obj->objectId, ipos));
- }
nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
T(YAFFS_TRACE_OS,
("yaffs_file_write writing %zu bytes, %d written at %d\n",
n, nWritten, ipos));
+
if (nWritten > 0) {
ipos += nWritten;
*pos = ipos;
}
yaffs_GrossUnlock(dev);
- return nWritten == 0 ? -ENOSPC : nWritten;
+ return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
}
/* Space holding and freeing is done to ensure we have space available for write_begin/end */
T(YAFFS_TRACE_OS,
("yaffs_readdir: entry . ino %d \n",
(int)inode->i_ino));
- if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
+ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
goto out;
- }
offset++;
f->f_pos++;
}
("yaffs_readdir: entry .. ino %d \n",
(int)f->f_dentry->d_parent->d_inode->i_ino));
if (filldir(dirent, "..", 2, offset,
- f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
goto out;
- }
offset++;
f->f_pos++;
}
strlen(name),
offset,
yaffs_GetObjectInode(l),
- yaffs_GetObjectType(l)) < 0) {
+ yaffs_GetObjectType(l)) < 0)
goto up_and_out;
- }
offset++;
f->f_pos++;
if (obj) {
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS,
("yaffs_mknod created object %d count = %d\n",
obj->objectId, atomic_read(&inode->i_count)));
int retVal;
T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
-#if 0
- /* attempt to fix dir bug - didn't work */
- if (!retVal) {
- dget(dentry);
- }
-#endif
return retVal;
}
dir->i_version++;
yaffs_GrossUnlock(dev);
mark_inode_dirty(dentry->d_inode);
+ update_dir_time(dir);
return 0;
}
yaffs_GrossUnlock(dev);
yaffs_GrossLock(dev);
- if (!S_ISDIR(inode->i_mode)) { /* Don't link directories */
+ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
obj);
- }
if (link) {
old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
yaffs_GrossUnlock(dev);
- if (link) {
+ if (link){
+ update_dir_time(dir);
return 0;
}
inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
d_instantiate(dentry, inode);
+ update_dir_time(dir);
T(YAFFS_TRACE_OS, ("symlink created OK\n"));
return 0;
} else {
T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
yaffs_GrossLock(dev);
- yaffs_FlushFile(obj, 1);
+ yaffs_FlushFile(obj, 1, datasync);
yaffs_GrossUnlock(dev);
return 0;
}
new_dentry->d_inode->i_nlink--;
mark_inode_dirty(new_dentry->d_inode);
}
-
+
+ update_dir_time(old_dir);
+ if(old_dir != new_dir)
+ update_dir_time(new_dir);
return 0;
} else {
return -ENOTEMPTY;
}
+
+static void yaffs_flush_sb_inodes(struct super_block *sb)
+{
+ struct inode *iptr;
+ yaffs_Object *obj;
+
+ list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
+ obj = yaffs_InodeToObject(iptr);
+ if(obj){
+ T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId));
+ yaffs_FlushFile(obj,1,0);
+ }
+ }
+}
+
static int yaffs_do_sync_fs(struct super_block *sb)
{
if (dev) {
yaffs_FlushEntireDeviceCache(dev);
+ yaffs_flush_sb_inodes(sb);
yaffs_CheckpointSave(dev);
}
int skip_checkpoint_read;
int skip_checkpoint_write;
int no_cache;
+ int tags_ecc_on;
+ int tags_ecc_overridden;
+ int lazy_load_enabled;
+ int lazy_load_overridden;
} yaffs_options;
#define MAX_OPT_LEN 20
memset(cur_opt, 0, MAX_OPT_LEN + 1);
p = 0;
+ while(*options_str == ',')
+ options_str++;
+
while (*options_str && *options_str != ',') {
if (p < MAX_OPT_LEN) {
cur_opt[p] = *options_str;
if (!strcmp(cur_opt, "inband-tags"))
options->inband_tags = 1;
- else if (!strcmp(cur_opt, "no-cache"))
+ else if (!strcmp(cur_opt, "tags-ecc-off")){
+ options->tags_ecc_on = 0;
+ options->tags_ecc_overridden=1;
+ } else if (!strcmp(cur_opt, "tags-ecc-on")){
+ options->tags_ecc_on = 1;
+ options->tags_ecc_overridden = 1;
+ } else if (!strcmp(cur_opt, "lazy-load-off")){
+ options->lazy_load_enabled = 0;
+ options->lazy_load_overridden=1;
+ } else if (!strcmp(cur_opt, "lazy-load-on")){
+ options->lazy_load_enabled = 1;
+ options->lazy_load_overridden = 1;
+ } else if (!strcmp(cur_opt, "no-cache"))
options->no_cache = 1;
else if (!strcmp(cur_opt, "no-checkpoint-read"))
options->skip_checkpoint_read = 1;
yaffs_devname(sb, devname_buf)));
/* Check it's an mtd device..... */
- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
+ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
return NULL; /* This isn't an mtd device */
- }
+
/* Get the device */
mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
if (!mtd) {
#ifdef CONFIG_YAFFS_AUTO_YAFFS2
- if (yaffsVersion == 1 &&
- WRITE_SIZE(mtd) >= 2048) {
- T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
- yaffsVersion = 2;
+ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
+ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
+ yaffsVersion = 2;
}
/* Added NCB 26/5/2006 for completeness */
- if (yaffsVersion == 2 &&
- !options.inband_tags &&
- WRITE_SIZE(mtd) == 512) {
- T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
- yaffsVersion = 1;
+ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
+ T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
+ yaffsVersion = 1;
}
#endif
dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
dev->inbandTags = options.inband_tags;
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+ dev->disableLazyLoad = 1;
+#endif
+ if(options.lazy_load_overridden)
+ dev->disableLazyLoad = !options.lazy_load_enabled;
+
+#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
+ dev->noTagsECC = 1;
+#endif
+ if(options.tags_ecc_overridden)
+ dev->noTagsECC = !options.tags_ecc_on;
+
/* ... and the functions. */
if (yaffsVersion == 2) {
dev->writeChunkWithTagsToNAND =
buf +=
sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
+ buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC);
buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
while (!done && (pos < count)) {
done = 1;
- while ((pos < count) && isspace(buf[pos])) {
+ while ((pos < count) && isspace(buf[pos]))
pos++;
- }
switch (buf[pos]) {
case '+':
mask_name = NULL;
mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+
if (end > buf + pos) {
mask_name = "numeral";
len = end - (buf + pos);
my_proc_entry->write_proc = yaffs_proc_write;
my_proc_entry->read_proc = yaffs_proc_read;
my_proc_entry->data = NULL;
- } else {
+ } else
return -ENOMEM;
- }
/* Now add the file system entries */
while (fsinst->fst && !error) {
error = register_filesystem(fsinst->fst);
- if (!error) {
+ if (!error)
fsinst->installed = 1;
- }
fsinst++;
}