/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
+ * Copyright (C) 2002-2018 Aleph One Ltd.
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Acknowledgements:
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
obj);
if (link) {
- old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
+ set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
d_instantiate(dentry, old_dentry->d_inode);
atomic_inc(&old_dentry->d_inode->i_count);
yaffs_trace(YAFFS_TRACE_OS,
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
+ if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
+ YAFFS_MAX_NAME_LENGTH)
+ return -ENAMETOOLONG;
+
+ if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
+ YAFFS_MAX_ALIAS_LENGTH)
+ return -ENAMETOOLONG;
+
dev = yaffs_inode_to_obj(dir)->my_dev;
yaffs_gross_lock(dev);
obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
ret_val = yaffs_unlinker(obj, dentry->d_name.name);
if (ret_val == YAFFS_OK) {
- dentry->d_inode->i_nlink--;
+ inode_dec_link_count(dentry->d_inode);
dir->i_version++;
yaffs_gross_unlock(dev);
- mark_inode_dirty(dentry->d_inode);
update_dir_time(dir);
return 0;
}
return -ENOTEMPTY;
}
-static int yaffs_sync_object(struct file *file, int datasync)
+static int yaffs_sync_object(struct file *file,
+ loff_t start, loff_t end, int datasync)
{
struct yaffs_obj *obj;
yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, "yaffs_sync_object");
yaffs_gross_lock(dev);
- yaffs_flush_file(obj, 1, datasync);
+ yaffs_flush_file(obj, 1, datasync, 0);
yaffs_gross_unlock(dev);
return 0;
}
yaffs_gross_unlock(dev);
if (ret_val == YAFFS_OK) {
- if (target) {
- new_dentry->d_inode->i_nlink--;
- mark_inode_dirty(new_dentry->d_inode);
- }
+ if (target)
+ inode_dec_link_count(new_dentry->d_inode);
update_dir_time(old_dir);
if (old_dir != new_dir)
yaffs_gross_lock(dev);
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 0);
yaffs_gross_unlock(dev);
unsigned char *pg_buf;
int ret;
struct yaffs_dev *dev;
+ loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
yaffs_trace(YAFFS_TRACE_OS,
- "yaffs_readpage_nolock at %08x, size %08x",
- (unsigned)(pg->index << PAGE_CACHE_SHIFT),
+ "yaffs_readpage_nolock at %lld, size %08x",
+ (long long)pos,
(unsigned)PAGE_CACHE_SIZE);
+
obj = yaffs_dentry_to_obj(f->f_dentry);
dev = obj->my_dev;
yaffs_gross_lock(dev);
- ret = yaffs_file_rd(obj, pg_buf,
- pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
+ ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
yaffs_gross_unlock(dev);
(int)obj->variant.file_variant.file_size, (int)inode->i_size);
n_written = yaffs_wr_file(obj, buffer,
- page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
+ ((loff_t)page->index) << PAGE_CACHE_SHIFT,
+ n_bytes, 0);
yaffs_touch_super(dev);
{
struct inode *iptr;
struct yaffs_obj *obj;
+ struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ spin_lock(&sb->s_inode_list_lock);
list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
+ spin_lock(&inode->i_lock);
+ if (iptr->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
+ spin_unlock(&inode->i_lock);
+ continue;
+ }
+
+ __iget(iptr);
+ spin_unlock(&inode->i_lock);
+ spin_unlock(&sb->s_inode_list_lock);
+
obj = yaffs_inode_to_obj(iptr);
if (obj) {
yaffs_trace(YAFFS_TRACE_OS,
"flushing obj %d", obj->obj_id);
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 0);
}
+
+ yaffs_gross_unlock(dev);
+ iput(iptr);
+ yaffs_gross_lock(dev);
+
+ spin_lock(&sb->s_inode_list_lock);
}
+ spin_unlock(&sb->s_inode_list_lock);
}
static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
yaffs_flush_inodes(sb);
yaffs_update_dirty_dirs(dev);
- yaffs_flush_whole_cache(dev);
+ yaffs_flush_whole_cache(dev, 1);
if (do_checkpoint)
yaffs_checkpoint_save(dev);
}
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);
+ set_nlink(inode, 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,
static void yaffs_put_super(struct super_block *sb)
{
struct yaffs_dev *dev = yaffs_super_to_dev(sb);
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
yaffs_trace(YAFFS_TRACE_OS, "yaffs_put_super");
}
kfree(dev);
+
+ if (mtd && mtd->sync)
+ mtd->sync(mtd);
+
+ if (mtd)
+ put_mtd_device(mtd);
}
-static void yaffs_mtd_put_super(struct super_block *sb)
+/* the function only is used to change dev->read_only when this file system
+ * is remounted.
+ */
+static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
{
- struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb));
+ int read_only = 0;
+ struct mtd_info *mtd;
+ struct yaffs_dev *dev = 0;
- if (mtd->sync)
- mtd->sync(mtd);
+ /* Get the device */
+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ if (!mtd) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "MTD device #%u doesn't appear to exist",
+ MINOR(sb->s_dev));
+ return 1;
+ }
- put_mtd_device(mtd);
+ /* Check it's NAND */
+ if (mtd->type != MTD_NANDFLASH) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "MTD device is not NAND it's type %d",
+ mtd->type);
+ return 1;
+ }
+
+ read_only = ((*flags & MS_RDONLY) != 0);
+ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
+ read_only = 1;
+ printk(KERN_INFO
+ "yaffs: mtd is read only, setting superblock read only");
+ *flags |= MS_RDONLY;
+ }
+
+ dev = sb->s_fs_info;
+ dev->read_only = read_only;
+
+ return 0;
}
+
static const struct super_operations yaffs_super_ops = {
.statfs = yaffs_statfs,
.put_super = yaffs_put_super,
.evict_inode = yaffs_evict_inode,
.sync_fs = yaffs_sync_fs,
.write_super = yaffs_write_super,
+ .remount_fs = yaffs_remount_fs,
};
static struct super_block *yaffs_internal_read_super(int yaffs_version,
/* Get the device */
mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
- if (!mtd) {
+ if (IS_ERR(mtd)) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"MTD device #%u doesn't appear to exist",
MINOR(sb->s_dev));
kfree(context);
dev = NULL;
context = NULL;
- }
- if (!dev) {
/* Deep shit could not allocate device structure */
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs_read_super failed trying to allocate yaffs_dev");
yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;
param->sb_dirty_fn = yaffs_touch_super;
- param->gc_control = yaffs_gc_control_callback;
+ param->gc_control_fn = yaffs_gc_control_callback;
yaffs_dev_to_lc(dev)->super = sb;
if (!context->bg_thread)
param->defered_dir_update = 0;
+ sb->s_maxbytes = yaffs_max_file_size(dev);
+
/* Release lock before yaffs_get_inode() */
yaffs_gross_unlock(dev);
return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
}
-static int yaffs_read_super(struct file_system_type *fs,
+static struct dentry *yaffs_mount(struct file_system_type *fs,
int flags, const char *dev_name,
- void *data, struct vfsmount *mnt)
+ void *data)
{
-
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs_internal_read_super_mtd, mnt);
+ return mount_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd);
}
static struct file_system_type yaffs_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs",
- .get_sb = yaffs_read_super,
+ .mount = yaffs_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
}
-static int yaffs2_read_super(struct file_system_type *fs,
- int flags, const char *dev_name, void *data,
- struct vfsmount *mnt)
+static struct dentry *yaffs2_mount(struct file_system_type *fs,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_bdev(fs, flags, dev_name, data,
- yaffs2_internal_read_super_mtd, mnt);
+ return mount_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd);
}
static struct file_system_type yaffs2_fs_type = {
.owner = THIS_MODULE,
.name = "yaffs2",
- .get_sb = yaffs2_read_super,
+ .mount = yaffs2_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
{
- buf +=
- sprintf(buf, "data_bytes_per_chunk.. %d\n",
- dev->data_bytes_per_chunk);
+ buf += sprintf(buf, "max file size......... %lld\n",
+ (long long) yaffs_max_file_size(dev));
+ buf += sprintf(buf, "data_bytes_per_chunk.. %d\n",
+ dev->data_bytes_per_chunk);
buf += sprintf(buf, "chunk_grp_bits........ %d\n", dev->chunk_grp_bits);
buf += sprintf(buf, "chunk_grp_size........ %d\n", dev->chunk_grp_size);
buf +=