/*
* fs/fs-writeback.c
*
* Copyright (C) 2002, Linus Torvalds.
*
* Contains all the functions related to writing back and waiting
* upon dirty inodes against superblocks, and writing back dirty
* pages against inodes. ie: data writeback. Writeout of the
* inode itself is not handled here.
*
* 10Apr2002 Andrew Morton
* Split out of fs/inode.c
* Additions for address_space-based writeback
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
#include "internal.h"
#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
/*
* We don't actually have pdflush, but this one is exported though /proc...
*/
int nr_pdflush_threads;
/*
* Work items for the bdi_writeback threads
*/
struct bdi_work {
struct list_head list;
struct list_head wait_list;
struct rcu_head rcu_head;
unsigned long seen;
atomic_t pending;
struct super_block *sb;
unsigned long nr_pages;
enum writeback_sync_modes sync_mode;
unsigned long state;
};
enum {
WS_USED_B = 0,
WS_ONSTACK_B,
};
#define WS_USED (1 << WS_USED_B)
#define WS_ONSTACK (1 << WS_ONSTACK_B)
static inline bool bdi_work_on_stack(struct bdi_work *work)
{
return test_bit(WS_ONSTACK_B, &work->state);
}
static inline void bdi_work_init(struct bdi_work *work,
struct writeback_control *wbc)
{
INIT_RCU_HEAD(&work->rcu_head);
work->sb = wbc->sb;
work->nr_pages = wbc->nr_to_write;
work->sync_mode = wbc->sync_mode;
work->state = WS_USED;
}
static inline void bdi_work_init_on_stack(struct bdi_work *work,
struct writeback_control *wbc)
{
bdi_work_init(work, wbc);
work->state |= WS_ONSTACK;
}
/**
* writeback_in_progress - determine whether there is writeback in progress
* @bdi: the device's backing_dev_info structure.
*
* Determine whether there is writeback waiting to be handled against a
* backing device.
*/
int writeback_in_progress(struct backing_dev_info *bdi)
{
return !list_empty(&bdi->work_list);
}
static void bdi_work_clear(struct bdi_work *work)
{
clear_bit(WS_USED_B, &work->state);
smp_mb__after_clear_bit();
wake_up_bit(&work->state, WS_USED_B);
}
static void bdi_work_free(struct rcu_head *head)
{
struct bdi_work *work = container_of(head, struct bdi_work, rcu_head);
if (!bdi_work_on_stack(work))
kfree(work);