Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1085db4a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs update from Jaegeuk Kim:
 "[Major bug fixes]
   o Store device file information correctly
   o Fix -EIO handling with respect to power-off-recovery
   o Allocate blocks with global locks
   o Fix wrong calculation of the SSR cost

  [Cleanups]
   o Get rid of fake on-stack dentries

  [Enhancement]
   o Support (un)freeze_fs
   o Enhance the f2fs_gc flow
   o Support 32-bit binary execution on 64-bit kernel"

* tag 'f2fs-for-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (29 commits)
  f2fs: avoid build warning
  f2fs: add compat_ioctl to provide backward compatability
  f2fs: fix calculation of max. gc cost in the SSR case
  f2fs: clarify and enhance the f2fs_gc flow
  f2fs: optimize the return condition for has_not_enough_free_secs
  f2fs: make an accessor to get sections for particular block type
  f2fs: mark gc_thread as NULL when thread creation is failed
  f2fs: name gc task as per the block device
  f2fs: remove unnecessary gc option check and balance_fs
  f2fs: remove repeated F2FS_SET_SB_DIRT call
  f2fs: when check superblock failed, try to check another superblock
  f2fs: use F2FS_BLKSIZE to judge bloksize and page_cache_size
  f2fs: add device name in debugfs
  f2fs: stop repeated checking if cp is needed
  f2fs: avoid balanc_fs during evict_inode
  f2fs: remove the use of page_cache_release
  f2fs: fix typo mistake for data_version description
  f2fs: reorganize code for ra_node_page
  f2fs: avoid redundant call to has_not_enough_free_secs in f2fs_gc
  f2fs: add un/freeze_fs into super_operations
  ...
parents 3c834b6f 7dd690c8
Loading
Loading
Loading
Loading
+27 −36
Original line number Diff line number Diff line
@@ -72,22 +72,22 @@ static int f2fs_write_meta_page(struct page *page,
{
	struct inode *inode = page->mapping->host;
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
	int err;

	wait_on_page_writeback(page);

	err = write_meta_page(sbi, page, wbc);
	if (err) {
	/* Should not write any meta pages, if any IO error was occurred */
	if (wbc->for_reclaim ||
			is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
		dec_page_count(sbi, F2FS_DIRTY_META);
		wbc->pages_skipped++;
		set_page_dirty(page);
		return AOP_WRITEPAGE_ACTIVATE;
	}

	dec_page_count(sbi, F2FS_DIRTY_META);
	wait_on_page_writeback(page);

	/* In this case, we should not unlock this page */
	if (err != AOP_WRITEPAGE_ACTIVATE)
	write_meta_page(sbi, page);
	dec_page_count(sbi, F2FS_DIRTY_META);
	unlock_page(page);
	return err;
	return 0;
}

static int f2fs_write_meta_pages(struct address_space *mapping,
@@ -138,7 +138,10 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
			BUG_ON(page->mapping != mapping);
			BUG_ON(!PageDirty(page));
			clear_page_dirty_for_io(page);
			f2fs_write_meta_page(page, &wbc);
			if (f2fs_write_meta_page(page, &wbc)) {
				unlock_page(page);
				break;
			}
			if (nwritten++ >= nr_to_write)
				break;
		}
@@ -161,7 +164,6 @@ static int f2fs_set_meta_page_dirty(struct page *page)
	if (!PageDirty(page)) {
		__set_page_dirty_nobuffers(page);
		inc_page_count(sbi, F2FS_DIRTY_META);
		F2FS_SET_SB_DIRT(sbi);
		return 1;
	}
	return 0;
@@ -216,19 +218,11 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
	new->ino = ino;

	/* add new_oentry into list which is sorted by inode number */
	if (orphan) {
		struct orphan_inode_entry *prev;

		/* get previous entry */
		prev = list_entry(orphan->list.prev, typeof(*prev), list);
		if (&prev->list != head)
			/* insert new orphan inode entry */
			list_add(&new->list, &prev->list);
	if (orphan)
		list_add(&new->list, this->prev);
	else
			list_add(&new->list, head);
	} else {
		list_add_tail(&new->list, head);
	}

	sbi->n_orphans++;
out:
	mutex_unlock(&sbi->orphan_inode_mutex);
@@ -545,7 +539,7 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
/*
 * Freeze all the FS-operations for checkpoint.
 */
void block_operations(struct f2fs_sb_info *sbi)
static void block_operations(struct f2fs_sb_info *sbi)
{
	int t;
	struct writeback_control wbc = {
@@ -717,27 +711,24 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
	sbi->alloc_valid_block_count = 0;

	/* Here, we only have one bio having CP pack */
	if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG))
		sbi->sb->s_flags |= MS_RDONLY;
	else
	sync_meta_pages(sbi, META_FLUSH, LONG_MAX);

	if (!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
		clear_prefree_segments(sbi);
		F2FS_RESET_SB_DIRT(sbi);
	}
}

/*
 * We guarantee that this checkpoint procedure should not fail.
 */
void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount)
void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
{
	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
	unsigned long long ckpt_ver;

	if (!blocked) {
	mutex_lock(&sbi->cp_mutex);
	block_operations(sbi);
	}

	f2fs_submit_bio(sbi, DATA, true);
	f2fs_submit_bio(sbi, NODE, true);
+3 −1
Original line number Diff line number Diff line
@@ -183,10 +183,12 @@ static int stat_show(struct seq_file *s, void *v)

	mutex_lock(&f2fs_stat_mutex);
	list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
		char devname[BDEVNAME_SIZE];

		update_general_status(si->sbi);

		seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++);
		seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n",
			bdevname(si->sbi->sb->s_bdev, devname), i++);
		seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
			   si->sit_area_segs, si->nat_area_segs);
		seq_printf(s, "[SSA: %d] [MAIN: %d",
+13 −16
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
	mutex_unlock_op(sbi, DENTRY_OPS);
}

void init_dent_inode(struct dentry *dentry, struct page *ipage)
void init_dent_inode(const struct qstr *name, struct page *ipage)
{
	struct f2fs_node *rn;

@@ -274,20 +274,19 @@ void init_dent_inode(struct dentry *dentry, struct page *ipage)

	wait_on_page_writeback(ipage);

	/* copy dentry info. to this inode page */
	/* copy name info. to this inode page */
	rn = (struct f2fs_node *)page_address(ipage);
	rn->i.i_namelen = cpu_to_le32(dentry->d_name.len);
	memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len);
	rn->i.i_namelen = cpu_to_le32(name->len);
	memcpy(rn->i.i_name, name->name, name->len);
	set_page_dirty(ipage);
}

static int init_inode_metadata(struct inode *inode, struct dentry *dentry)
static int init_inode_metadata(struct inode *inode,
		struct inode *dir, const struct qstr *name)
{
	struct inode *dir = dentry->d_parent->d_inode;

	if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
		int err;
		err = new_inode_page(inode, dentry);
		err = new_inode_page(inode, name);
		if (err)
			return err;

@@ -310,7 +309,7 @@ static int init_inode_metadata(struct inode *inode, struct dentry *dentry)
		if (IS_ERR(ipage))
			return PTR_ERR(ipage);
		set_cold_node(inode, ipage);
		init_dent_inode(dentry, ipage);
		init_dent_inode(name, ipage);
		f2fs_put_page(ipage, 1);
	}
	if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
@@ -371,7 +370,7 @@ static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots)
	goto next;
}

int f2fs_add_link(struct dentry *dentry, struct inode *inode)
int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode)
{
	unsigned int bit_pos;
	unsigned int level;
@@ -380,17 +379,15 @@ int f2fs_add_link(struct dentry *dentry, struct inode *inode)
	f2fs_hash_t dentry_hash;
	struct f2fs_dir_entry *de;
	unsigned int nbucket, nblock;
	struct inode *dir = dentry->d_parent->d_inode;
	struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
	const char *name = dentry->d_name.name;
	size_t namelen = dentry->d_name.len;
	size_t namelen = name->len;
	struct page *dentry_page = NULL;
	struct f2fs_dentry_block *dentry_blk = NULL;
	int slots = GET_DENTRY_SLOTS(namelen);
	int err = 0;
	int i;

	dentry_hash = f2fs_dentry_hash(name, dentry->d_name.len);
	dentry_hash = f2fs_dentry_hash(name->name, name->len);
	level = 0;
	current_depth = F2FS_I(dir)->i_current_depth;
	if (F2FS_I(dir)->chash == dentry_hash) {
@@ -433,7 +430,7 @@ int f2fs_add_link(struct dentry *dentry, struct inode *inode)
	++level;
	goto start;
add_dentry:
	err = init_inode_metadata(inode, dentry);
	err = init_inode_metadata(inode, dir, name);
	if (err)
		goto fail;

@@ -442,7 +439,7 @@ int f2fs_add_link(struct dentry *dentry, struct inode *inode)
	de = &dentry_blk->dentry[bit_pos];
	de->hash_code = dentry_hash;
	de->name_len = cpu_to_le16(namelen);
	memcpy(dentry_blk->filename[bit_pos], name, namelen);
	memcpy(dentry_blk->filename[bit_pos], name->name, name->len);
	de->ino = cpu_to_le32(inode->i_ino);
	set_de_type(de, inode);
	for (i = 0; i < slots; i++)
+35 −9
Original line number Diff line number Diff line
@@ -103,6 +103,20 @@ static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
	return before;
}

/*
 * ioctl commands
 */
#define F2FS_IOC_GETFLAGS               FS_IOC_GETFLAGS
#define F2FS_IOC_SETFLAGS               FS_IOC_SETFLAGS

#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
 * ioctl commands in 32 bit emulation
 */
#define F2FS_IOC32_GETFLAGS             FS_IOC32_GETFLAGS
#define F2FS_IOC32_SETFLAGS             FS_IOC32_SETFLAGS
#endif

/*
 * For INODE and NODE manager
 */
@@ -141,7 +155,7 @@ struct f2fs_inode_info {

	/* Use below internally in f2fs*/
	unsigned long flags;		/* use to pass per-file flags */
	unsigned long long data_version;/* lastes version of data for fsync */
	unsigned long long data_version;/* latest version of data for fsync */
	atomic_t dirty_dents;		/* # of dirty dentry pages */
	f2fs_hash_t chash;		/* hash value of given file name */
	unsigned int clevel;		/* maximum level of given file name */
@@ -573,6 +587,14 @@ static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
	return atomic_read(&sbi->nr_pages[count_type]);
}

static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type)
{
	unsigned int pages_per_sec = sbi->segs_per_sec *
					(1 << sbi->log_blocks_per_seg);
	return ((get_pages(sbi, block_type) + pages_per_sec - 1)
			>> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
}

static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi)
{
	block_t ret;
@@ -842,12 +864,12 @@ void f2fs_truncate(struct inode *);
int f2fs_setattr(struct dentry *, struct iattr *);
int truncate_hole(struct inode *, pgoff_t, pgoff_t);
long f2fs_ioctl(struct file *, unsigned int, unsigned long);
long f2fs_compat_ioctl(struct file *, unsigned int, unsigned long);

/*
 * inode.c
 */
void f2fs_set_inode_flags(struct inode *);
struct inode *f2fs_iget_nowait(struct super_block *, unsigned long);
struct inode *f2fs_iget(struct super_block *, unsigned long);
void update_inode(struct inode *, struct page *);
int f2fs_write_inode(struct inode *, struct writeback_control *);
@@ -867,12 +889,18 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
				struct page *, struct inode *);
void init_dent_inode(struct dentry *, struct page *);
int f2fs_add_link(struct dentry *, struct inode *);
void init_dent_inode(const struct qstr *, struct page *);
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
int f2fs_make_empty(struct inode *, struct inode *);
bool f2fs_empty_dir(struct inode *);

static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
{
	return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name,
				inode);
}

/*
 * super.c
 */
@@ -896,7 +924,7 @@ void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
int truncate_inode_blocks(struct inode *, pgoff_t);
int remove_inode_page(struct inode *);
int new_inode_page(struct inode *, struct dentry *);
int new_inode_page(struct inode *, const struct qstr *);
struct page *new_node_page(struct dnode_of_data *, unsigned int);
void ra_node_page(struct f2fs_sb_info *, nid_t);
struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
@@ -929,8 +957,7 @@ void allocate_new_segments(struct f2fs_sb_info *);
struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
struct bio *f2fs_bio_alloc(struct block_device *, int);
void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync);
int write_meta_page(struct f2fs_sb_info *, struct page *,
					struct writeback_control *);
void write_meta_page(struct f2fs_sb_info *, struct page *);
void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
					block_t, block_t *);
void write_data_page(struct inode *, struct page *, struct dnode_of_data*,
@@ -963,8 +990,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *);
void set_dirty_dir_page(struct inode *, struct page *);
void remove_dirty_dir_inode(struct inode *);
void sync_dirty_dir_inodes(struct f2fs_sb_info *);
void block_operations(struct f2fs_sb_info *);
void write_checkpoint(struct f2fs_sb_info *, bool, bool);
void write_checkpoint(struct f2fs_sb_info *, bool);
void init_orphan_info(struct f2fs_sb_info *);
int __init create_checkpoint_caches(void);
void destroy_checkpoint_caches(void);
+30 −5
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/writeback.h>
#include <linux/falloc.h>
#include <linux/types.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
#include <linux/mount.h>

@@ -157,11 +158,11 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)

	if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
		need_cp = true;
	if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP))
	else if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP))
		need_cp = true;
	if (!space_for_roll_forward(sbi))
	else if (!space_for_roll_forward(sbi))
		need_cp = true;
	if (need_to_sync_dir(sbi, inode))
	else if (need_to_sync_dir(sbi, inode))
		need_cp = true;

	if (need_cp) {
@@ -298,8 +299,6 @@ void f2fs_truncate(struct inode *inode)
		inode->i_mtime = inode->i_ctime = CURRENT_TIME;
		mark_inode_dirty(inode);
	}

	f2fs_balance_fs(F2FS_SB(inode->i_sb));
}

static int f2fs_getattr(struct vfsmount *mnt,
@@ -356,6 +355,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
			attr->ia_size != i_size_read(inode)) {
		truncate_setsize(inode, attr->ia_size);
		f2fs_truncate(inode);
		f2fs_balance_fs(F2FS_SB(inode->i_sb));
	}

	__setattr_copy(inode, attr);
@@ -387,12 +387,17 @@ const struct inode_operations f2fs_file_inode_operations = {
static void fill_zero(struct inode *inode, pgoff_t index,
					loff_t start, loff_t len)
{
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
	struct page *page;

	if (!len)
		return;

	f2fs_balance_fs(sbi);

	mutex_lock_op(sbi, DATA_NEW);
	page = get_new_data_page(inode, index, false);
	mutex_unlock_op(sbi, DATA_NEW);

	if (!IS_ERR(page)) {
		wait_on_page_writeback(page);
@@ -630,6 +635,23 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	}
}

#ifdef CONFIG_COMPAT
long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
	case F2FS_IOC32_GETFLAGS:
		cmd = F2FS_IOC_GETFLAGS;
		break;
	case F2FS_IOC32_SETFLAGS:
		cmd = F2FS_IOC_SETFLAGS;
		break;
	default:
		return -ENOIOCTLCMD;
	}
	return f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif

const struct file_operations f2fs_file_operations = {
	.llseek		= generic_file_llseek,
	.read		= do_sync_read,
@@ -641,6 +663,9 @@ const struct file_operations f2fs_file_operations = {
	.fsync		= f2fs_sync_file,
	.fallocate	= f2fs_fallocate,
	.unlocked_ioctl	= f2fs_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl	= f2fs_compat_ioctl,
#endif
	.splice_read	= generic_file_splice_read,
	.splice_write	= generic_file_splice_write,
};
Loading