Skip to content

Commit

Permalink
vfs: kill write_super and sync_supers
Browse files Browse the repository at this point in the history
Finally we can kill the 'sync_supers' kernel thread along with the
'->write_super()' superblock operation because all the users are gone.
Now every file-system is supposed to self-manage own superblock and
its dirty state.

The nice thing about killing this thread is that it improves power management.
Indeed, 'sync_supers' is a source of monotonic system wake-ups - it woke up
every 5 seconds no matter what - even if there were no dirty superblocks and
even if there were no file-systems using this service (e.g., btrfs and
journalled ext4 do not need it). So it was wasting power most of the time. And
because the thread was in the core of the kernel, all systems had to have it.
So I am quite happy to make it go away.

Interestingly, this thread is a left-over from the pdflush kernel thread which
was a self-forking kernel thread responsible for all the write-back in old
Linux kernels. It was turned into per-block device BDI threads, and
'sync_supers' was a left-over. Thus, R.I.P, pdflush as well.

Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
dedekind authored and Al Viro committed Aug 3, 2012
1 parent d42d1da commit f0cd2db
Show file tree
Hide file tree
Showing 5 changed files with 0 additions and 97 deletions.
40 changes: 0 additions & 40 deletions fs/super.c
Expand Up @@ -536,46 +536,6 @@ void drop_super(struct super_block *sb)


EXPORT_SYMBOL(drop_super); EXPORT_SYMBOL(drop_super);


/**
* sync_supers - helper for periodic superblock writeback
*
* Call the write_super method if present on all dirty superblocks in
* the system. This is for the periodic writeback used by most older
* filesystems. For data integrity superblock writeback use
* sync_filesystems() instead.
*
* Note: check the dirty flag before waiting, so we don't
* hold up the sync while mounting a device. (The newly
* mounted device won't need syncing.)
*/
void sync_supers(void)
{
struct super_block *sb, *p = NULL;

spin_lock(&sb_lock);
list_for_each_entry(sb, &super_blocks, s_list) {
if (hlist_unhashed(&sb->s_instances))
continue;
if (sb->s_op->write_super && sb->s_dirt) {
sb->s_count++;
spin_unlock(&sb_lock);

down_read(&sb->s_umount);
if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN))
sb->s_op->write_super(sb);
up_read(&sb->s_umount);

spin_lock(&sb_lock);
if (p)
__put_super(p);
p = sb;
}
}
if (p)
__put_super(p);
spin_unlock(&sb_lock);
}

/** /**
* iterate_supers - call function for all active superblocks * iterate_supers - call function for all active superblocks
* @f: function to call * @f: function to call
Expand Down
1 change: 0 additions & 1 deletion include/linux/backing-dev.h
Expand Up @@ -124,7 +124,6 @@ void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
void bdi_start_background_writeback(struct backing_dev_info *bdi); void bdi_start_background_writeback(struct backing_dev_info *bdi);
int bdi_writeback_thread(void *data); int bdi_writeback_thread(void *data);
int bdi_has_dirty_io(struct backing_dev_info *bdi); int bdi_has_dirty_io(struct backing_dev_info *bdi);
void bdi_arm_supers_timer(void);
void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi); void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi);
void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2); void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2);


Expand Down
3 changes: 0 additions & 3 deletions include/linux/fs.h
Expand Up @@ -1491,7 +1491,6 @@ struct sb_writers {
struct super_block { struct super_block {
struct list_head s_list; /* Keep this first */ struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */ dev_t s_dev; /* search index; _not_ kdev_t */
unsigned char s_dirt;
unsigned char s_blocksize_bits; unsigned char s_blocksize_bits;
unsigned long s_blocksize; unsigned long s_blocksize;
loff_t s_maxbytes; /* Max file size */ loff_t s_maxbytes; /* Max file size */
Expand Down Expand Up @@ -1861,7 +1860,6 @@ struct super_operations {
int (*drop_inode) (struct inode *); int (*drop_inode) (struct inode *);
void (*evict_inode) (struct inode *); void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *); void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*sync_fs)(struct super_block *sb, int wait); int (*sync_fs)(struct super_block *sb, int wait);
int (*freeze_fs) (struct super_block *); int (*freeze_fs) (struct super_block *);
int (*unfreeze_fs) (struct super_block *); int (*unfreeze_fs) (struct super_block *);
Expand Down Expand Up @@ -2397,7 +2395,6 @@ extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
int datasync); int datasync);
extern int vfs_fsync(struct file *file, int datasync); extern int vfs_fsync(struct file *file, int datasync);
extern int generic_write_sync(struct file *file, loff_t pos, loff_t count); extern int generic_write_sync(struct file *file, loff_t pos, loff_t count);
extern void sync_supers(void);
extern void emergency_sync(void); extern void emergency_sync(void);
extern void emergency_remount(void); extern void emergency_remount(void);
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK
Expand Down
52 changes: 0 additions & 52 deletions mm/backing-dev.c
Expand Up @@ -39,12 +39,6 @@ DEFINE_SPINLOCK(bdi_lock);
LIST_HEAD(bdi_list); LIST_HEAD(bdi_list);
LIST_HEAD(bdi_pending_list); LIST_HEAD(bdi_pending_list);


static struct task_struct *sync_supers_tsk;
static struct timer_list sync_supers_timer;

static int bdi_sync_supers(void *);
static void sync_supers_timer_fn(unsigned long);

void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2) void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2)
{ {
if (wb1 < wb2) { if (wb1 < wb2) {
Expand Down Expand Up @@ -250,12 +244,6 @@ static int __init default_bdi_init(void)
{ {
int err; int err;


sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
BUG_ON(IS_ERR(sync_supers_tsk));

setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
bdi_arm_supers_timer();

err = bdi_init(&default_backing_dev_info); err = bdi_init(&default_backing_dev_info);
if (!err) if (!err)
bdi_register(&default_backing_dev_info, NULL, "default"); bdi_register(&default_backing_dev_info, NULL, "default");
Expand All @@ -270,46 +258,6 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)
return wb_has_dirty_io(&bdi->wb); return wb_has_dirty_io(&bdi->wb);
} }


/*
* kupdated() used to do this. We cannot do it from the bdi_forker_thread()
* or we risk deadlocking on ->s_umount. The longer term solution would be
* to implement sync_supers_bdi() or similar and simply do it from the
* bdi writeback thread individually.
*/
static int bdi_sync_supers(void *unused)
{
set_user_nice(current, 0);

while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();

/*
* Do this periodically, like kupdated() did before.
*/
sync_supers();
}

return 0;
}

void bdi_arm_supers_timer(void)
{
unsigned long next;

if (!dirty_writeback_interval)
return;

next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
mod_timer(&sync_supers_timer, round_jiffies_up(next));
}

static void sync_supers_timer_fn(unsigned long unused)
{
wake_up_process(sync_supers_tsk);
bdi_arm_supers_timer();
}

static void wakeup_timer_fn(unsigned long data) static void wakeup_timer_fn(unsigned long data)
{ {
struct backing_dev_info *bdi = (struct backing_dev_info *)data; struct backing_dev_info *bdi = (struct backing_dev_info *)data;
Expand Down
1 change: 0 additions & 1 deletion mm/page-writeback.c
Expand Up @@ -1532,7 +1532,6 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos) void __user *buffer, size_t *length, loff_t *ppos)
{ {
proc_dointvec(table, write, buffer, length, ppos); proc_dointvec(table, write, buffer, length, ppos);
bdi_arm_supers_timer();
return 0; return 0;
} }


Expand Down

0 comments on commit f0cd2db

Please sign in to comment.