Commit 3259f8be authored by Chris Mason's avatar Chris Mason

Add new functions for triggering inode writeback

When btrfs is running low on metadata space, it needs to force delayed
allocation pages to disk.  It currently does this with a suboptimal walk
of a private list of inodes with delayed allocation, and it would be
much better if we used the generic flusher threads.

writeback_inodes_sb_if_idle would be ideal, but it waits for the flusher
thread to start IO on all the dirty pages in the FS before it returns.
This adds variants of writeback_inodes_sb* that allow the caller to
control how many pages get sent down.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent cb44921a
...@@ -1069,33 +1069,44 @@ static void wait_sb_inodes(struct super_block *sb) ...@@ -1069,33 +1069,44 @@ static void wait_sb_inodes(struct super_block *sb)
} }
/** /**
* writeback_inodes_sb - writeback dirty inodes from given super_block * writeback_inodes_sb_nr - writeback dirty inodes from given super_block
* @sb: the superblock * @sb: the superblock
* @nr: the number of pages to write
* *
* Start writeback on some inodes on this super_block. No guarantees are made * Start writeback on some inodes on this super_block. No guarantees are made
* on how many (if any) will be written, and this function does not wait * on how many (if any) will be written, and this function does not wait
* for IO completion of submitted IO. The number of pages submitted is * for IO completion of submitted IO.
* returned.
*/ */
void writeback_inodes_sb(struct super_block *sb) void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr)
{ {
unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY);
unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS);
DECLARE_COMPLETION_ONSTACK(done); DECLARE_COMPLETION_ONSTACK(done);
struct wb_writeback_work work = { struct wb_writeback_work work = {
.sb = sb, .sb = sb,
.sync_mode = WB_SYNC_NONE, .sync_mode = WB_SYNC_NONE,
.done = &done, .done = &done,
.nr_pages = nr,
}; };
WARN_ON(!rwsem_is_locked(&sb->s_umount)); WARN_ON(!rwsem_is_locked(&sb->s_umount));
work.nr_pages = nr_dirty + nr_unstable +
(inodes_stat.nr_inodes - inodes_stat.nr_unused);
bdi_queue_work(sb->s_bdi, &work); bdi_queue_work(sb->s_bdi, &work);
wait_for_completion(&done); wait_for_completion(&done);
} }
EXPORT_SYMBOL(writeback_inodes_sb_nr);
/**
* writeback_inodes_sb - writeback dirty inodes from given super_block
* @sb: the superblock
*
* Start writeback on some inodes on this super_block. No guarantees are made
* on how many (if any) will be written, and this function does not wait
* for IO completion of submitted IO.
*/
void writeback_inodes_sb(struct super_block *sb)
{
return writeback_inodes_sb_nr(sb, global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_UNSTABLE_NFS) +
(inodes_stat.nr_inodes - inodes_stat.nr_unused));
}
EXPORT_SYMBOL(writeback_inodes_sb); EXPORT_SYMBOL(writeback_inodes_sb);
/** /**
...@@ -1117,6 +1128,27 @@ int writeback_inodes_sb_if_idle(struct super_block *sb) ...@@ -1117,6 +1128,27 @@ int writeback_inodes_sb_if_idle(struct super_block *sb)
} }
EXPORT_SYMBOL(writeback_inodes_sb_if_idle); EXPORT_SYMBOL(writeback_inodes_sb_if_idle);
/**
* writeback_inodes_sb_if_idle - start writeback if none underway
* @sb: the superblock
* @nr: the number of pages to write
*
* Invoke writeback_inodes_sb if no writeback is currently underway.
* Returns 1 if writeback was started, 0 if not.
*/
int writeback_inodes_sb_nr_if_idle(struct super_block *sb,
unsigned long nr)
{
if (!writeback_in_progress(sb->s_bdi)) {
down_read(&sb->s_umount);
writeback_inodes_sb_nr(sb, nr);
up_read(&sb->s_umount);
return 1;
} else
return 0;
}
EXPORT_SYMBOL(writeback_inodes_sb_nr_if_idle);
/** /**
* sync_inodes_sb - sync sb inode pages * sync_inodes_sb - sync sb inode pages
* @sb: the superblock * @sb: the superblock
......
...@@ -60,7 +60,9 @@ struct writeback_control { ...@@ -60,7 +60,9 @@ struct writeback_control {
struct bdi_writeback; struct bdi_writeback;
int inode_wait(void *); int inode_wait(void *);
void writeback_inodes_sb(struct super_block *); void writeback_inodes_sb(struct super_block *);
void writeback_inodes_sb_nr(struct super_block *, unsigned long nr);
int writeback_inodes_sb_if_idle(struct super_block *); int writeback_inodes_sb_if_idle(struct super_block *);
int writeback_inodes_sb_nr_if_idle(struct super_block *, unsigned long nr);
void sync_inodes_sb(struct super_block *); void sync_inodes_sb(struct super_block *);
void writeback_inodes_wb(struct bdi_writeback *wb, void writeback_inodes_wb(struct bdi_writeback *wb,
struct writeback_control *wbc); struct writeback_control *wbc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment