Skip to contentSkip to conversation

per device dirty throttling -v3

PATCH In review [email protected] 4 participants 27 messages Apr 5, 2007 – Sep 26, 2007

Subsystems (18)
lore
Share & tools
lore
#0 lore raw

cover per device dirty throttling -v3

Against 2.6.21-rc5-mm4 without:
per-backing_dev-dirty-and-writeback-page-accounting.patch

This series implements BDI independent dirty limits and congestion control.

This should solve several problems we currently have in this area:

- mutual interference starvation (for any number of BDIs), and
- deadlocks with stacked BDIs (loop and FUSE).

All the fancy new congestion code has been compile and boot tested, but not much more. I'm posting to get feedback on the ideas.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw

PATCH 1/12 nfs: remove congestion_end()

Its redundant, clear_bdi_congested() already wakes the waiters.

---
 fs/nfs/write.c              |    4 +---
 include/linux/backing-dev.h |    1 -
 mm/backing-dev.c            |   13 -------------
 3 files changed, 1 insertion(+), 17 deletions(-)
fs/nfs/write.c +1 -3
Index: linux-2.6-mm/fs/nfs/write.c
===================================================================
@@ -235,10 +235,8 @@ static void nfs_end_page_writeback(struc
 	struct nfs_server *nfss = NFS_SERVER(inode);
 
 	end_page_writeback(page);
-	if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) {
+	if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
 		clear_bdi_congested(&nfss->backing_dev_info, WRITE);
-		congestion_end(WRITE);
-	}
 }
 
 /*
include/linux/backing-dev.h +0 -1
Index: linux-2.6-mm/include/linux/backing-dev.h
===================================================================
@@ -96,7 +96,6 @@ void clear_bdi_congested(struct backing_
 void set_bdi_congested(struct backing_dev_info *bdi, int rw);
 long congestion_wait(int rw, long timeout);
 long congestion_wait_interruptible(int rw, long timeout);
-void congestion_end(int rw);
 
 #define bdi_cap_writeback_dirty(bdi) \
 	(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
mm/backing-dev.c +0 -13
Index: linux-2.6-mm/mm/backing-dev.c
===================================================================
@@ -70,16 +70,3 @@ long congestion_wait_interruptible(int r
 	return ret;
 }
 EXPORT_SYMBOL(congestion_wait_interruptible);
-
-/**
- * congestion_end - wake up sleepers on a congested backing_dev_info
- * @rw: READ or WRITE
- */
-void congestion_end(int rw)
-{
-	wait_queue_head_t *wqh = &congestion_wqh[rw];
-
-	if (waitqueue_active(wqh))
-		wake_up(wqh);
-}
-EXPORT_SYMBOL(congestion_end);

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#2 lore raw

PATCH 2/12 mm: scalable bdi statistics counters.

In reply to [email protected]

Provide scalable per backing_dev_info statistics counters modeled on the ZVC code.

---
 block/ll_rw_blk.c           |    1 
 drivers/block/rd.c          |    2 
 drivers/char/mem.c          |    2 
 fs/char_dev.c               |    1 
 fs/fuse/inode.c             |    1 
 fs/nfs/client.c             |    1 
 include/linux/backing-dev.h |   98 +++++++++++++++++++++++++++++++++++++++++
 mm/backing-dev.c            |  103 ++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 209 insertions(+)
block/ll_rw_blk.c +1 -0
Index: linux-2.6-mm/block/ll_rw_blk.c
===================================================================
@@ -208,6 +208,7 @@ void blk_queue_make_request(request_queu
 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
 	q->make_request_fn = mfn;
+	bdi_init(&q->backing_dev_info);
 	blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
 	blk_queue_hardsect_size(q, 512);
 	blk_queue_dma_alignment(q, 511);
include/linux/backing-dev.h +98 -0

118 lines not on this page · raw message

mm/backing-dev.c +103 -0

106 lines not on this page · raw message

drivers/block/rd.c +2 -0
Index: linux-2.6-mm/drivers/block/rd.c
===================================================================
@@ -421,6 +421,8 @@ static int __init rd_init(void)
 	int i;
 	int err = -ENOMEM;
 
+	bdi_init(&rd_file_backing_dev_info);
+
 	if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
 			(rd_blocksize & (rd_blocksize-1))) {
 		printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
drivers/char/mem.c +2 -0
Index: linux-2.6-mm/drivers/char/mem.c
===================================================================
@@ -987,6 +987,8 @@ static int __init chr_dev_init(void)
 			      MKDEV(MEM_MAJOR, devlist[i].minor),
 			      devlist[i].name);
 
+	bdi_init(&zero_bdi);
+
 	return 0;
 }
 
fs/char_dev.c +1 -0
Index: linux-2.6-mm/fs/char_dev.c
===================================================================
@@ -548,6 +548,7 @@ static struct kobject *base_probe(dev_t 
 void __init chrdev_init(void)
 {
 	cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
+	bdi_init(&directly_mappable_cdev_bdi);
 }
 
 
fs/fuse/inode.c +1 -0
Index: linux-2.6-mm/fs/fuse/inode.c
===================================================================
@@ -413,6 +413,7 @@ static struct fuse_conn *new_conn(void)
 		atomic_set(&fc->num_waiting, 0);
 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
+		bdi_init(&fc->bdi);
 		fc->reqctr = 0;
 		fc->blocked = 1;
 		get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
fs/nfs/client.c +1 -0
Index: linux-2.6-mm/fs/nfs/client.c
===================================================================
@@ -661,6 +661,7 @@ static void nfs_server_set_fsinfo(struct
 	server->backing_dev_info.ra_pages0 = min_t(unsigned, server->rpages,
 				VM_MIN_READAHEAD >> (PAGE_CACHE_SHIFT - 10));
 	server->backing_dev_info.ra_thrash_bytes = server->rsize * NFS_MAX_READAHEAD;
+	bdi_init(&server->backing_dev_info);
 
 	if (server->wsize > max_rpc_payload)
 		server->wsize = max_rpc_payload;

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#3 lore raw

Re: [PATCH 02/12] mm: scalable bdi statistics counters.

Quoted 4 lines · On Thu, 05 Apr 2007 19:42:11 +0200 [email protected] wrote:

Provide scalable per backing_dev_info statistics counters modeled on the ZVC code.

Quoted 9 lines
---
 block/ll_rw_blk.c           |    1 
 drivers/block/rd.c          |    2 
 drivers/char/mem.c          |    2 
 fs/char_dev.c               |    1 
 fs/fuse/inode.c             |    1 
 fs/nfs/client.c             |    1 
 include/linux/backing-dev.h |   98 +++++++++++++++++++++++++++++++++++++++++
 mm/backing-dev.c            |  103 ++++++++++++++++++++++++++++++++++++++++++++

madness! Quite duplicative of vmstat.h, yet all this infrastructure is still only usable in one specific application.

Can we please look at generalising the vmstat.h stuff?

Or, the API in percpu_counter.h appears suitable to this application. (The comment at line 6 is a total lie).

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#4 lore raw

Re: [PATCH 02/12] mm: scalable bdi statistics counters.

Quoted 17 lines · Andrew Morton
Quoted 4 lines · On Thu, 05 Apr 2007 19:42:11 +0200 [email protected] wrote:

Provide scalable per backing_dev_info statistics counters modeled on the ZVC code.

Quoted 9 lines
---
 block/ll_rw_blk.c           |    1 
 drivers/block/rd.c          |    2 
 drivers/char/mem.c          |    2 
 fs/char_dev.c               |    1 
 fs/fuse/inode.c             |    1 
 fs/nfs/client.c             |    1 
 include/linux/backing-dev.h |   98 +++++++++++++++++++++++++++++++++++++++++
 mm/backing-dev.c            |  103 ++++++++++++++++++++++++++++++++++++++++++++
Quoted 7 lines

madness! Quite duplicative of vmstat.h, yet all this infrastructure is still only usable in one specific application.

Can we please look at generalising the vmstat.h stuff?

Or, the API in percpu_counter.h appears suitable to this application. (The comment at line 6 is a total lie).

Ok, I'll see what I can come up with.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#5 lore raw

PATCH 3/12 mm: count dirty pages per BDI

In reply to [email protected]

Count per BDI dirty pages.

---
 fs/buffer.c                 |    1 +
 include/linux/backing-dev.h |    1 +
 mm/page-writeback.c         |    2 ++
 mm/truncate.c               |    1 +
 4 files changed, 5 insertions(+)
fs/buffer.c +1 -0
Index: linux-2.6/fs/buffer.c
===================================================================
@@ -740,6 +740,7 @@ int __set_page_dirty_buffers(struct page
 	if (page->mapping) {	/* Race with truncate? */
 		if (mapping_cap_account_dirty(mapping)) {
 			__inc_zone_page_state(page, NR_FILE_DIRTY);
+			__inc_bdi_stat(mapping->backing_dev_info, BDI_DIRTY);
 			task_io_account_write(PAGE_CACHE_SIZE);
 		}
 		radix_tree_tag_set(&mapping->page_tree,
mm/page-writeback.c +2 -0
Index: linux-2.6/mm/page-writeback.c
===================================================================
@@ -828,6 +828,7 @@ int __set_page_dirty_nobuffers(struct pa
 			BUG_ON(mapping2 != mapping);
 			if (mapping_cap_account_dirty(mapping)) {
 				__inc_zone_page_state(page, NR_FILE_DIRTY);
+				__inc_bdi_stat(mapping->backing_dev_info, BDI_DIRTY);
 				task_io_account_write(PAGE_CACHE_SIZE);
 			}
 			radix_tree_tag_set(&mapping->page_tree,
@@ -961,6 +962,7 @@ int clear_page_dirty_for_io(struct page 
 		 */
 		if (TestClearPageDirty(page)) {
 			dec_zone_page_state(page, NR_FILE_DIRTY);
+			dec_bdi_stat(mapping->backing_dev_info, BDI_DIRTY);
 			return 1;
 		}
 		return 0;
mm/truncate.c +1 -0
Index: linux-2.6/mm/truncate.c
===================================================================
@@ -71,6 +71,7 @@ void cancel_dirty_page(struct page *page
 		struct address_space *mapping = page->mapping;
 		if (mapping && mapping_cap_account_dirty(mapping)) {
 			dec_zone_page_state(page, NR_FILE_DIRTY);
+			dec_bdi_stat(mapping->backing_dev_info, BDI_DIRTY);
 			if (account_size)
 				task_io_account_cancelled_write(account_size);
 		}
include/linux/backing-dev.h +1 -0
Index: linux-2.6/include/linux/backing-dev.h
===================================================================
@@ -24,6 +24,7 @@ enum bdi_state {
 };
 
 enum bdi_stat_item {
+	BDI_DIRTY,
 	NR_BDI_STAT_ITEMS
 };
 

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#6 lore raw

PATCH 4/12 mm: count writeback pages per BDI

In reply to [email protected]

Count per BDI writeback pages.

---
 include/linux/backing-dev.h |    1 +
 mm/page-writeback.c         |    8 ++++++--
 2 files changed, 7 insertions(+), 2 deletions(-)
mm/page-writeback.c +6 -2
Index: linux-2.6/mm/page-writeback.c
===================================================================
@@ -981,10 +981,12 @@ int test_clear_page_writeback(struct pag
 
 		write_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestClearPageWriteback(page);
-		if (ret)
+		if (ret) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_WRITEBACK);
+			__dec_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
+		}
 		write_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestClearPageWriteback(page);
@@ -1004,10 +1006,12 @@ int test_set_page_writeback(struct page 
 
 		write_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestSetPageWriteback(page);
-		if (!ret)
+		if (!ret) {
 			radix_tree_tag_set(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_WRITEBACK);
+			__inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
+		}
 		if (!PageDirty(page))
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
include/linux/backing-dev.h +1 -0
Index: linux-2.6/include/linux/backing-dev.h
===================================================================
@@ -25,6 +25,7 @@ enum bdi_state {
 
 enum bdi_stat_item {
 	BDI_DIRTY,
+	BDI_WRITEBACK,
 	NR_BDI_STAT_ITEMS
 };
 

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#7 lore raw

PATCH 5/12 mm: count unstable pages per BDI

In reply to [email protected]

Count per BDI unstable pages.

---
 fs/nfs/write.c              |    4 ++++
 include/linux/backing-dev.h |    1 +
 2 files changed, 5 insertions(+)
fs/nfs/write.c +4 -0
Index: linux-2.6/fs/nfs/write.c
===================================================================
@@ -451,6 +451,7 @@ nfs_mark_request_commit(struct nfs_page 
 	nfsi->ncommit++;
 	spin_unlock(&nfsi->req_lock);
 	inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+	inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_UNSTABLE);
 	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 }
 #endif
@@ -511,6 +512,7 @@ static void nfs_cancel_commit_list(struc
 	while(!list_empty(head)) {
 		req = nfs_list_entry(head->next);
 		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+		dec_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_UNSTABLE);
 		nfs_list_remove_request(req);
 		nfs_inode_remove_request(req);
 		nfs_unlock_request(req);
@@ -1236,6 +1238,7 @@ nfs_commit_list(struct inode *inode, str
 		nfs_list_remove_request(req);
 		nfs_mark_request_commit(req);
 		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+		dec_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_UNSTABLE);
 		nfs_clear_page_writeback(req);
 	}
 	return -ENOMEM;
@@ -1260,6 +1263,7 @@ static void nfs_commit_done(struct rpc_t
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+		dec_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_UNSTABLE);
 
 		dprintk("NFS: commit (%s/%Ld %d@%Ld)",
 			req->wb_context->dentry->d_inode->i_sb->s_id,
include/linux/backing-dev.h +1 -0
Index: linux-2.6/include/linux/backing-dev.h
===================================================================
@@ -26,6 +26,7 @@ enum bdi_state {
 enum bdi_stat_item {
 	BDI_DIRTY,
 	BDI_WRITEBACK,
+	BDI_UNSTABLE,
 	NR_BDI_STAT_ITEMS
 };
 

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#8 lore raw

PATCH 6/12 mm: expose BDI statistics in sysfs.

In reply to [email protected]

Expose the per BDI stats in /sys/block/<dev>/queue/*

---
 block/ll_rw_blk.c   |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 mm/page-writeback.c |    2 -
 2 files changed, 82 insertions(+), 1 deletion(-)
block/ll_rw_blk.c +32 -0
Index: linux-2.6/block/ll_rw_blk.c
===================================================================
@@ -3975,6 +3975,20 @@ static ssize_t queue_max_hw_sectors_show
 	return queue_var_show(max_hw_sectors_kb, (page));
 }
 
+static ssize_t queue_nr_dirty_show(struct request_queue *q, char *page)
+{
+	return sprintf(page, "%lu\n", bdi_stat(&q->backing_dev_info, BDI_DIRTY));
+}
+
+static ssize_t queue_nr_writeback_show(struct request_queue *q, char *page)
+{
+	return sprintf(page, "%lu\n", bdi_stat(&q->backing_dev_info, BDI_WRITEBACK));
+}
+
+static ssize_t queue_nr_unstable_show(struct request_queue *q, char *page)
+{
+	return sprintf(page, "%lu\n", bdi_stat(&q->backing_dev_info, BDI_UNSTABLE));
+}
 
 static struct queue_sysfs_entry queue_requests_entry = {
 	.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
@@ -4005,6 +4019,21 @@ static struct queue_sysfs_entry queue_ma
 	.show = queue_max_hw_sectors_show,
 };
 
+static struct queue_sysfs_entry queue_dirty_entry = {
+	.attr = {.name = "dirty_pages", .mode = S_IRUGO },
+	.show = queue_nr_dirty_show,
+};
+
+static struct queue_sysfs_entry queue_writeback_entry = {
+	.attr = {.name = "writeback_pages", .mode = S_IRUGO },
+	.show = queue_nr_writeback_show,
+};
+
+static struct queue_sysfs_entry queue_unstable_entry = {
+	.attr = {.name = "unstable_pages", .mode = S_IRUGO },
+	.show = queue_nr_unstable_show,
+};
+
 static struct queue_sysfs_entry queue_iosched_entry = {
 	.attr = {.name = "scheduler", .mode = S_IRUGO | S_IWUSR },
 	.show = elv_iosched_show,
@@ -4017,6 +4046,9 @@ static struct attribute *default_attrs[]
 	&queue_initial_ra_entry.attr,
 	&queue_max_hw_sectors_entry.attr,
 	&queue_max_sectors_entry.attr,
+	&queue_dirty_entry.attr,
+	&queue_writeback_entry.attr,
+	&queue_unstable_entry.attr,
 	&queue_iosched_entry.attr,
 	NULL,
 };

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

PATCH 7/12 mm: per device dirty threshold

In reply to [email protected]

Scale writeback cache per backing device, proportional to its writeout speed.

akpm sayeth:

Quoted 5 lines

Which problem are we trying to solve here? afaik our two uppermost problems are:

a) Heavy write to queue A causes light writer to queue B to blok for a long time in balance_dirty_pages(). Even if the devices have the same speed.

This one; esp when not the same speed. The - my usb stick makes my computer suck - problem. But even on similar speed, the separation of device should avoid blocking dev B when dev A is being throttled.

The writeout speed is measure dynamically, so when it doesn't have anything to write out for a while its writeback cache size goes to 0.

Conversely, when starting up it will in the beginning act almost synchronous but will quickly build up a 'fair' share of the writeback cache.

Quoted 2 lines

b) heavy write to device A causes light write to device A to block for a long time in balance_dirty_pages(), occasionally. Harder to fix.

This will indeed take more. I've thought about it though. But one quickly ends up with per task state.

How it all works:

We pick a 2^n value based on the total vm size to act as a period - vm_cycle_shift. This period measures 'time' in writeout events.

Each writeout increases time and adds to a per bdi counter. This counter is halved when a period expires. So per bdi speed is:

0.5 * (previous cycle speed) + this cycle's events.

---
 include/linux/backing-dev.h |    8 ++
 mm/backing-dev.c            |    3 
 mm/page-writeback.c         |  166 +++++++++++++++++++++++++++++++++++---------
 3 files changed, 145 insertions(+), 32 deletions(-)
include/linux/backing-dev.h +8 -0
Index: linux-2.6/include/linux/backing-dev.h
===================================================================
@@ -27,6 +27,8 @@ enum bdi_stat_item {
 	BDI_DIRTY,
 	BDI_WRITEBACK,
 	BDI_UNSTABLE,
+	BDI_WRITEOUT,
+	BDI_WRITEOUT_TOTAL,
 	NR_BDI_STAT_ITEMS
 };
 
@@ -50,6 +52,12 @@ struct backing_dev_info {
 	void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
 	void *unplug_io_data;
 
+	/*
+	 * data used for scaling the writeback cache
+	 */
+	spinlock_t lock;	/* protect the cycle count */
+	unsigned long cycles;	/* writeout cycles */
+
 	atomic_long_t bdi_stats[NR_BDI_STAT_ITEMS];
 #ifdef CONFIG_SMP
 	struct bdi_per_cpu_data pcd[NR_CPUS];
mm/page-writeback.c +134 -32

255 lines not on this page · raw message

mm/backing-dev.c +3 -0
Index: linux-2.6/mm/backing-dev.c
===================================================================
@@ -91,6 +91,9 @@ void bdi_init(struct backing_dev_in
 {
 	int i;
 
+	spin_lock_init(&bdi->lock);
+	bdi->cycles = 0;
+
 	for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
 		atomic_long_set(&bdi->bdi_stats[i], 0);
 

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#10 lore raw

PATCH 8/12 mm: fixup possible deadlock

In reply to [email protected]

When the threshol is in the order of the per cpu inaccuracies we can deadlock by not receiveing the updated count, introduce a more expensive but more accurate stat read function to use on low thresholds.

(TODO: roll into the bdi_stat patch)

---
 include/linux/backing-dev.h |   13 ++++++++++++-
 mm/backing-dev.c            |   31 +++++++++++++++++++++++++------
 mm/page-writeback.c         |   19 +++++++++++++++----
 3 files changed, 52 insertions(+), 11 deletions(-)
include/linux/backing-dev.h +12 -1
Index: linux-2.6/include/linux/backing-dev.h
===================================================================
@@ -8,6 +8,7 @@
 #ifndef _LINUX_BACKING_DEV_H
 #define _LINUX_BACKING_DEV_H
 
+#include <linux/cpumask.h>
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
@@ -34,7 +35,6 @@ enum bdi_stat_item {
 
 #ifdef CONFIG_SMP
 struct bdi_per_cpu_data {
-	s8 stat_threshold;
 	s8 bdi_stat_diff[NR_BDI_STAT_ITEMS];
 } ____cacheline_aligned_in_smp;
 #endif
@@ -60,6 +60,7 @@ struct backing_dev_info {
 
 	atomic_long_t bdi_stats[NR_BDI_STAT_ITEMS];
 #ifdef CONFIG_SMP
+	int stat_threshold;
 	struct bdi_per_cpu_data pcd[NR_CPUS];
 #endif
 };
@@ -109,6 +110,8 @@ static inline unsigned long bdi_stat(str
 }
 
 #ifdef CONFIG_SMP
+unsigned long bdi_stat_accurate(struct backing_dev_info *bdi, enum bdi_stat_item item);
+
 void __mod_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item, int delta);
 void __inc_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item);
 void __dec_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item);
@@ -117,8 +120,14 @@ void mod_bdi_stat(struct backing_dev_inf
 void inc_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item);
 void dec_bdi_stat(struct backing_dev_info *bdi, enum bdi_stat_item item);
 
+static inline unsigned long bdi_stat_delta(struct backing_dev_info *bdi)
+{
+	return num_online_cpus() * bdi->stat_threshold;
+}
 #else /* CONFIG_SMP */
 
+#define bdi_stat_accurate bdi_stat
+
 static inline void __mod_bdi_stat(struct backing_dev_info *bdi,
 		enum bdi_stat_item item, int delta)
 {
@@ -142,6 +151,8 @@ static inline void __dec_bdi_stat(struct
 #define mod_bdi_stat __mod_bdi_stat
 #define inc_bdi_stat __inc_bdi_stat
 #define dec_bdi_stat __dec_bdi_stat
+
+#define bdi_stat_delta(bdi) 1UL
 #endif
 
 void bdi_init(struct backing_dev_info *bdi);
mm/backing-dev.c +25 -6
Index: linux-2.6/mm/backing-dev.c
===================================================================
@@ -98,17 +98,36 @@ void bdi_init(struct backing_dev_in
 		atomic_long_set(&bdi->bdi_stats[i], 0);
 
 #ifdef CONFIG_SMP
+	bdi->stat_threshold = 8 * ilog2(num_online_cpus());
 	for (i = 0; i < NR_CPUS; i++) {
 		int j;
 		for (j = 0; j < NR_BDI_STAT_ITEMS; j++)
 			bdi->pcd[i].bdi_stat_diff[j] = 0;
-		bdi->pcd[i].stat_threshold = 8 * ilog2(num_online_cpus());
 	}
 #endif
 }
 EXPORT_SYMBOL(bdi_init);
 
 #ifdef CONFIG_SMP
+unsigned long bdi_stat_accurate(struct backing_dev_info *bdi,
+		enum bdi_stat_item item)
+{
+	long x = atomic_long_read(&bdi_stats[item]);
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct bdi_per_cpu_data *pcd = &bdi->pcd[cpu];
+		s8 *p = pcd->bdi_stat_diff + item;
+
+		x += *p;
+	}
+
+	if (x < 0)
+		x = 0;
+
+	return x;
+}
+
 void __mod_bdi_stat(struct backing_dev_info *bdi,
 		enum bdi_stat_item item, int delta)
 {
@@ -118,7 +137,7 @@ void __mod_bdi_stat(struct backing_dev_i
 
 	x = delta + *p;
 
-	if (unlikely(x > pcd->stat_threshold || x < -pcd->stat_threshold)) {
+	if (unlikely(x > bdi->stat_threshold || x < -bdi->stat_threshold)) {
 		bdi_stat_add(x, bdi, item);
 		x = 0;
 	}
@@ -144,8 +163,8 @@ void __inc_bdi_stat(struct backing_dev_i
 
 	(*p)++;
 
-	if (unlikely(*p > pcd->stat_threshold)) {
-		int overstep = pcd->stat_threshold / 2;
+	if (unlikely(*p > bdi->stat_threshold)) {
+		int overstep = bdi->stat_threshold / 2;
 
 		bdi_stat_add(*p + overstep, bdi, item);
 		*p = -overstep;
@@ -170,8 +189,8 @@ void __dec_bdi_stat(struct backing_dev_i
 
 	(*p)--;
 
-	if (unlikely(*p < -pcd->stat_threshold)) {
-		int overstep = pcd->stat_threshold / 2;
+	if (unlikely(*p < -bdi->stat_threshold)) {
+		int overstep = bdi->stat_threshold / 2;
 
 		bdi_stat_add(*p - overstep, bdi, item);
 		*p = overstep;
mm/page-writeback.c +15 -4
Index: linux-2.6/mm/page-writeback.c
===================================================================
@@ -341,14 +341,25 @@ static void balance_dirty_pages(struct a
 		 * been flushed to permanent storage.
 		 */
 		if (bdi_nr_reclaimable) {
+			unsigned long bdi_nr_writeback;
 			writeback_inodes(&wbc);
 
 			get_dirty_limits(&background_thresh, &dirty_thresh,
 				       &bdi_thresh, bdi);
-			bdi_nr_reclaimable = bdi_stat(bdi, BDI_DIRTY) +
-						bdi_stat(bdi, BDI_UNSTABLE);
-			if (bdi_nr_reclaimable + bdi_stat(bdi, BDI_WRITEBACK) <=
-			     	bdi_thresh)
+
+			if (bdi_thresh < bdi_stat_delta(bdi)) {
+				bdi_nr_reclaimable =
+					bdi_stat_accurate(bdi, BDI_DIRTY) +
+					bdi_stat_accurate(bdi, BDI_UNSTABLE);
+				bdi_nr_writeback =
+					bdi_stat_accurate(bdi, NR_WRITEBACK);
+			} else {
+				bdi_nr_reclaimable = bdi_stat(bdi, BDI_DIRTY) +
+					bdi_stat(bdi, BDI_UNSTABLE);
+				bdi_nr_writeback = bdi_stat(bdi, NR_WRITEBACK);
+			}
+
+			if (bdi_nr_reclaimable + bdi_nr_writeback <= bdi_thresh)
 				break;
 
 			pages_written += write_chunk - wbc.nr_to_write;

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#11 lore raw

Re: [PATCH 08/12] mm: fixup possible deadlock

Quoted 2 lines · On Thu, 05 Apr 2007 19:42:17 +0200 [email protected] wrote:

When the threshol is in the order of the per cpu inaccuracies we can deadlock by not receiveing the updated count,

That explanation is a bit, umm, terse.

Quoted 2 lines

introduce a more expensive
but more accurate stat read function to use on low thresholds.

Looks like percpu_counter_sum().

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#12 lore raw

PATCH 9/12 mm: remove throttle_vm_writeback

In reply to [email protected]

rely on accurate dirty page accounting to provide enough push back

---

include/linux/writeback.h +0 -1
Index: linux-2.6-mm/include/linux/writeback.h
===================================================================
@@ -84,7 +84,6 @@ static inline void wait_on_inode(struct 
 int wakeup_pdflush(long nr_pages);
 void laptop_io_completion(void);
 void laptop_sync_completion(void);
-void throttle_vm_writeout(gfp_t gfp_mask);
 
 extern struct timer_list laptop_mode_wb_timer;
 static inline int laptop_spinned_down(void)
mm/page-writeback.c +0 -31
Index: linux-2.6-mm/mm/page-writeback.c
===================================================================
@@ -437,37 +437,6 @@ void balance_dirty_pages_ratelimited_nr(
 }
 EXPORT_SYMBOL(balance_dirty_pages_ratelimited_nr);
 
-void throttle_vm_writeout(gfp_t gfp_mask)
-{
-	long background_thresh;
-	long dirty_thresh;
-
-	if ((gfp_mask & (__GFP_FS|__GFP_IO)) != (__GFP_FS|__GFP_IO)) {
-		/*
-		 * The caller might hold locks which can prevent IO completion
-		 * or progress in the filesystem.  So we cannot just sit here
-		 * waiting for IO to complete.
-		 */
-		congestion_wait(WRITE, HZ/10);
-		return;
-	}
-
-        for ( ; ; ) {
-		get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);
-
-                /*
-                 * Boost the allowable dirty threshold a bit for page
-                 * allocators so they don't get DoS'ed by heavy writers
-                 */
-                dirty_thresh += dirty_thresh / 10;      /* wheeee... */
-
-                if (global_page_state(NR_UNSTABLE_NFS) +
-			global_page_state(NR_WRITEBACK) <= dirty_thresh)
-                        	break;
-                congestion_wait(WRITE, HZ/10);
-        }
-}
-
 /*
  * writeback at least _min_pages, and keep writing until the amount of dirty
  * memory is less than the background threshold, or until we're all clean.
mm/vmscan.c +0 -2
Index: linux-2.6-mm/mm/vmscan.c
===================================================================
@@ -1047,8 +1047,6 @@ static unsigned long shrink_zone(int pri
 		}
 	}
 
-	throttle_vm_writeout(sc->gfp_mask);
-
 	atomic_dec(&zone->reclaim_in_progress);
 	return nr_reclaimed;
 }

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#13 lore raw

Re: [PATCH 09/12] mm: remove throttle_vm_writeback

Quoted 1 line · On Thu, 05 Apr 2007 19:42:18 +0200 [email protected] wrote:

rely on accurate dirty page accounting to provide enough push back

I think we'd like to see a bit more justification than that, please.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#14 lore raw

Re: [PATCH 09/12] mm: remove throttle_vm_writeback

Quoted 6 lines · Andrew Morton
Quoted 1 line · On Thu, 05 Apr 2007 19:42:18 +0200 [email protected] wrote:

rely on accurate dirty page accounting to provide enough push back

I think we'd like to see a bit more justification than that, please.

it should read like this:

        for ( ; ; ) {
		get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);

                /*
                 * Boost the allowable dirty threshold a bit for page
                 * allocators so they don't get DoS'ed by heavy writers
                 */
                dirty_thresh += dirty_thresh / 10;      /* wheeee... */

                if (global_page_state(NR_FILE_DIRTY) + 
		    global_page_state(NR_UNSTABLE_NFS) +
		    global_page_state(NR_WRITEBACK) <= dirty_thresh)
                        	break;

                congestion_wait(WRITE, HZ/10);
        }

[ note the extra NR_FILE_DIRTY ]

now, balance_dirty_pages() is there to ensure:

nr_dirty + nr_unstable + nr_writeback < dirty_thresh (1)

reclaim will (with the introduction of dirty page tracking) never generate dirty pages, so the only disturbance of that equation is an increase in nr_writeback.

[ pageout() sets wbc.for_reclaim=1, so NFS traffic will not generate
unstable pages ]

So, what throttle_vm_writeout() does is limit the number of added writeback pages to 10% of the total limit.

pageout() seems to avoid stuffing pages down a congested bdi (TODO: has details), along with the much smaller io-queues, the initial purpose of this function - which was to avoid all memory getting stuck in io-queues - seems to be handled.

Now the problems...

Trouble is that it currently does not take nr_dirty into account which in the worst case limits it to 110% of the limit.

Also, I'm seeing (2.6.23-rc8-mm1) live-locks in throttle_vm_writeback() where nr_dirty + nr_unstable > thresh - which according to (1) should not happen, and will not change without explicit action.

Hmm maybe the 10% is < nr_cpus * ratelimit_pages.

2 cpus, mem=128M -> ratelimit_pages ~ 512
threshold ~ 1500

so indeed: 150 < 1024.

Still not conclusive but at least getting somewhere.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#15 lore raw

PATCH 10/12 mm: page_alloc_wait

In reply to [email protected]

Introduce a mechanism to wait on free memory.

Currently congestion_wait() is abused to do this.

---
 arch/i386/lib/usercopy.c |    2 +-
 fs/xfs/linux-2.6/kmem.c  |    4 ++--
 include/linux/mm.h       |    3 +++
 mm/page_alloc.c          |   25 +++++++++++++++++++++++--
 mm/shmem.c               |    2 +-
 mm/vmscan.c              |    1 +
 6 files changed, 31 insertions(+), 6 deletions(-)
arch/i386/lib/usercopy.c +1 -1
Index: linux-2.6-mm/arch/i386/lib/usercopy.c
===================================================================
@@ -751,7 +751,7 @@ survive:
 
 			if (retval == -ENOMEM && is_init(current)) {
 				up_read(&current->mm->mmap_sem);
-				congestion_wait(WRITE, HZ/50);
+				page_alloc_wait(HZ/50);
 				goto survive;
 			}
 
fs/xfs/linux-2.6/kmem.c +2 -2
Index: linux-2.6-mm/fs/xfs/linux-2.6/kmem.c
===================================================================
@@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __n
 			printk(KERN_ERR "XFS: possible memory allocation "
 					"deadlock in %s (mode:0x%x)\n",
 					__FUNCTION__, lflags);
-		congestion_wait(WRITE, HZ/50);
+		page_alloc_wait(HZ/50);
 	} while (1);
 }
 
@@ -131,7 +131,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsig
 			printk(KERN_ERR "XFS: possible memory allocation "
 					"deadlock in %s (mode:0x%x)\n",
 					__FUNCTION__, lflags);
-		congestion_wait(WRITE, HZ/50);
+		page_alloc_wait(HZ/50);
 	} while (1);
 }
 
include/linux/mm.h +3 -0
Index: linux-2.6-mm/include/linux/mm.h
===================================================================
@@ -1028,6 +1028,9 @@ extern void setup_per_cpu_pageset(void);
 static inline void setup_per_cpu_pageset(void) {}
 #endif
 
+void page_alloc_ok(void);
+long page_alloc_wait(long timeout);
+
 /* prio_tree.c */
 void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old);
 void vma_prio_tree_insert(struct vm_area_struct *, struct prio_tree_root *);
mm/page_alloc.c +23 -2
Index: linux-2.6-mm/mm/page_alloc.c
===================================================================
@@ -107,6 +107,9 @@ unsigned long __meminitdata nr_kernel_pa
 unsigned long __meminitdata nr_all_pages;
 static unsigned long __initdata dma_reserve;
 
+static wait_queue_head_t page_alloc_wqh =
+	__WAIT_QUEUE_HEAD_INITIALIZER(page_alloc_wqh);
+
 #ifdef CONFIG_ARCH_POPULATES_NODE_MAP
   /*
    * MAX_ACTIVE_REGIONS determines the maxmimum number of distinct
@@ -1698,7 +1701,7 @@ nofail_alloc:
 			if (page)
 				goto got_pg;
 			if (gfp_mask & __GFP_NOFAIL) {
-				congestion_wait(WRITE, HZ/50);
+				page_alloc_wait(HZ/50);
 				goto nofail_alloc;
 			}
 		}
@@ -1763,7 +1766,7 @@ nofail_alloc:
 			do_retry = 1;
 	}
 	if (do_retry) {
-		congestion_wait(WRITE, HZ/50);
+		page_alloc_wait(HZ/50);
 		goto rebalance;
 	}
 
@@ -4217,3 +4220,21 @@ void set_pageblock_flags_group(struct pa
 		else
 			__clear_bit(bitidx + start_bitidx, bitmap);
 }
+
+void page_alloc_ok(void)
+{
+	if (waitqueue_active(&page_alloc_wqh))
+		wake_up(&page_alloc_wqh);
+}
+
+long page_alloc_wait(long timeout)
+{
+	long ret;
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait(&page_alloc_wqh, &wait, TASK_UNINTERRUPTIBLE);
+	ret = schedule_timeout(timeout);
+	finish_wait(&page_alloc_wqh, &wait);
+	return ret;
+}
+EXPORT_SYMBOL(page_alloc_wait);
mm/shmem.c +1 -1
Index: linux-2.6-mm/mm/shmem.c
===================================================================
@@ -1216,7 +1216,7 @@ repeat:
 			page_cache_release(swappage);
 			if (error == -ENOMEM) {
 				/* let kswapd refresh zone for GFP_ATOMICs */
-				congestion_wait(WRITE, HZ/50);
+				page_alloc_wait(HZ/50);
 			}
 			goto repeat;
 		}
mm/vmscan.c +1 -0
Index: linux-2.6-mm/mm/vmscan.c
===================================================================
@@ -1436,6 +1436,7 @@ static int kswapd(void *p)
 		finish_wait(&pgdat->kswapd_wait, &wait);
 
 		balance_pgdat(pgdat, order);
+		page_alloc_ok();
 	}
 	return 0;
 }

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#16 lore raw

Re: [PATCH 10/12] mm: page_alloc_wait

Quoted 3 lines · On Thu, 05 Apr 2007 19:42:19 +0200 [email protected] wrote:

Introduce a mechanism to wait on free memory.

Currently congestion_wait() is abused to do this.

Such a very small explanation for such a terrifying change.

mm/vmscan.c static int kswapd(void *p) · line 1442

Quoted 12 lines

...

mm/vmscan.c +1 -0
@@ -1436,6 +1436,7 @@ static int kswapd(void *p)
 		finish_wait(&pgdat->kswapd_wait, &wait);
 
 		balance_pgdat(pgdat, order);
+		page_alloc_ok();
 	}
 	return 0;
 }

For a start, we don't know that kswapd freed pages which are in a suitable zone. And we don't know that kswapd freed pages which are in a suitable cpuset.

congestion_wait() is similarly ignorant of the suitability of the pages, but the whole idea behind congestion_wait is that it will throttle page allocators to some speed which is proportional to the speed at which the IO systems can retire writes - view it as a variable-speed polling operation, in which the polling frequency goes up when the IO system gets faster. This patch changes that philosophy fundamentally. That's worth more than a 2-line changelog.

Also, there might be situations in which kswapd gets stuck in some dark corner. Perhaps the process which is waiting in the page allocator holds filesystem locks which kswapd is blocked on. Or kswapd might be blocked on a particular request queue, or a dead NFS server or something. The timeout will save us, but things will be slow.

There could be other problems too, dunno - this stuff is tricky. Why are you changing it, what problems are being solved, etc?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw

Re: [PATCH 10/12] mm: page_alloc_wait

Quoted 8 lines · Andrew Morton
Quoted 3 lines · On Thu, 05 Apr 2007 19:42:19 +0200 [email protected] wrote:

Introduce a mechanism to wait on free memory.

Currently congestion_wait() is abused to do this.

Such a very small explanation for such a terrifying change.

Yes, I suck at writing changelogs, bad me. Normally I would take a day to write them, but I just wanted to get this code out there. Perhaps a bad decision.

Quoted 25 lines

mm/vmscan.c static int kswapd(void *p) · line 1442

Quoted 12 lines

...

mm/vmscan.c +1 -0
@@ -1436,6 +1436,7 @@ static int kswapd(void *p)
 		finish_wait(&pgdat->kswapd_wait, &wait);
 
 		balance_pgdat(pgdat, order);
+		page_alloc_ok();
 	}
 	return 0;
 }

For a start, we don't know that kswapd freed pages which are in a suitable zone. And we don't know that kswapd freed pages which are in a suitable cpuset.

congestion_wait() is similarly ignorant of the suitability of the pages, but the whole idea behind congestion_wait is that it will throttle page allocators to some speed which is proportional to the speed at which the IO systems can retire writes - view it as a variable-speed polling operation, in which the polling frequency goes up when the IO system gets faster. This patch changes that philosophy fundamentally. That's worth more than a 2-line changelog.

Quoted 8 lines

Also, there might be situations in which kswapd gets stuck in some dark corner. Perhaps the process which is waiting in the page allocator holds filesystem locks which kswapd is blocked on. Or kswapd might be blocked on a particular request queue, or a dead NFS server or something. The timeout will save us, but things will be slow.

There could be other problems too, dunno - this stuff is tricky. Why are you changing it, what problems are being solved, etc?

Lets start with the why, because of 12/12; I wanted to introduce per BDI congestion feedback, and hence needed a BDI context for congestion_wait(). These specific callers weren't in the context of a BDI but of a more global idea.

Perhaps I could call page_alloc_ok() from bdi_congestion_end() irrespective of the actual BDI uncongested? That would more or less give the old semantics.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#18 lore raw

PATCH 11/12 mm: accurate pageout congestion wait

In reply to [email protected]

Only do the congestion wait when we actually encountered congestion.

---

 include/linux/swap.h |    1 +
 mm/page_io.c         |    9 +++++++++
 mm/vmscan.c          |   25 ++++++++++++++++++++-----
 3 files changed, 30 insertions(+), 5 deletions(-)
mm/vmscan.c +20 -5
Index: linux-2.6-mm/mm/vmscan.c
===================================================================
@@ -70,6 +70,8 @@ struct scan_control {
 	int all_unreclaimable;
 
 	int order;
+
+	int encountered_congestion;
 };
 
 /*
@@ -315,7 +317,8 @@ typedef enum {
  * pageout is called by shrink_page_list() for each dirty page.
  * Calls ->writepage().
  */
-static pageout_t pageout(struct page *page, struct address_space *mapping)
+static pageout_t pageout(struct page *page, struct address_space *mapping,
+		struct scan_control *sc)
 {
 	/*
 	 * If the page is dirty, only perform writeback if that write
@@ -357,6 +360,7 @@ static pageout_t pageout(struct page *pa
 
 	if (clear_page_dirty_for_io(page)) {
 		int res;
+		struct backing_dev_info *bdi;
 		struct writeback_control wbc = {
 			.sync_mode = WB_SYNC_NONE,
 			.nr_to_write = SWAP_CLUSTER_MAX,
@@ -366,6 +370,14 @@ static pageout_t pageout(struct page *pa
 			.for_reclaim = 1,
 		};
 
+		if (mapping == &swapper_space)
+			bdi = swap_bdi(page);
+		else
+			bdi = mapping->backing_dev_info;
+
+		if (bdi_congested(bdi, WRITE))
+			sc->encountered_congestion = 1;
+
 		SetPageReclaim(page);
 		res = mapping->a_ops->writepage(page, &wbc);
 		if (res < 0)
@@ -533,7 +545,7 @@ static unsigned long shrink_page_list(st
 				goto keep_locked;
 
 			/* Page is dirty, try to write it out here */
-			switch(pageout(page, mapping)) {
+			switch(pageout(page, mapping, sc)) {
 			case PAGE_KEEP:
 				goto keep_locked;
 			case PAGE_ACTIVATE:
@@ -1141,6 +1153,7 @@ unsigned long try_to_free_pages(struct z
 
 	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
 		sc.nr_scanned = 0;
+		sc.encountered_congestion = 0;
 		if (!priority)
 			disable_swap_token();
 		nr_reclaimed += shrink_zones(priority, zones, &sc);
@@ -1169,7 +1182,7 @@ unsigned long try_to_free_pages(struct z
 		}
 
 		/* Take a nap, wait for some writeback to complete */
-		if (sc.nr_scanned && priority < DEF_PRIORITY - 2)
+		if (sc.encountered_congestion)
 			congestion_wait(WRITE, HZ/10);
 	}
 	/* top priority shrink_caches still had more to do? don't OOM, then */
@@ -1250,6 +1263,7 @@ loop_again:
 		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
 		unsigned long lru_pages = 0;
 
+		sc.encountered_congestion = 0;
 		/* The swap token gets in the way of swapout... */
 		if (!priority)
 			disable_swap_token();
@@ -1337,7 +1351,7 @@ loop_again:
 		 * OK, kswapd is getting into trouble.  Take a nap, then take
 		 * another pass across the zones.
 		 */
-		if (total_scanned && priority < DEF_PRIORITY - 2)
+		if (sc.encountered_congestion)
 			congestion_wait(WRITE, HZ/10);
 
 		/*
@@ -1580,6 +1594,7 @@ unsigned long shrink_all_memory(unsigned
 			unsigned long nr_to_scan = nr_pages - ret;
 
 			sc.nr_scanned = 0;
+			sc.encountered_congestion = 0;
 			ret += shrink_all_zones(nr_to_scan, prio, pass, &sc);
 			if (ret >= nr_pages)
 				goto out;
@@ -1591,7 +1606,7 @@ unsigned long shrink_all_memory(unsigned
 			if (ret >= nr_pages)
 				goto out;
 
-			if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
+			if (sc.encountered_congestion)
 				congestion_wait(WRITE, HZ / 10);
 		}
 	}
include/linux/swap.h +1 -0
Index: linux-2.6-mm/include/linux/swap.h
===================================================================
@@ -220,6 +220,7 @@ extern void swap_unplug_io_fn(struct bac
 
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
+extern struct backing_dev_info *swap_bdi(struct page *);
 extern int swap_readpage(struct file *, struct page *);
 extern int swap_writepage(struct page *page, struct writeback_control *wbc);
 extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err);
mm/page_io.c +9 -0
Index: linux-2.6-mm/mm/page_io.c
===================================================================
@@ -19,6 +19,15 @@
 #include <linux/writeback.h>
 #include <asm/pgtable.h>
 
+struct backing_dev_info *swap_bdi(struct page *page)
+{
+	struct swap_info_struct *sis;
+	swp_entry_t entry = { .val = page_private(page), };
+
+	sis = get_swap_info_struct(swp_type(entry));
+	return blk_get_backing_dev_info(sis->bdev);
+}
+
 static struct bio *get_swap_bio(gfp_t gfp_flags, pgoff_t index,
 				struct page *page, bio_end_io_t end_io)
 {

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#19 lore raw

Re: [PATCH 11/12] mm: accurate pageout congestion wait

Quoted 1 line · On Thu, 05 Apr 2007 19:42:20 +0200 [email protected] wrote:

Only do the congestion wait when we actually encountered congestion.

The name congestion_wait() was accurate back in 2002, but it isn't accurate any more, and you got misled. It does not only wait for a queue to become uncongested.

See clear_bdi_congested()'s callers. As long as the queue is in an uncongested state, we deliver wakeups to congestion_wait() blockers on every IO completion. As I said before, it is so that the MM's polling operations poll at a higher frequency when the IO system is working faster. (It is also to synchronise with end_page_writeback()'s feeding of clean pages to us via rotate_reclaimable_page()).

Page reclaim can get into trouble without any request queue having entered a congested state. For example, think about a machine which has a single disk, and the operator has increased that disk's request queue size to 100,000. With your patch all the VM's throttling would be bypassed and we go into a busy loop and declare OOM instantly.

There are probably other situations in which page reclaim gets into trouble without a request queue being congested.

Minor point: bdi_congested() can be arbitrarily expensive - for DM stackups it is roughly proportional to the number of subdevices in the device. We need to be careful about how frequently we call it.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#20 lore raw

Re: [PATCH 11/12] mm: accurate pageout congestion wait

Quoted 8 lines · Andrew Morton
Quoted 1 line · On Thu, 05 Apr 2007 19:42:20 +0200 [email protected] wrote:

Only do the congestion wait when we actually encountered congestion.

The name congestion_wait() was accurate back in 2002, but it isn't accurate any more, and you got misled. It does not only wait for a queue to become uncongested.

Quite so indeed.

Quoted 6 lines

See clear_bdi_congested()'s callers. As long as the queue is in an uncongested state, we deliver wakeups to congestion_wait() blockers on every IO completion. As I said before, it is so that the MM's polling operations poll at a higher frequency when the IO system is working faster. (It is also to synchronise with end_page_writeback()'s feeding of clean pages to us via rotate_reclaimable_page()).

Hmm, but the condition under which we did call congestion_wait() is a bit magical.

Quoted 8 lines

Page reclaim can get into trouble without any request queue having entered a congested state. For example, think about a machine which has a single disk, and the operator has increased that disk's request queue size to 100,000. With your patch all the VM's throttling would be bypassed and we go into a busy loop and declare OOM instantly.

There are probably other situations in which page reclaim gets into trouble without a request queue being congested.

Ok, in the light of allt his, I will think on this some more.

Quoted 3 lines

Minor point: bdi_congested() can be arbitrarily expensive - for DM stackups it is roughly proportional to the number of subdevices in the device. We need to be careful about how frequently we call it.

Yuck, ok, good point.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#21 lore raw

PATCH 12/12 mm: per BDI congestion feedback

In reply to [email protected]

Now that we have per BDI dirty throttling is makes sense to also have oer BDI congestion feedback; why wait on another device if the current one is not congested.

---
 drivers/block/pktcdvd.c     |    2 -
 drivers/md/dm-crypt.c       |    7 +++--
 fs/cifs/file.c              |    2 -
 fs/ext4/writeback.c         |    2 -
 fs/fat/file.c               |    4 ++
 fs/fs-writeback.c           |    2 -
 fs/nfs/write.c              |    2 -
 fs/reiser4/vfs_ops.c        |    2 -
 fs/reiserfs/journal.c       |    7 +++--
 fs/xfs/linux-2.6/xfs_aops.c |    2 -
 include/linux/backing-dev.h |    7 +++--
 include/linux/writeback.h   |    3 +-
 mm/backing-dev.c            |   61 ++++++++++++++++++++++++++++----------------
 mm/page-writeback.c         |   19 +++++++------
 mm/vmscan.c                 |   19 +++++++------
 15 files changed, 88 insertions(+), 53 deletions(-)
include/linux/backing-dev.h +5 -2
Index: linux-2.6-mm/include/linux/backing-dev.h
===================================================================
@@ -10,6 +10,7 @@
 
 #include <linux/cpumask.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <asm/atomic.h>
 
 struct page;
@@ -52,6 +53,8 @@ struct backing_dev_info {
 	void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
 	void *unplug_io_data;
 
+	wait_queue_head_t congestion_wqh[2];
+
 	/*
 	 * data used for scaling the writeback cache
 	 */
@@ -214,8 +217,8 @@ static inline int bdi_rw_congested(struc
 
 void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
 void set_bdi_congested(struct backing_dev_info *bdi, int rw);
-long congestion_wait(int rw, long timeout);
-long congestion_wait_interruptible(int rw, long timeout);
+long congestion_wait(struct backing_dev_info *bdi, int rw, long timeout);
+long congestion_wait_interruptible(struct backing_dev_info *bdi, int rw, long timeout);
 
 #define bdi_cap_writeback_dirty(bdi) \
 	(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
mm/backing-dev.c +39 -22

95 lines not on this page · raw message

mm/page-writeback.c +11 -8
Index: linux-2.6-mm/mm/page-writeback.c
===================================================================
@@ -366,7 +366,7 @@ static void balance_dirty_pages(struct a
 			if (pages_written >= write_chunk)
 				break;		/* We've done our duty */
 		}
-		congestion_wait(WRITE, HZ/10);
+		congestion_wait(bdi, WRITE, HZ/10);
 	}
 
 	if (writeback_in_progress(bdi))
@@ -462,15 +462,17 @@ static void background_writeout(unsigned
 			global_page_state(NR_UNSTABLE_NFS) < background_thresh
 				&& min_pages <= 0)
 			break;
-		wbc.encountered_congestion = 0;
+		wbc.encountered_congestion = NULL;
 		wbc.nr_to_write = MAX_WRITEBACK_PAGES;
 		wbc.pages_skipped = 0;
 		writeback_inodes(&wbc);
 		min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
 		if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
 			/* Wrote less than expected */
-			congestion_wait(WRITE, HZ/10);
-			if (!wbc.encountered_congestion)
+			if (wbc.encountered_congestion)
+				congestion_wait(wbc.encountered_congestion,
+						WRITE, HZ/10);
+			else
 				break;
 		}
 	}
@@ -535,12 +537,13 @@ static void wb_kupdate(unsigned long arg
 			global_page_state(NR_UNSTABLE_NFS) +
 			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
 	while (nr_to_write > 0) {
-		wbc.encountered_congestion = 0;
+		wbc.encountered_congestion = NULL;
 		wbc.nr_to_write = MAX_WRITEBACK_PAGES;
 		writeback_inodes(&wbc);
 		if (wbc.nr_to_write > 0) {
 			if (wbc.encountered_congestion)
-				congestion_wait(WRITE, HZ/10);
+				congestion_wait(wbc.encountered_congestion,
+					       	WRITE, HZ/10);
 			else
 				break;	/* All the old data is written */
 		}
@@ -698,7 +701,7 @@ int write_cache_pages(struct address_spa
 	int range_whole = 0;
 
 	if (wbc->nonblocking && bdi_write_congested(bdi)) {
-		wbc->encountered_congestion = 1;
+		wbc->encountered_congestion = bdi;
 		return 0;
 	}
 
@@ -760,7 +763,7 @@ retry:
 			if (ret || (--(wbc->nr_to_write) <= 0))
 				done = 1;
 			if (wbc->nonblocking && bdi_write_congested(bdi)) {
-				wbc->encountered_congestion = 1;
+				wbc->encountered_congestion = bdi;
 				done = 1;
 			}
 		}
drivers/block/pktcdvd.c +1 -1
Index: linux-2.6-mm/drivers/block/pktcdvd.c
===================================================================
@@ -2589,7 +2589,7 @@ static int pkt_make_request(request_queu
 		set_bdi_congested(&q->backing_dev_info, WRITE);
 		do {
 			spin_unlock(&pd->lock);
-			congestion_wait(WRITE, HZ);
+			congestion_wait(&q->backing_dev_info, WRITE, HZ);
 			spin_lock(&pd->lock);
 		} while(pd->bio_queue_size > pd->write_congestion_off);
 	}
drivers/md/dm-crypt.c +5 -2
Index: linux-2.6-mm/drivers/md/dm-crypt.c
===================================================================
@@ -640,8 +640,11 @@ static void process_write(struct crypt_i
 		 * may be gone already. */
 
 		/* out of memory -> run queues */
-		if (remaining)
-			congestion_wait(WRITE, HZ/100);
+		if (remaining) {
+			struct backing_dev_info *bdi =
+				&io->target->table->md->queue->backing_dev_info;
+			congestion_wait(bdi, WRITE, HZ/100);
+		}
 	}
 }
 
fs/fat/file.c +3 -1
Index: linux-2.6-mm/fs/fat/file.c
===================================================================
@@ -118,8 +118,10 @@ static int fat_file_release(struct inode
 {
 	if ((filp->f_mode & FMODE_WRITE) &&
 	     MSDOS_SB(inode->i_sb)->options.flush) {
+		struct backing_dev_info *bdi =
+			inode->i_mapping->backing_dev_info;
 		fat_flush_inodes(inode->i_sb, inode, NULL);
-		congestion_wait(WRITE, HZ/10);
+		congestion_wait(bdi, WRITE, HZ/10);
 	}
 	return 0;
 }
fs/reiserfs/journal.c +5 -2
Index: linux-2.6-mm/fs/reiserfs/journal.c
===================================================================
@@ -970,8 +970,11 @@ int reiserfs_async_progress_wait(struct 
 {
 	DEFINE_WAIT(wait);
 	struct reiserfs_journal *j = SB_JOURNAL(s);
-	if (atomic_read(&j->j_async_throttle))
-		congestion_wait(WRITE, HZ / 10);
+	if (atomic_read(&j->j_async_throttle)) {
+		struct backing_dev_info *bdi =
+			blk_get_backing_dev_info(j->j_dev_bd);
+		congestion_wait(bdi, WRITE, HZ / 10);
+	}
 	return 0;
 }
 
include/linux/writeback.h +2 -1
Index: linux-2.6-mm/include/linux/writeback.h
===================================================================
@@ -54,11 +54,12 @@ struct writeback_control {
 	loff_t range_end;
 
 	unsigned nonblocking:1;		/* Don't get stuck on request queues */
-	unsigned encountered_congestion:1; /* An output: a queue is full */
 	unsigned for_kupdate:1;		/* A kupdate writeback */
 	unsigned for_reclaim:1;		/* Invoked from the page allocator */
 	unsigned for_writepages:1;	/* This is a writepages() call */
 	unsigned range_cyclic:1;	/* range_start is cyclic */
+
+	struct backing_dev_info *encountered_congestion; /* An output: a queue is full */
 };
 
 /*
fs/cifs/file.c +1 -1
Index: linux-2.6-mm/fs/cifs/file.c
===================================================================
@@ -1143,7 +1143,7 @@ static int cifs_writepages(struct addres
 	 * If it is, we should test it again after we do I/O
 	 */
 	if (wbc->nonblocking && bdi_write_congested(bdi)) {
-		wbc->encountered_congestion = 1;
+		wbc->encountered_congestion = bdi;
 		kfree(iov);
 		return 0;
 	}
fs/ext4/writeback.c +1 -1
Index: linux-2.6-mm/fs/ext4/writeback.c
===================================================================
@@ -782,7 +782,7 @@ int ext4_wb_writepages(struct address_sp
 #ifdef EXT4_WB_STATS
 				atomic_inc(&EXT4_SB(inode->i_sb)->s_wb_congested);
 #endif
-				wbc->encountered_congestion = 1;
+				wbc->encountered_congestion = bdi;
 				done = 1;
 			}
 		}
fs/fs-writeback.c +1 -1
Index: linux-2.6-mm/fs/fs-writeback.c
===================================================================
@@ -349,7 +349,7 @@ int generic_sync_sb_inodes(struct super_
 		}
 
 		if (wbc->nonblocking && bdi_write_congested(bdi)) {
-			wbc->encountered_congestion = 1;
+			wbc->encountered_congestion = bdi;
 			if (!sb_is_blkdev_sb(sb))
 				break;		/* Skip a congested fs */
 			list_move(&inode->i_list, &sb->s_dirty);
fs/reiser4/vfs_ops.c +1 -1
Index: linux-2.6-mm/fs/reiser4/vfs_ops.c
===================================================================
@@ -169,7 +169,7 @@ void reiser4_writeout(struct super_block
 		if (wbc->nonblocking &&
 		    bdi_write_congested(mapping->backing_dev_info)) {
 			blk_run_address_space(mapping);
-			wbc->encountered_congestion = 1;
+			wbc->encountered_congestion = mapping->backing_dev_info;
 			break;
 		}
 		repeats++;
fs/xfs/linux-2.6/xfs_aops.c +1 -1
Index: linux-2.6-mm/fs/xfs/linux-2.6/xfs_aops.c
===================================================================
@@ -777,7 +777,7 @@ xfs_convert_page(
 			bdi = inode->i_mapping->backing_dev_info;
 			wbc->nr_to_write--;
 			if (bdi_write_congested(bdi)) {
-				wbc->encountered_congestion = 1;
+				wbc->encountered_congestion = bdi;
 				done = 1;
 			} else if (wbc->nr_to_write <= 0) {
 				done = 1;
mm/vmscan.c +11 -8
Index: linux-2.6-mm/mm/vmscan.c
===================================================================
@@ -71,7 +71,7 @@ struct scan_control {
 
 	int order;
 
-	int encountered_congestion;
+	struct backing_dev_info *encountered_congestion;
 };
 
 /*
@@ -376,7 +376,7 @@ static pageout_t pageout(struct page *pa
 			bdi = mapping->backing_dev_info;
 
 		if (bdi_congested(bdi, WRITE))
-			sc->encountered_congestion = 1;
+			sc->encountered_congestion = bdi;
 
 		SetPageReclaim(page);
 		res = mapping->a_ops->writepage(page, &wbc);
@@ -1153,7 +1153,7 @@ unsigned long try_to_free_pages(struct z
 
 	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
 		sc.nr_scanned = 0;
-		sc.encountered_congestion = 0;
+		sc.encountered_congestion = NULL;
 		if (!priority)
 			disable_swap_token();
 		nr_reclaimed += shrink_zones(priority, zones, &sc);
@@ -1183,7 +1183,8 @@ unsigned long try_to_free_pages(struct z
 
 		/* Take a nap, wait for some writeback to complete */
 		if (sc.encountered_congestion)
-			congestion_wait(WRITE, HZ/10);
+			congestion_wait(sc.encountered_congestion,
+					WRITE, HZ/10);
 	}
 	/* top priority shrink_caches still had more to do? don't OOM, then */
 	if (!sc.all_unreclaimable)
@@ -1263,7 +1264,7 @@ loop_again:
 		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
 		unsigned long lru_pages = 0;
 
-		sc.encountered_congestion = 0;
+		sc.encountered_congestion = NULL;
 		/* The swap token gets in the way of swapout... */
 		if (!priority)
 			disable_swap_token();
@@ -1352,7 +1353,8 @@ loop_again:
 		 * another pass across the zones.
 		 */
 		if (sc.encountered_congestion)
-			congestion_wait(WRITE, HZ/10);
+			congestion_wait(sc.encountered_congestion,
+					WRITE, HZ/10);
 
 		/*
 		 * We do this so kswapd doesn't build up large priorities for
@@ -1594,7 +1596,7 @@ unsigned long shrink_all_memory(unsigned
 			unsigned long nr_to_scan = nr_pages - ret;
 
 			sc.nr_scanned = 0;
-			sc.encountered_congestion = 0;
+			sc.encountered_congestion = NULL;
 			ret += shrink_all_zones(nr_to_scan, prio, pass, &sc);
 			if (ret >= nr_pages)
 				goto out;
@@ -1607,7 +1609,8 @@ unsigned long shrink_all_memory(unsigned
 				goto out;
 
 			if (sc.encountered_congestion)
-				congestion_wait(WRITE, HZ / 10);
+				congestion_wait(sc.encountered_congestion,
+						WRITE, HZ / 10);
 		}
 	}
 
fs/nfs/write.c +1 -1
Index: linux-2.6-mm/fs/nfs/write.c
===================================================================
@@ -567,7 +567,7 @@ static int nfs_wait_on_write_congestion(
 		sigset_t oldset;
 
 		rpc_clnt_sigmask(clnt, &oldset);
-		ret = congestion_wait_interruptible(WRITE, HZ/10);
+		ret = congestion_wait_interruptible(bdi, WRITE, HZ/10);
 		rpc_clnt_sigunmask(clnt, &oldset);
 		if (ret == -ERESTARTSYS)
 			break;

--

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#22 lore raw

Re: [PATCH 12/12] mm: per BDI congestion feedback

Quoted 3 lines · On Thu, 05 Apr 2007 19:42:21 +0200 [email protected] wrote:

Now that we have per BDI dirty throttling is makes sense to also have oer BDI congestion feedback; why wait on another device if the current one is not congested.

Similar comments apply. congestion_wait() should be called throttle_at_a_rate_proportional_to_the_speed_of_presently_uncongested_queues().

If a process is throttled in the page allocator waiting for pages to become reclaimable, that process absolutely does not care whether those pages were previously dirty against /dev/sda or against /dev/sdb. It wants to be woken up for writeout completion against any queue.

- wbc.encountered_congestion = 0;
+ wbc.encountered_congestion = NULL;
wbc.nr_to_write = MAX_WRITEBACK_PAGES; wbc.pages_skipped = 0; writeback_inodes(&wbc);
min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;

 		if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
	 			/* Wrote less than expected */

- congestion_wait(WRITE, HZ/10);
- if (!wbc.encountered_congestion)
+ if (wbc.encountered_congestion)
+ congestion_wait(wbc.encountered_congestion,
+ WRITE, HZ/10);
+ else

Well that confused me. You'd be needing to rename wbc.encountered_congestion to congested_bdi or something.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#23 lore raw

Re: [PATCH 12/12] mm: per BDI congestion feedback

Quoted 7 lines · Andrew Morton
Quoted 3 lines · On Thu, 05 Apr 2007 19:42:21 +0200 [email protected] wrote:

Now that we have per BDI dirty throttling is makes sense to also have oer BDI congestion feedback; why wait on another device if the current one is not congested.

Quoted 7 lines

Similar comments apply. congestion_wait() should be called throttle_at_a_rate_proportional_to_the_speed_of_presently_uncongested_queues().

If a process is throttled in the page allocator waiting for pages to become reclaimable, that process absolutely does not care whether those pages were previously dirty against /dev/sda or against /dev/sdb. It wants to be woken up for writeout completion against any queue.

OK, so you disagree with Miklos' 2nd point here:
http://lkml.org/lkml/2007/4/4/137

And in the light of clear_bdi_congestion() being called for each writeout completion under the threshold this does make sense.

So this whole 8-12/12 series is not needed and just served as an learning experience :-/

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#24 lore raw

Re: [PATCH 12/12] mm: per BDI congestion feedback

Quoted 11 lines · On Fri, 06 Apr 2007 09:01:57 +0200 Peter Zijlstra <[email protected]>…
Quoted 10 lines · Andrew Morton
Quoted 3 lines · On Thu, 05 Apr 2007 19:42:21 +0200 [email protected] wrote:

Now that we have per BDI dirty throttling is makes sense to also have oer BDI congestion feedback; why wait on another device if the current one is not congested.

Similar comments apply. congestion_wait() should be called throttle_at_a_rate_proportional_to_the_speed_of_presently_uncongested_queues().

Quoted 7 lines
Quoted 4 lines

If a process is throttled in the page allocator waiting for pages to become reclaimable, that process absolutely does not care whether those pages were previously dirty against /dev/sda or against /dev/sdb. It wants to be woken up for writeout completion against any queue.

OK, so you disagree with Miklos' 2nd point here:
http://lkml.org/lkml/2007/4/4/137

Yup, silly man thought that "congestion_wait" has something to do with congestion ;) I think it sort-of used to, once.

Now it really means no more than "block until a batch of writes complete".

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

maintainer
#25 lore raw

Re: [PATCH 12/12] mm: per BDI congestion feedback

Quoted 5 lines
Quoted 2 lines

OK, so you disagree with Miklos' 2nd point here:
http://lkml.org/lkml/2007/4/4/137

Yup, silly man thought that "congestion_wait" has something to do with congestion ;) I think it sort-of used to, once.

Oh well. I _usually_ do actually read the code, but this seemed so obvious... I'll learn never to trust descriptive function names.

Miklos

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#26 lore raw
In reply to [email protected]

Don't worry, it's me!

Seems I forgot to edit the From field :-(

Quoted 5 lines · On Thu, 2007-04-05 at 19:42 +0200, [email protected] wrote:

Against 2.6.21-rc5-mm4 without:
per-backing_dev-dirty-and-writeback-page-accounting.patch

This series implements BDI independent dirty limits and congestion control.

Quoted 9 lines

This should solve several problems we currently have in this area:

- mutual interference starvation (for any number of BDIs), and
- deadlocks with stacked BDIs (loop and FUSE).

All the fancy new congestion code has been compile and boot tested, but not much more. I'm posting to get feedback on the ideas.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>