Skip to content

Commit

Permalink
[PATCH] separate bdi congestion functions from queue congestion funct…
Browse files Browse the repository at this point in the history
…ions

Separate out the concept of "queue congestion" from "backing-dev congestion".
Congestion is a backing-dev concept, not a queue concept.

The blk_* congestion functions are retained, as wrappers around the core
backing-dev congestion functions.

This proper layering is needed so that NFS can cleanly use the congestion
functions, and so that CONFIG_BLOCK=n actually links.

Cc: "Thomas Maier" <[email protected]>
Cc: "Jens Axboe" <[email protected]>
Cc: Trond Myklebust <[email protected]>
Cc: David Howells <[email protected]>
Cc: Peter Osterlund <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Andrew Morton authored and Linus Torvalds committed Oct 20, 2006
1 parent 79e2de4 commit 3fcfab1
Show file tree
Hide file tree
Showing 17 changed files with 126 additions and 104 deletions.
3 changes: 2 additions & 1 deletion arch/i386/lib/usercopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/highmem.h>
#include <linux/blkdev.h>
#include <linux/module.h>
#include <linux/backing-dev.h>
#include <asm/uaccess.h>
#include <asm/mmx.h>

Expand Down Expand Up @@ -741,7 +742,7 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from,

if (retval == -ENOMEM && is_init(current)) {
up_read(&current->mm->mmap_sem);
blk_congestion_wait(WRITE, HZ/50);
congestion_wait(WRITE, HZ/50);
goto survive;
}

Expand Down
71 changes: 0 additions & 71 deletions block/ll_rw_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ static kmem_cache_t *requestq_cachep;
*/
static kmem_cache_t *iocontext_cachep;

static wait_queue_head_t congestion_wqh[2] = {
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
};

/*
* Controlling structure to kblockd
*/
Expand Down Expand Up @@ -112,37 +107,6 @@ static void blk_queue_congestion_threshold(struct request_queue *q)
q->nr_congestion_off = nr;
}

/*
* A queue has just exitted congestion. Note this in the global counter of
* congested queues, and wake up anyone who was waiting for requests to be
* put back.
*/
void blk_clear_queue_congested(request_queue_t *q, int rw)
{
enum bdi_state bit;
wait_queue_head_t *wqh = &congestion_wqh[rw];

bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
clear_bit(bit, &q->backing_dev_info.state);
smp_mb__after_clear_bit();
if (waitqueue_active(wqh))
wake_up(wqh);
}
EXPORT_SYMBOL(blk_clear_queue_congested);

/*
* A queue has just entered congestion. Flag that in the queue's VM-visible
* state flags and increment the global gounter of congested queues.
*/
void blk_set_queue_congested(request_queue_t *q, int rw)
{
enum bdi_state bit;

bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
set_bit(bit, &q->backing_dev_info.state);
}
EXPORT_SYMBOL(blk_set_queue_congested);

/**
* blk_get_backing_dev_info - get the address of a queue's backing_dev_info
* @bdev: device
Expand Down Expand Up @@ -2755,41 +2719,6 @@ void blk_end_sync_rq(struct request *rq, int error)
}
EXPORT_SYMBOL(blk_end_sync_rq);

/**
* blk_congestion_wait - wait for a queue to become uncongested
* @rw: READ or WRITE
* @timeout: timeout in jiffies
*
* Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
* If no queues are congested then just wait for the next request to be
* returned.
*/
long blk_congestion_wait(int rw, long timeout)
{
long ret;
DEFINE_WAIT(wait);
wait_queue_head_t *wqh = &congestion_wqh[rw];

prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
ret = io_schedule_timeout(timeout);
finish_wait(wqh, &wait);
return ret;
}

EXPORT_SYMBOL(blk_congestion_wait);

/**
* blk_congestion_end - wake up sleepers on a congestion queue
* @rw: READ or WRITE
*/
void blk_congestion_end(int rw)
{
wait_queue_head_t *wqh = &congestion_wqh[rw];

if (waitqueue_active(wqh))
wake_up(wqh);
}

/*
* Has to be called with the request spinlock acquired
*/
Expand Down
3 changes: 2 additions & 1 deletion drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <linux/backing-dev.h>
#include <asm/atomic.h>
#include <linux/scatterlist.h>
#include <asm/page.h>
Expand Down Expand Up @@ -602,7 +603,7 @@ static void process_write(struct crypt_io *io)

/* out of memory -> run queues */
if (remaining)
blk_congestion_wait(bio_data_dir(clone), HZ/100);
congestion_wait(bio_data_dir(clone), HZ/100);
}
}

Expand Down
3 changes: 2 additions & 1 deletion fs/fat/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/writeback.h>
#include <linux/backing-dev.h>
#include <linux/blkdev.h>

int fat_generic_ioctl(struct inode *inode, struct file *filp,
Expand Down Expand Up @@ -118,7 +119,7 @@ static int fat_file_release(struct inode *inode, struct file *filp)
if ((filp->f_mode & FMODE_WRITE) &&
MSDOS_SB(inode->i_sb)->options.flush) {
fat_flush_inodes(inode->i_sb, inode, NULL);
blk_congestion_wait(WRITE, HZ/10);
congestion_wait(WRITE, HZ/10);
}
return 0;
}
Expand Down
4 changes: 3 additions & 1 deletion fs/nfs/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs_page.h>
#include <linux/backing-dev.h>

#include <asm/uaccess.h>
#include <linux/smp_lock.h>

Expand Down Expand Up @@ -395,7 +397,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
out:
clear_bit(BDI_write_congested, &bdi->state);
wake_up_all(&nfs_write_congestion);
writeback_congestion_end();
congestion_end(WRITE);
return err;
}

Expand Down
3 changes: 2 additions & 1 deletion fs/reiserfs/journal.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <linux/workqueue.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>

/* gets a struct reiserfs_journal_list * from a list head */
#define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \
Expand Down Expand Up @@ -970,7 +971,7 @@ int reiserfs_async_progress_wait(struct super_block *s)
DEFINE_WAIT(wait);
struct reiserfs_journal *j = SB_JOURNAL(s);
if (atomic_read(&j->j_async_throttle))
blk_congestion_wait(WRITE, HZ / 10);
congestion_wait(WRITE, HZ / 10);
return 0;
}

Expand Down
5 changes: 3 additions & 2 deletions fs/xfs/linux-2.6/kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include "time.h"
#include "kmem.h"

Expand Down Expand Up @@ -53,7 +54,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
printk(KERN_ERR "XFS: possible memory allocation "
"deadlock in %s (mode:0x%x)\n",
__FUNCTION__, lflags);
blk_congestion_wait(WRITE, HZ/50);
congestion_wait(WRITE, HZ/50);
} while (1);
}

Expand Down Expand Up @@ -131,7 +132,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
printk(KERN_ERR "XFS: possible memory allocation "
"deadlock in %s (mode:0x%x)\n",
__FUNCTION__, lflags);
blk_congestion_wait(WRITE, HZ/50);
congestion_wait(WRITE, HZ/50);
} while (1);
}

Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/linux-2.6/xfs_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/hash.h>
#include <linux/kthread.h>
#include <linux/migrate.h>
#include <linux/backing-dev.h>
#include "xfs_linux.h"

STATIC kmem_zone_t *xfs_buf_zone;
Expand Down Expand Up @@ -395,7 +396,7 @@ _xfs_buf_lookup_pages(

XFS_STATS_INC(xb_page_retries);
xfsbufd_wakeup(0, gfp_mask);
blk_congestion_wait(WRITE, HZ/50);
congestion_wait(WRITE, HZ/50);
goto retry;
}

Expand Down
7 changes: 7 additions & 0 deletions include/linux/backing-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <asm/atomic.h>

struct page;

/*
* Bits in backing_dev_info.state
*/
Expand Down Expand Up @@ -88,6 +90,11 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
(1 << BDI_write_congested));
}

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);
void congestion_end(int rw);

#define bdi_cap_writeback_dirty(bdi) \
(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))

Expand Down
24 changes: 20 additions & 4 deletions include/linux/blkdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,26 @@ extern void blk_recount_segments(request_queue_t *, struct bio *);
extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
extern int sg_scsi_ioctl(struct file *, struct request_queue *,
struct gendisk *, struct scsi_ioctl_command __user *);
extern void blk_clear_queue_congested(request_queue_t *q, int rw);
extern void blk_set_queue_congested(request_queue_t *q, int rw);

/*
* A queue has just exitted congestion. Note this in the global counter of
* congested queues, and wake up anyone who was waiting for requests to be
* put back.
*/
static inline void blk_clear_queue_congested(request_queue_t *q, int rw)
{
clear_bdi_congested(&q->backing_dev_info, rw);
}

/*
* A queue has just entered congestion. Flag that in the queue's VM-visible
* state flags and increment the global gounter of congested queues.
*/
static inline void blk_set_queue_congested(request_queue_t *q, int rw)
{
set_bdi_congested(&q->backing_dev_info, rw);
}

extern void blk_start_queue(request_queue_t *q);
extern void blk_stop_queue(request_queue_t *q);
extern void blk_sync_queue(struct request_queue *q);
Expand Down Expand Up @@ -767,10 +785,8 @@ extern int blk_queue_init_tags(request_queue_t *, int, struct blk_queue_tag *);
extern void blk_queue_free_tags(request_queue_t *);
extern int blk_queue_resize_tags(request_queue_t *, int);
extern void blk_queue_invalidate_tags(request_queue_t *);
extern long blk_congestion_wait(int rw, long timeout);
extern struct blk_queue_tag *blk_init_tags(int);
extern void blk_free_tags(struct blk_queue_tag *);
extern void blk_congestion_end(int rw);

static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
int tag)
Expand Down
1 change: 0 additions & 1 deletion include/linux/writeback.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ int wakeup_pdflush(long nr_pages);
void laptop_io_completion(void);
void laptop_sync_completion(void);
void throttle_vm_writeout(void);
void writeback_congestion_end(void);

/* These are exported to sysctl. */
extern int dirty_background_ratio;
Expand Down
3 changes: 2 additions & 1 deletion mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \
obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
page_alloc.o page-writeback.o pdflush.o \
readahead.o swap.o truncate.o vmscan.o \
prio_tree.o util.o mmzone.o vmstat.o $(mmu-y)
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
$(mmu-y)

ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy)
obj-y += bounce.o
Expand Down
69 changes: 69 additions & 0 deletions mm/backing-dev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

#include <linux/wait.h>
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/module.h>

static wait_queue_head_t congestion_wqh[2] = {
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
};


void clear_bdi_congested(struct backing_dev_info *bdi, int rw)
{
enum bdi_state bit;
wait_queue_head_t *wqh = &congestion_wqh[rw];

bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
clear_bit(bit, &bdi->state);
smp_mb__after_clear_bit();
if (waitqueue_active(wqh))
wake_up(wqh);
}
EXPORT_SYMBOL(clear_bdi_congested);

void set_bdi_congested(struct backing_dev_info *bdi, int rw)
{
enum bdi_state bit;

bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
set_bit(bit, &bdi->state);
}
EXPORT_SYMBOL(set_bdi_congested);

/**
* congestion_wait - wait for a backing_dev to become uncongested
* @rw: READ or WRITE
* @timeout: timeout in jiffies
*
* Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit
* write congestion. If no backing_devs are congested then just wait for the
* next write to be completed.
*/
long congestion_wait(int rw, long timeout)
{
long ret;
DEFINE_WAIT(wait);
wait_queue_head_t *wqh = &congestion_wqh[rw];

prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
ret = io_schedule_timeout(timeout);
finish_wait(wqh, &wait);
return ret;
}
EXPORT_SYMBOL(congestion_wait);

/**
* 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);
Loading

0 comments on commit 3fcfab1

Please sign in to comment.