@@ -35,6 +35,7 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/delay.h>
#define DEBUG_SUBSYSTEM S_LLITE
@@ -299,7 +300,6 @@ static void sa_put(struct ll_statahead_info *sai, struct sa_entry *entry,
if (sai->sai_task)
wake_up_process(sai->sai_task);
spin_unlock(&lli->lli_sa_lock);
-
}
/*
@@ -898,37 +898,40 @@ static int ll_agl_thread(void *arg)
CDEBUG(D_READA, "agl thread started: sai %p, parent %pd\n",
sai, parent);
- while (!kthread_should_stop()) {
-
+ while (({set_current_state(TASK_IDLE);
+ !kthread_should_stop(); })) {
spin_lock(&plli->lli_agl_lock);
- /* The statahead thread maybe help to process AGL entries,
- * so check whether list empty again.
- */
clli = list_first_entry_or_null(&sai->sai_agls,
struct ll_inode_info,
lli_agl_list);
if (clli) {
+ __set_current_state(TASK_RUNNING);
list_del_init(&clli->lli_agl_list);
spin_unlock(&plli->lli_agl_lock);
ll_agl_trigger(&clli->lli_vfs_inode, sai);
cond_resched();
} else {
spin_unlock(&plli->lli_agl_lock);
- }
-
- set_current_state(TASK_IDLE);
- if (list_empty(&sai->sai_agls) &&
- !kthread_should_stop())
schedule();
- __set_current_state(TASK_RUNNING);
+ }
}
+ __set_current_state(TASK_RUNNING);
return 0;
}
static void ll_stop_agl(struct ll_statahead_info *sai)
{
- struct ll_inode_info *plli = ll_i2info(sai->sai_dentry->d_inode);
+ struct dentry *parent = sai->sai_dentry;
+ struct ll_inode_info *plli = ll_i2info(parent->d_inode);
struct ll_inode_info *clli;
+ struct task_struct *agl_task;
+
+ spin_lock(&plli->lli_agl_lock);
+ agl_task = sai->sai_agl_task;
+ sai->sai_agl_task = NULL;
+ spin_unlock(&plli->lli_agl_lock);
+ if (!agl_task)
+ return;
CDEBUG(D_READA, "stop agl thread: sai %p pid %u\n",
sai, (unsigned int)sai->sai_agl_task->pid);
@@ -1076,14 +1079,19 @@ static int ll_statahead_thread(void *arg)
fid_le_to_cpu(&fid, &ent->lde_fid);
- do {
- sa_handle_callback(sai);
+ while (({set_current_state(TASK_IDLE);
+ sai->sai_task; })) {
+ if (sa_has_callback(sai)) {
+ __set_current_state(TASK_RUNNING);
+ sa_handle_callback(sai);
+ }
spin_lock(&lli->lli_agl_lock);
while (sa_sent_full(sai) &&
!agl_list_empty(sai)) {
struct ll_inode_info *clli;
+ __set_current_state(TASK_RUNNING);
clli = list_first_entry(&sai->sai_agls,
struct ll_inode_info,
lli_agl_list);
@@ -1097,15 +1105,11 @@ static int ll_statahead_thread(void *arg)
}
spin_unlock(&lli->lli_agl_lock);
- set_current_state(TASK_IDLE);
- if (sa_sent_full(sai) &&
- !sa_has_callback(sai) &&
- agl_list_empty(sai) &&
- sai->sai_task)
- /* wait for spare statahead window */
- schedule();
- __set_current_state(TASK_RUNNING);
- } while (sa_sent_full(sai) && sai->sai_task);
+ if (!sa_sent_full(sai))
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
sa_statahead(parent, name, namelen, &fid);
}
@@ -1138,21 +1142,18 @@ static int ll_statahead_thread(void *arg)
* statahead is finished, but statahead entries need to be cached, wait
* for file release to stop me.
*/
- while (sai->sai_task) {
- sa_handle_callback(sai);
-
- set_current_state(TASK_IDLE);
- /* ensure we see the NULL stored by
- * ll_deauthorize_statahead()
- */
- if (!sa_has_callback(sai) &&
- smp_load_acquire(&sai->sai_task))
+ while (({set_current_state(TASK_IDLE);
+ sai->sai_task; })) {
+ if (sa_has_callback(sai)) {
+ __set_current_state(TASK_RUNNING);
+ sa_handle_callback(sai);
+ } else {
schedule();
- __set_current_state(TASK_RUNNING);
+ }
}
+ __set_current_state(TASK_RUNNING);
out:
- if (sai->sai_agl_task)
- ll_stop_agl(sai);
+ ll_stop_agl(sai);
/*
* wait for inflight statahead RPCs to finish, and then we can free sai
@@ -1160,7 +1161,7 @@ static int ll_statahead_thread(void *arg)
*/
while (sai->sai_sent != sai->sai_replied) {
/* in case we're not woken up, timeout wait */
- schedule_timeout_idle(HZ>>3);
+ msleep(125);
}
/* release resources held by statahead RPCs */
@@ -1176,7 +1177,7 @@ static int ll_statahead_thread(void *arg)
wake_up(&sai->sai_waitq);
ll_sai_put(sai);
- do_exit(rc);
+ return rc;
}
/* authorize opened dir handle @key to statahead */
@@ -1220,18 +1221,15 @@ void ll_deauthorize_statahead(struct inode *dir, void *key)
sai = lli->lli_sai;
if (sai && sai->sai_task) {
/*
- * statahead thread may not quit yet because it needs to cache
- * entries, now it's time to tell it to quit.
+ * statahead thread may not have quit yet because it needs to
+ * cache entries, now it's time to tell it to quit.
*
- * In case sai is released, wake_up() is called inside spinlock,
- * so we use smp_store_release() to serialize ops.
+ * wake_up_process() provides the necessary barriers
+ * to pair with set_current_state().
*/
struct task_struct *task = sai->sai_task;
- /* ensure ll_statahead_thread sees the NULL before
- * calling schedule() again.
- */
- smp_store_release(&sai->sai_task, NULL);
+ sai->sai_task = NULL;
wake_up_process(task);
}
spin_unlock(&lli->lli_sa_lock);
@@ -1510,6 +1508,11 @@ static int revalidate_statahead_dentry(struct inode *dir,
ldd = ll_d2d(*dentryp);
ldd->lld_sa_generation = lli->lli_sa_generation;
sa_put(sai, entry, lli);
+ spin_lock(&lli->lli_sa_lock);
+ if (sai->sai_task)
+ wake_up_process(sai->sai_task);
+ spin_unlock(&lli->lli_sa_lock);
+
return rc;
}