/*
* 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:
* for any version of Linux.
*/
#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
+#include <linux/iversion.h>
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
#define YAFFS_COMPILE_BACKGROUND
#define YAFFS_HAS_EVICT_INODE
#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0))
#define YAFFS_NEW_FOLLOW_LINK 1
#else
#define YAFFS_NEW_FOLLOW_LINK 0
#include <linux/statfs.h>
#define UnlockPage(p) unlock_page(p)
-#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
/* FIXME: use sb->s_id instead ? */
-#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
#else
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
#define YPROC_ROOT (&proc_root)
#else
-#define YPROC_ROOT NULL
+#define YPROC_ROOT NULL
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
#define Y_INIT_TIMER(a) init_timer(a)
-#else
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
#define Y_INIT_TIMER(a) init_timer_on_stack(a)
+#else
+#define Y_INIT_TIMER(a,cb) timer_setup_on_stack(a,cb,0)
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
-
#include "yaffs_linux.h"
-
#include "yaffs_mtdif.h"
#include "yaffs_packedtags2.h"
#include "yaffs_getblockinfo.h"
-unsigned int yaffs_trace_mask =
- YAFFS_TRACE_BAD_BLOCKS |
- YAFFS_TRACE_ALWAYS |
- 0;
-
+unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS | 0;
unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
unsigned int yaffs_auto_checkpoint = 1;
unsigned int yaffs_gc_control = 1;
#define YAFFS_USE_DIR_ITERATE
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
+#define YAFFS_USE_XATTR
+#endif
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
#define YAFFS_NEW_PROCFS
#include <linux/seq_file.h>
#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+#define PAGE_CACHE_SIZE PAGE_SIZE
+#define PAGE_CACHE_SHIFT PAGE_SHIFT
+#define Y_GET_DENTRY(f) ((f)->f_path.dentry)
+#define YAFFS_NEW_XATTR 1
+#define YAFFS_NEW_GET_LINK 1
+#else
+#define Y_GET_DENTRY(f) ((f)->f_dentry)
+#define YAFFS_NEW_XATTR 0
+#define YAFFS_NEW_GET_LINK 0
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
+#define page_cache_release put_page
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+ } while (0)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
+#define update_dir_time(dir) do {\
+ (dir)->i_ctime = (dir)->i_mtime = current_kernel_time(); \
+ } while (0)
+#else
#define update_dir_time(dir) do {\
- (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
- } while (0)
+ (dir)->i_ctime = (dir)->i_mtime = current_kernel_time64(); \
+ } while (0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0))
+static inline int setattr_prepare(struct dentry *dentry, struct iattr *attr)
+{
+ return inode_change_ok(dentry->d_inode, attr);
+}
+#endif
static void yaffs_fill_inode_from_obj(struct inode *inode,
struct yaffs_obj *obj);
struct yaffs_obj *obj;
unsigned char *pg_buf;
int ret;
- loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
+ loff_t pos = ((loff_t) pg->index) << PAGE_SHIFT;
struct yaffs_dev *dev;
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_readpage_nolock at %lld, size %08x",
(long long)pos,
- (unsigned)PAGE_CACHE_SIZE);
+ (unsigned)PAGE_SIZE);
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
dev = obj->my_dev;
int n_free_chunks;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
dev = obj->my_dev;
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
dev = obj->my_dev;
struct inode *inode;
struct yaffs_dev *dev;
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
if (!obj) {
yaffs_trace(YAFFS_TRACE_OS,
yaffs_gross_lock(dev);
- inode = f->f_dentry->d_inode;
+ inode = Y_GET_DENTRY(f)->d_inode;
if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
ipos = inode->i_size;
static int yaffs_file_flush(struct file *file)
#endif
{
- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
+ struct yaffs_obj *obj = yaffs_dentry_to_obj(Y_GET_DENTRY(file));
struct yaffs_dev *dev = obj->my_dev;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
static const struct file_operations yaffs_file_operations = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
.read = new_sync_read,
.write = new_sync_write,
+#endif
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
#else
#endif
if (error == 0)
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error == 0) {
int result;
if (!error) {
return error;
}
+#ifdef YAFFS_USE_XATTR
+#if (YAFFS_NEW_XATTR > 0)
+static int yaffs_setxattr(struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value, size_t size, int flags)
+{
+#else
static int yaffs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
+#endif
int error = 0;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
return error;
}
+#if (YAFFS_NEW_XATTR > 0)
+static ssize_t yaffs_getxattr(struct dentry * dentry, struct inode *inode,
+ const char *name, void *buff, size_t size)
+{
+#else
static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
void *buff, size_t size)
{
struct inode *inode = dentry->d_inode;
+#endif
int error = 0;
struct yaffs_dev *dev;
struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
return error;
}
+#endif
static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
{
static const struct inode_operations yaffs_file_inode_operations = {
.setattr = yaffs_setattr,
+#ifdef YAFFS_USE_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
+#endif
+ .listxattr = yaffs_listxattr,
};
return ret;
}
+#if (YAFFS_NEW_GET_LINK == 0)
#if (YAFFS_NEW_FOLLOW_LINK == 1)
static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
return ret;
#endif
}
+#else
+static const char *yaffs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done)
+{
+ unsigned char *alias;
+ struct yaffs_dev *dev;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+ dev = yaffs_dentry_to_obj(dentry)->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
+ yaffs_gross_unlock(dev);
+
+ if (!alias)
+ return ERR_PTR(-ENOMEM);
+ set_delayed_call(done, kfree_link, alias);
+ return alias;
+}
+#endif
#ifdef YAFFS_HAS_PUT_INODE
static const struct inode_operations yaffs_symlink_inode_operations = {
.readlink = yaffs_readlink,
+#if (YAFFS_NEW_GET_LINK == 1)
+ .get_link = yaffs_get_link,
+#else
.follow_link = yaffs_follow_link,
+#endif
#if (YAFFS_NEW_FOLLOW_LINK == 1)
.put_link = yaffs_put_link,
#endif
.setattr = yaffs_setattr,
+#ifdef YAFFS_USE_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
+#endif
+ .listxattr = yaffs_listxattr,
};
#ifdef YAFFS_USE_OWN_IGET
*
* NB: POSIX says you can rename an object over an old object of the same name
*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry, unsigned int unused)
+#else
static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
+#endif
{
struct yaffs_dev *dev;
int ret_val = YAFFS_FAIL;
if (ret_val == YAFFS_OK) {
inode_dec_link_count(dentry->d_inode);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0))
+ inode_inc_iversion(dir);
+#else
dir->i_version++;
+#endif
yaffs_gross_unlock(dev);
update_dir_time(dir);
return 0;
.mknod = yaffs_mknod,
.rename = yaffs_rename,
.setattr = yaffs_setattr,
+ .listxattr = yaffs_listxattr,
+#ifdef YAFFS_USE_XATTR
.setxattr = yaffs_setxattr,
.getxattr = yaffs_getxattr,
- .listxattr = yaffs_listxattr,
.removexattr = yaffs_removexattr,
+#endif
};
/*-----------------------------------------------------------------*/
char name[YAFFS_MAX_NAME_LENGTH + 1];
- obj = yaffs_dentry_to_obj(f->f_dentry);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
dev = obj->my_dev;
yaffs_gross_lock(dev);
}
if (!dir_emit_dots(f, dc))
- return 0;
+ goto out;
curoffs = 1;
struct yaffs_obj *obj;
struct yaffs_dev *dev;
struct yaffs_search_context *sc;
- struct inode *inode = f->f_dentry->d_inode;
+ struct inode *inode = Y_GET_DENTRY(f)->d_inode;
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);
+ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));
dev = obj->my_dev;
yaffs_gross_lock(dev);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
inode->i_rdev = old_decode_dev(obj->yst_rdev);
- inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+ inode->i_atime.tv_sec = (YTIME_T) (obj->yst_atime);
inode->i_atime.tv_nsec = 0;
- inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+ inode->i_mtime.tv_sec = (YTIME_T) obj->yst_mtime;
inode->i_mtime.tv_nsec = 0;
- inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+ inode->i_ctime.tv_sec = (YTIME_T) obj->yst_ctime;
inode->i_ctime.tv_nsec = 0;
#else
inode->i_rdev = obj->yst_rdev;
#ifdef YAFFS_COMPILE_BACKGROUND
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+struct timer_struct {
+ struct task_struct *task;
+ struct timer_list timer;
+};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+static void yaffs_background_waker(struct timer_list *t)
+{
+ struct timer_struct *ts = from_timer(ts, t, timer);
+
+ wake_up_process(ts->task);
+}
+#else
void yaffs_background_waker(unsigned long data)
{
wake_up_process((struct task_struct *)data);
}
+#endif
static int yaffs_bg_thread_fn(void *data)
{
unsigned int urgency;
int gc_result;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+ struct timer_struct timer;
+#else
struct timer_list timer;
+#endif
yaffs_trace(YAFFS_TRACE_BACKGROUND,
"yaffs_background starting for dev %p", (void *)dev);
}
}
yaffs_gross_unlock(dev);
-#if 1
expires = next_dir_update;
if (time_before(next_gc, expires))
expires = next_gc;
if (time_before(expires, now))
expires = now + HZ;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+ Y_INIT_TIMER(&timer.timer, yaffs_background_waker);
+ timer.timer.expires = expires + 1;
+ timer.task = current;
+#else
Y_INIT_TIMER(&timer);
timer.expires = expires + 1;
timer.data = (unsigned long)current;
timer.function = yaffs_background_waker;
+#endif
set_current_state(TASK_INTERRUPTIBLE);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
+ add_timer(&timer.timer);
+ schedule();
+ del_timer_sync(&timer.timer);
+#else
add_timer(&timer);
schedule();
del_timer_sync(&timer);
-#else
- msleep(10);
#endif
}
static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
{
int read_only = 0;
+ int was_read_only = 0;
struct mtd_info *mtd;
struct yaffs_dev *dev = 0;
}
dev = sb->s_fs_info;
+ was_read_only = dev->read_only;
dev->read_only = read_only;
+ if (was_read_only && !read_only) {
+ yaffs_gross_lock(dev);
+ yaffs_guts_cleanup(dev);
+ yaffs_gross_unlock(dev);
+ yaffs_bg_start(dev);
+ } else if (!was_read_only && read_only) {
+ yaffs_bg_stop(dev);
+ }
+
return 0;
}
.open = yaffs_proc_open,
.read = seq_read,
.write = yaffs_proc_write,
+ .release = single_release,
};
static int yaffs_procfs_init(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_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
MODULE_LICENSE("GPL");