Merge branch 'lazytime' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull lazytime mount option support from Al Viro: "Lazytime stuff from tytso" * 'lazytime' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: ext4: add optimization for the lazytime mount option vfs: add find_inode_nowait() function vfs: add support for a lazytime mount option
This commit is contained in:
106
fs/inode.c
106
fs/inode.c
@@ -18,6 +18,7 @@
|
||||
#include <linux/buffer_head.h> /* for inode_has_buffers */
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/list_lru.h>
|
||||
#include <trace/events/writeback.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
@@ -30,7 +31,7 @@
|
||||
* inode_sb_list_lock protects:
|
||||
* sb->s_inodes, inode->i_sb_list
|
||||
* bdi->wb.list_lock protects:
|
||||
* bdi->wb.b_{dirty,io,more_io}, inode->i_wb_list
|
||||
* bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_wb_list
|
||||
* inode_hash_lock protects:
|
||||
* inode_hashtable, inode->i_hash
|
||||
*
|
||||
@@ -403,7 +404,8 @@ static void inode_lru_list_add(struct inode *inode)
|
||||
*/
|
||||
void inode_add_lru(struct inode *inode)
|
||||
{
|
||||
if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) &&
|
||||
if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC |
|
||||
I_FREEING | I_WILL_FREE)) &&
|
||||
!atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE)
|
||||
inode_lru_list_add(inode);
|
||||
}
|
||||
@@ -634,7 +636,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
|
||||
spin_unlock(&inode->i_lock);
|
||||
continue;
|
||||
}
|
||||
if (inode->i_state & I_DIRTY && !kill_dirty) {
|
||||
if (inode->i_state & I_DIRTY_ALL && !kill_dirty) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
busy = 1;
|
||||
continue;
|
||||
@@ -1268,6 +1270,56 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino)
|
||||
}
|
||||
EXPORT_SYMBOL(ilookup);
|
||||
|
||||
/**
|
||||
* find_inode_nowait - find an inode in the inode cache
|
||||
* @sb: super block of file system to search
|
||||
* @hashval: hash value (usually inode number) to search for
|
||||
* @match: callback used for comparisons between inodes
|
||||
* @data: opaque data pointer to pass to @match
|
||||
*
|
||||
* Search for the inode specified by @hashval and @data in the inode
|
||||
* cache, where the helper function @match will return 0 if the inode
|
||||
* does not match, 1 if the inode does match, and -1 if the search
|
||||
* should be stopped. The @match function must be responsible for
|
||||
* taking the i_lock spin_lock and checking i_state for an inode being
|
||||
* freed or being initialized, and incrementing the reference count
|
||||
* before returning 1. It also must not sleep, since it is called with
|
||||
* the inode_hash_lock spinlock held.
|
||||
*
|
||||
* This is a even more generalized version of ilookup5() when the
|
||||
* function must never block --- find_inode() can block in
|
||||
* __wait_on_freeing_inode() --- or when the caller can not increment
|
||||
* the reference count because the resulting iput() might cause an
|
||||
* inode eviction. The tradeoff is that the @match funtion must be
|
||||
* very carefully implemented.
|
||||
*/
|
||||
struct inode *find_inode_nowait(struct super_block *sb,
|
||||
unsigned long hashval,
|
||||
int (*match)(struct inode *, unsigned long,
|
||||
void *),
|
||||
void *data)
|
||||
{
|
||||
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
|
||||
struct inode *inode, *ret_inode = NULL;
|
||||
int mval;
|
||||
|
||||
spin_lock(&inode_hash_lock);
|
||||
hlist_for_each_entry(inode, head, i_hash) {
|
||||
if (inode->i_sb != sb)
|
||||
continue;
|
||||
mval = match(inode, hashval, data);
|
||||
if (mval == 0)
|
||||
continue;
|
||||
if (mval == 1)
|
||||
ret_inode = inode;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
spin_unlock(&inode_hash_lock);
|
||||
return ret_inode;
|
||||
}
|
||||
EXPORT_SYMBOL(find_inode_nowait);
|
||||
|
||||
int insert_inode_locked(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
@@ -1418,11 +1470,20 @@ static void iput_final(struct inode *inode)
|
||||
*/
|
||||
void iput(struct inode *inode)
|
||||
{
|
||||
if (inode) {
|
||||
BUG_ON(inode->i_state & I_CLEAR);
|
||||
|
||||
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock))
|
||||
iput_final(inode);
|
||||
if (!inode)
|
||||
return;
|
||||
BUG_ON(inode->i_state & I_CLEAR);
|
||||
retry:
|
||||
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
|
||||
if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
|
||||
atomic_inc(&inode->i_count);
|
||||
inode->i_state &= ~I_DIRTY_TIME;
|
||||
spin_unlock(&inode->i_lock);
|
||||
trace_writeback_lazytime_iput(inode);
|
||||
mark_inode_dirty_sync(inode);
|
||||
goto retry;
|
||||
}
|
||||
iput_final(inode);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iput);
|
||||
@@ -1481,14 +1542,9 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This does the actual work of updating an inodes time or version. Must have
|
||||
* had called mnt_want_write() before calling this.
|
||||
*/
|
||||
static int update_time(struct inode *inode, struct timespec *time, int flags)
|
||||
int generic_update_time(struct inode *inode, struct timespec *time, int flags)
|
||||
{
|
||||
if (inode->i_op->update_time)
|
||||
return inode->i_op->update_time(inode, time, flags);
|
||||
int iflags = I_DIRTY_TIME;
|
||||
|
||||
if (flags & S_ATIME)
|
||||
inode->i_atime = *time;
|
||||
@@ -1498,9 +1554,27 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
|
||||
inode->i_ctime = *time;
|
||||
if (flags & S_MTIME)
|
||||
inode->i_mtime = *time;
|
||||
mark_inode_dirty_sync(inode);
|
||||
|
||||
if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION))
|
||||
iflags |= I_DIRTY_SYNC;
|
||||
__mark_inode_dirty(inode, iflags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_update_time);
|
||||
|
||||
/*
|
||||
* This does the actual work of updating an inodes time or version. Must have
|
||||
* had called mnt_want_write() before calling this.
|
||||
*/
|
||||
static int update_time(struct inode *inode, struct timespec *time, int flags)
|
||||
{
|
||||
int (*update_time)(struct inode *, struct timespec *, int);
|
||||
|
||||
update_time = inode->i_op->update_time ? inode->i_op->update_time :
|
||||
generic_update_time;
|
||||
|
||||
return update_time(inode, time, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* touch_atime - update the access time
|
||||
|
Reference in New Issue
Block a user