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: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
cb44921a09
commit
3259f8bed2
2 changed files with 44 additions and 10 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
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 {
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue