Commit e9792be1 authored by Lai Siyao's avatar Lai Siyao Committed by Greg Kroah-Hartman

staging: lustre: statahead: statahead thread wait for RPCs to finish

Statahead thread should wait for inflight stat RPCs to finish in
case statahead RPC callback may access data allocated in statahead
thread context.

ll_sa_entry_fini() should keep old entry if stat RPC is not
finished yet.

Simplify sai refcounting:
* newly allocated sai will hold one refcount, and it will put it
  after starting statahead thread.
* statahead thread holds one refcount.
* agl thread holds one refcount.
* stat process calls do_statahead_enter() which will try to get
  sai, and if it's valid, it will revalidate from statahead cache,
  and put refcount after use.
Signed-off-by: default avatarLai Siyao <lai.siyao@intel.com>
Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-3270
Reviewed-on: http://review.whamcloud.com/9663Reviewed-by: default avatarFan Yong <fan.yong@intel.com>
Reviewed-by: default avatarJames Simmons <uja.ornl@gmail.com>
Reviewed-by: default avatarOleg Drokin <oleg.drokin@intel.com>
Signed-off-by: default avatarJames Simmons <jsimmons@infradead.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d38a48e5
......@@ -806,7 +806,6 @@ struct md_enqueue_info {
int (*mi_cb)(struct ptlrpc_request *req,
struct md_enqueue_info *minfo, int rc);
__u64 mi_cbdata;
unsigned int mi_generation;
};
struct obd_ops {
......
......@@ -279,7 +279,7 @@ static int ll_revalidate_dentry(struct dentry *dentry,
if (lookup_flags & (LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE))
return 1;
if (d_need_statahead(dir, dentry) <= 0)
if (!dentry_need_statahead(dir, dentry))
return 1;
if (lookup_flags & LOOKUP_RCU)
......
......@@ -351,13 +351,11 @@ int ll_file_release(struct inode *inode, struct file *file)
fd = LUSTRE_FPRIVATE(file);
LASSERT(fd);
/* The last ref on @file, maybe not be the owner pid of statahead.
* Different processes can open the same dir, "ll_opendir_key" means:
* it is me that should stop the statahead thread.
/* The last ref on @file, maybe not be the owner pid of statahead,
* because parent and child process can share the same file handle.
*/
if (S_ISDIR(inode->i_mode) && lli->lli_opendir_key == fd &&
lli->lli_opendir_pid != 0)
ll_stop_statahead(inode, lli->lli_opendir_key);
if (S_ISDIR(inode->i_mode) && lli->lli_opendir_key == fd)
ll_deauthorize_statahead(inode, fd);
if (is_root_inode(inode)) {
LUSTRE_FPRIVATE(file) = NULL;
......@@ -530,7 +528,7 @@ int ll_file_open(struct inode *inode, struct file *file)
struct obd_client_handle **och_p = NULL;
__u64 *och_usecount = NULL;
struct ll_file_data *fd;
int rc = 0, opendir_set = 0;
int rc = 0;
CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), flags %o\n",
PFID(ll_inode2fid(inode)), inode, file->f_flags);
......@@ -545,16 +543,8 @@ int ll_file_open(struct inode *inode, struct file *file)
}
fd->fd_file = file;
if (S_ISDIR(inode->i_mode)) {
spin_lock(&lli->lli_sa_lock);
if (!lli->lli_opendir_key && !lli->lli_sai &&
lli->lli_opendir_pid == 0) {
lli->lli_opendir_key = fd;
lli->lli_opendir_pid = current_pid();
opendir_set = 1;
}
spin_unlock(&lli->lli_sa_lock);
}
if (S_ISDIR(inode->i_mode))
ll_authorize_statahead(inode, fd);
if (is_root_inode(inode)) {
LUSTRE_FPRIVATE(file) = fd;
......@@ -713,9 +703,10 @@ int ll_file_open(struct inode *inode, struct file *file)
mutex_unlock(&lli->lli_och_mutex);
out_openerr:
if (opendir_set != 0)
ll_stop_statahead(inode, lli->lli_opendir_key);
ll_file_data_put(fd);
if (lli->lli_opendir_key == fd)
ll_deauthorize_statahead(inode, fd);
if (fd)
ll_file_data_put(fd);
} else {
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1);
}
......
......@@ -172,6 +172,13 @@ struct ll_inode_info {
* -- I am the owner of dir statahead.
*/
pid_t d_opendir_pid;
/* stat will try to access statahead entries or start
* statahead if this flag is set, and this flag will be
* set upon dir open, and cleared when dir is closed,
* statahead hit ratio is too low, or start statahead
* thread failed.
*/
unsigned int d_sa_enabled:1;
/* directory stripe information */
struct lmv_stripe_md *d_lsm_md;
/* striped directory size */
......@@ -184,6 +191,7 @@ struct ll_inode_info {
#define lli_opendir_key u.d.d_opendir_key
#define lli_sai u.d.d_sai
#define lli_sa_lock u.d.d_sa_lock
#define lli_sa_enabled u.d.d_sa_enabled
#define lli_opendir_pid u.d.d_opendir_pid
#define lli_lsm_md u.d.d_lsm_md
#define lli_stripe_dir_size u.d.d_stripe_size
......@@ -495,6 +503,9 @@ struct ll_sb_info {
atomic_t ll_sa_wrong; /* statahead thread stopped for
* low hit ratio
*/
atomic_t ll_sa_running; /* running statahead thread
* count
*/
atomic_t ll_agl_total; /* AGL thread started count */
dev_t ll_sdev_orig; /* save s_dev before assign for
......@@ -1040,7 +1051,8 @@ struct ll_statahead_info {
int do_statahead_enter(struct inode *dir, struct dentry **dentry,
int only_unplug);
void ll_stop_statahead(struct inode *dir, void *key);
void ll_authorize_statahead(struct inode *dir, void *key);
void ll_deauthorize_statahead(struct inode *dir, void *key);
blkcnt_t dirty_cnt(struct inode *inode);
......@@ -1086,25 +1098,31 @@ ll_statahead_mark(struct inode *dir, struct dentry *dentry)
ldd->lld_sa_generation = sai->sai_generation;
}
static inline int
d_need_statahead(struct inode *dir, struct dentry *dentryp)
static inline bool
dentry_need_statahead(struct inode *dir, struct dentry *dentry)
{
struct ll_inode_info *lli;
struct ll_dentry_data *ldd;
if (ll_i2sbi(dir)->ll_sa_max == 0)
return -EAGAIN;
return false;
lli = ll_i2info(dir);
/*
* statahead is not allowed for this dir, there may be three causes:
* 1. dir is not opened.
* 2. statahead hit ratio is too low.
* 3. previous stat started statahead thread failed.
*/
if (!lli->lli_sa_enabled)
return false;
/* not the same process, don't statahead */
if (lli->lli_opendir_pid != current_pid())
return -EAGAIN;
/* statahead has been stopped */
if (!lli->lli_opendir_key)
return -EAGAIN;
return false;
ldd = ll_d2d(dentryp);
ldd = ll_d2d(dentry);
/*
* When stats a dentry, the system trigger more than once "revalidate"
* or "lookup", for "getattr", for "getxattr", and maybe for others.
......@@ -1122,19 +1140,16 @@ d_need_statahead(struct inode *dir, struct dentry *dentryp)
*/
if (ldd && lli->lli_sai &&
ldd->lld_sa_generation == lli->lli_sai->sai_generation)
return -EAGAIN;
return false;
return 1;
return true;
}
static inline int
ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int only_unplug)
{
int ret;
ret = d_need_statahead(dir, *dentryp);
if (ret <= 0)
return ret;
if (!dentry_need_statahead(dir, *dentryp))
return -EAGAIN;
return do_statahead_enter(dir, dentryp, only_unplug);
}
......
......@@ -116,6 +116,7 @@ static struct ll_sb_info *ll_init_sbi(struct super_block *sb)
sbi->ll_sa_max = LL_SA_RPC_DEF;
atomic_set(&sbi->ll_sa_total, 0);
atomic_set(&sbi->ll_sa_wrong, 0);
atomic_set(&sbi->ll_sa_running, 0);
atomic_set(&sbi->ll_agl_total, 0);
sbi->ll_flags |= LL_SBI_AGL_ENABLED;
......@@ -630,6 +631,12 @@ void ll_kill_super(struct super_block *sb)
if (sbi) {
sb->s_dev = sbi->ll_sdev_orig;
sbi->ll_umounting = 1;
/* wait running statahead threads to quit */
while (atomic_read(&sbi->ll_sa_running) > 0) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(MSEC_PER_SEC >> 3));
}
}
}
......@@ -795,6 +802,7 @@ void ll_lli_init(struct ll_inode_info *lli)
lli->lli_sai = NULL;
spin_lock_init(&lli->lli_sa_lock);
lli->lli_opendir_pid = 0;
lli->lli_sa_enabled = 0;
} else {
mutex_init(&lli->lli_size_mutex);
lli->lli_symlink_name = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment