static inline int agl_should_run(struct ll_statahead_info *sai,
struct inode *inode)
{
- return (inode && S_ISREG(inode->i_mode) && sai->sai_agl_valid);
+ return inode && S_ISREG(inode->i_mode) && sai->sai_agl_task;
}
static inline struct ll_inode_info *
{
struct ll_inode_info *child = ll_i2info(inode);
struct ll_inode_info *parent = ll_i2info(sai->sai_dentry->d_inode);
- int added = 0;
spin_lock(&child->lli_agl_lock);
if (child->lli_agl_index == 0) {
LASSERT(list_empty(&child->lli_agl_list));
- igrab(inode);
spin_lock(&parent->lli_agl_lock);
- if (agl_list_empty(sai))
- added = 1;
- list_add_tail(&child->lli_agl_list, &sai->sai_agls);
- if (added && sai->sai_agl_task)
- wake_up_process(sai->sai_agl_task);
+ /* Re-check under the lock */
+ if (agl_should_run(sai, inode)) {
+ if (agl_list_empty(sai))
+ wake_up_process(sai->sai_agl_task);
+ igrab(inode);
+ list_add_tail(&child->lli_agl_list, &sai->sai_agls);
+ } else
+ child->lli_agl_index = 0;
spin_unlock(&parent->lli_agl_lock);
} else {
spin_unlock(&child->lli_agl_lock);
EXIT;
}
-#ifndef TASK_IDLE
-#define TASK_IDLE TASK_INTERRUPTIBLE
-#endif
-
/* async glimpse (agl) thread main function */
static int ll_agl_thread(void *arg)
{
kthread_stop(agl_task);
spin_lock(&plli->lli_agl_lock);
- sai->sai_agl_valid = 0;
while (!agl_list_empty(sai)) {
clli = agl_first_entry(sai);
list_del_init(&clli->lli_agl_list);
/* start agl thread */
static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
{
- struct ll_inode_info *plli;
- struct task_struct *task;
+ int node = cfs_cpt_spread_node(cfs_cpt_tab, CFS_CPT_ANY);
+ struct ll_inode_info *plli;
+ struct task_struct *task;
ENTRY;
sai, parent);
plli = ll_i2info(parent->d_inode);
- task = kthread_create(ll_agl_thread, parent,
- "ll_agl_%u", plli->lli_opendir_pid);
+ task = kthread_create_on_node(ll_agl_thread, parent, node, "ll_agl_%d",
+ plli->lli_opendir_pid);
if (IS_ERR(task)) {
CERROR("can't start ll_agl thread, rc: %ld\n", PTR_ERR(task));
RETURN_EXIT;
}
sai->sai_agl_task = task;
- sai->sai_agl_valid = 1;
atomic_inc(&ll_i2sbi(d_inode(parent))->ll_agl_total);
/* Get an extra reference that the thread holds */
ll_sai_get(d_inode(parent));
struct ll_statahead_info *sai = lli->lli_sai;
int first = 0;
struct md_op_data *op_data;
- struct ll_dir_chain chain;
struct page *page = NULL;
__u64 pos = 0;
int rc = 0;
if (!op_data)
GOTO(out, rc = -ENOMEM);
- ll_dir_chain_init(&chain);
while (pos != MDS_DIR_END_OFF && sai->sai_task) {
struct lu_dirpage *dp;
struct lu_dirent *ent;
}
sai->sai_in_readpage = 1;
- page = ll_get_dir_page(dir, op_data, pos, &chain);
+ page = ll_get_dir_page(dir, op_data, pos);
ll_unlock_md_op_lsm(op_data);
sai->sai_in_readpage = 0;
if (IS_ERR(page)) {
break;
}
}
- ll_dir_chain_fini(&chain);
ll_finish_md_op_data(op_data);
if (rc < 0) {
/* file is first dirent under @dir */
static int is_first_dirent(struct inode *dir, struct dentry *dentry)
{
- struct ll_dir_chain chain;
struct qstr *target = &dentry->d_name;
struct md_op_data *op_data;
int dot_de;
*FIXME choose the start offset of the readdir
*/
- ll_dir_chain_init(&chain);
- page = ll_get_dir_page(dir, op_data, 0, &chain);
+ page = ll_get_dir_page(dir, op_data, 0);
while (1) {
struct lu_dirpage *dp;
*/
ll_release_page(dir, page, le32_to_cpu(dp->ldp_flags) &
LDF_COLLIDE);
- page = ll_get_dir_page(dir, op_data, pos, &chain);
+ page = ll_get_dir_page(dir, op_data, pos);
}
}
EXIT;
out:
- ll_dir_chain_fini(&chain);
ll_finish_md_op_data(op_data);
return rc;
* \param[in] dir parent directory
* \param[in] dentry dentry that triggers statahead, normally the first
* dirent under @dir
+ * \param[in] agl indicate whether AGL is needed
* \retval -EAGAIN on success, because when this function is
* called, it's already in lookup call, so client should
* do it itself instead of waiting for statahead thread
* to do it asynchronously.
* \retval negative number upon error
*/
-static int start_statahead_thread(struct inode *dir, struct dentry *dentry)
+static int start_statahead_thread(struct inode *dir, struct dentry *dentry,
+ bool agl)
{
+ int node = cfs_cpt_spread_node(cfs_cpt_tab, CFS_CPT_ANY);
struct ll_inode_info *lli = ll_i2info(dir);
struct ll_statahead_info *sai = NULL;
struct dentry *parent = dentry->d_parent;
CDEBUG(D_READA, "start statahead thread: [pid %d] [parent %pd]\n",
current->pid, parent);
- task = kthread_create(ll_statahead_thread, parent, "ll_sa_%u",
- lli->lli_opendir_pid);
+ task = kthread_create_on_node(ll_statahead_thread, parent, node,
+ "ll_sa_%u", lli->lli_opendir_pid);
if (IS_ERR(task)) {
spin_lock(&lli->lli_sa_lock);
lli->lli_sai = NULL;
GOTO(out, rc);
}
- if (ll_i2sbi(parent->d_inode)->ll_flags & LL_SBI_AGL_ENABLED)
+ if (ll_i2sbi(parent->d_inode)->ll_flags & LL_SBI_AGL_ENABLED && agl)
ll_start_agl(parent, sai);
atomic_inc(&ll_i2sbi(parent->d_inode)->ll_sa_total);
RETURN(rc);
}
+/*
+ * Check whether statahead for @dir was started.
+ */
+static inline bool ll_statahead_started(struct inode *dir, bool agl)
+{
+ struct ll_inode_info *lli = ll_i2info(dir);
+ struct ll_statahead_info *sai;
+
+ spin_lock(&lli->lli_sa_lock);
+ sai = lli->lli_sai;
+ if (sai && (sai->sai_agl_task != NULL) != agl)
+ CDEBUG(D_READA,
+ "%s: Statahead AGL hint changed from %d to %d\n",
+ ll_i2sbi(dir)->ll_fsname,
+ sai->sai_agl_task != NULL, agl);
+ spin_unlock(&lli->lli_sa_lock);
+
+ return !!sai;
+}
+
/**
* statahead entry function, this is called when client getattr on a file, it
* will start statahead thread if this is the first dir entry, else revalidate
*
* \param[in] dir parent directory
* \param[out] dentryp dentry to getattr
+ * \param[in] agl whether start the agl thread
+ *
+ * \retval 1 on success
+ * \retval 0 revalidation from statahead cache failed, caller needs
+ * to getattr from server directly
+ * \retval negative number on error, caller often ignores this and
+ * then getattr from server
+ */
+int ll_start_statahead(struct inode *dir, struct dentry *dentry, bool agl)
+{
+ if (!ll_statahead_started(dir, agl))
+ return start_statahead_thread(dir, dentry, agl);
+ return 0;
+}
+
+/**
+ * revalidate dentry from statahead cache.
+ *
+ * \param[in] dir parent directory
+ * \param[out] dentryp dentry to getattr
* \param[in] unplug unplug statahead window only (normally for negative
* dentry)
* \retval 1 on success
* \retval negative number on error, caller often ignores this and
* then getattr from server
*/
-int ll_statahead(struct inode *dir, struct dentry **dentryp, bool unplug)
+int ll_revalidate_statahead(struct inode *dir, struct dentry **dentryp,
+ bool unplug)
{
struct ll_statahead_info *sai;
+ int rc = 0;
sai = ll_sai_get(dir);
if (sai) {
- int rc;
-
rc = revalidate_statahead_dentry(dir, sai, dentryp, unplug);
CDEBUG(D_READA, "revalidate statahead %pd: rc = %d.\n",
*dentryp, rc);
ll_sai_put(sai);
- return rc;
}
- return start_statahead_thread(dir, *dentryp);
+ return rc;
}