Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 208337
b: refs/heads/master
c: 080dcec
h: refs/heads/master
i:
  208335: 5760715
v: v3
  • Loading branch information
Artem Bityutskiy authored and Jens Axboe committed Aug 7, 2010
1 parent 0ef991c commit 8d52e25
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 66 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 297252c81de8043ca6c36e5984c24fdb5aab9013
refs/heads/master: 080dcec41709be72613133f695be75b98dd43e88
1 change: 0 additions & 1 deletion trunk/include/linux/backing-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ struct bdi_writeback {

struct backing_dev_info {
struct list_head bdi_list;
struct rcu_head rcu_head;
unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
unsigned long state; /* Always use atomic bitops on this */
unsigned int capabilities; /* Device capabilities */
Expand Down
82 changes: 18 additions & 64 deletions trunk/mm/backing-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ static struct timer_list sync_supers_timer;
static int bdi_sync_supers(void *);
static void sync_supers_timer_fn(unsigned long);

static void bdi_add_default_flusher_thread(struct backing_dev_info *bdi);

#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
Expand Down Expand Up @@ -331,6 +329,7 @@ static int bdi_forker_thread(void *ptr)
set_user_nice(current, 0);

for (;;) {
bool fork = false;
struct task_struct *task;
struct backing_dev_info *bdi, *tmp;

Expand All @@ -349,23 +348,30 @@ static int bdi_forker_thread(void *ptr)
* a thread registered. If so, set that up.
*/
list_for_each_entry_safe(bdi, tmp, &bdi_list, bdi_list) {
if (!bdi_cap_writeback_dirty(bdi))
continue;
if (bdi->wb.task)
continue;
if (list_empty(&bdi->work_list) &&
!bdi_has_dirty_io(bdi))
continue;

bdi_add_default_flusher_thread(bdi);
WARN(!test_bit(BDI_registered, &bdi->state),
"bdi %p/%s is not registered!\n", bdi, bdi->name);

list_del_rcu(&bdi->bdi_list);
fork = true;
break;
}
spin_unlock_bh(&bdi_lock);

/* Keep working if default bdi still has things to do */
if (!list_empty(&me->bdi->work_list))
__set_current_state(TASK_RUNNING);

if (list_empty(&bdi_pending_list)) {
if (!fork) {
unsigned long wait;

spin_unlock_bh(&bdi_lock);
wait = msecs_to_jiffies(dirty_writeback_interval * 10);
if (wait)
schedule_timeout(wait);
Expand All @@ -378,13 +384,13 @@ static int bdi_forker_thread(void *ptr)
__set_current_state(TASK_RUNNING);

/*
* This is our real job - check for pending entries in
* bdi_pending_list, and create the threads that got added
* Set the pending bit - if someone will try to unregister this
* bdi - it'll wait on this bit.
*/
bdi = list_entry(bdi_pending_list.next, struct backing_dev_info,
bdi_list);
list_del_init(&bdi->bdi_list);
spin_unlock_bh(&bdi_lock);
set_bit(BDI_pending, &bdi->state);

/* Make sure no one uses the picked bdi */
synchronize_rcu();

task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s",
dev_name(bdi->dev));
Expand All @@ -397,7 +403,7 @@ static int bdi_forker_thread(void *ptr)
* flush other bdi's to free memory.
*/
spin_lock_bh(&bdi_lock);
list_add_tail(&bdi->bdi_list, &bdi_pending_list);
list_add_tail_rcu(&bdi->bdi_list, &bdi_list);
spin_unlock_bh(&bdi_lock);

bdi_flush_io(bdi);
Expand All @@ -408,57 +414,6 @@ static int bdi_forker_thread(void *ptr)
return 0;
}

static void bdi_add_to_pending(struct rcu_head *head)
{
struct backing_dev_info *bdi;

bdi = container_of(head, struct backing_dev_info, rcu_head);
INIT_LIST_HEAD(&bdi->bdi_list);

spin_lock(&bdi_lock);
list_add_tail(&bdi->bdi_list, &bdi_pending_list);
spin_unlock(&bdi_lock);

/*
* We are now on the pending list, wake up bdi_forker_task()
* to finish the job and add us back to the active bdi_list
*/
wake_up_process(default_backing_dev_info.wb.task);
}

/*
* Add the default flusher thread that gets created for any bdi
* that has dirty data pending writeout
*/
static void bdi_add_default_flusher_thread(struct backing_dev_info *bdi)
{
if (!bdi_cap_writeback_dirty(bdi))
return;

if (WARN_ON(!test_bit(BDI_registered, &bdi->state))) {
printk(KERN_ERR "bdi %p/%s is not registered!\n",
bdi, bdi->name);
return;
}

/*
* Check with the helper whether to proceed adding a thread. Will only
* abort if we two or more simultanous calls to
* bdi_add_default_flusher_thread() occured, further additions will
* block waiting for previous additions to finish.
*/
if (!test_and_set_bit(BDI_pending, &bdi->state)) {
list_del_rcu(&bdi->bdi_list);

/*
* We must wait for the current RCU period to end before
* moving to the pending list. So schedule that operation
* from an RCU callback.
*/
call_rcu(&bdi->rcu_head, bdi_add_to_pending);
}
}

/*
* Remove bdi from bdi_list, and ensure that it is no longer visible
*/
Expand Down Expand Up @@ -599,7 +554,6 @@ int bdi_init(struct backing_dev_info *bdi)
bdi->max_ratio = 100;
bdi->max_prop_frac = PROP_FRAC_BASE;
spin_lock_init(&bdi->wb_lock);
INIT_RCU_HEAD(&bdi->rcu_head);
INIT_LIST_HEAD(&bdi->bdi_list);
INIT_LIST_HEAD(&bdi->work_list);

Expand Down

0 comments on commit 8d52e25

Please sign in to comment.