Commit b7bd1dee authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] sysrq-S, sysrq-U cleanups

From: Christoph Hellwig <hch@lst.de>

Change sysrq sync/remount from a magic bdflush hook to proper pdflush
operations.  The sync operation reuses most of the regular sys_sync path now
instead of implementing it's own superblock walking and (broken) local disk
detection, the remount implementation has been moved to super.c, cleaned up
and updated for the last two years locking changes.  It also shares some code
with the regular remount path now.
parent 862fb282
...@@ -101,131 +101,19 @@ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, ...@@ -101,131 +101,19 @@ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
{ {
machine_restart(NULL); machine_restart(NULL);
} }
static struct sysrq_key_op sysrq_reboot_op = { static struct sysrq_key_op sysrq_reboot_op = {
.handler = sysrq_handle_reboot, .handler = sysrq_handle_reboot,
.help_msg = "reBoot", .help_msg = "reBoot",
.action_msg = "Resetting", .action_msg = "Resetting",
}; };
/* SYNC SYSRQ HANDLERS BLOCK */
/* do_emergency_sync helper function */
/* Guesses if the device is a local hard drive */
static int is_local_disk(struct block_device *bdev)
{
switch (MAJOR(bdev->bd_dev)) {
case IDE0_MAJOR:
case IDE1_MAJOR:
case IDE2_MAJOR:
case IDE3_MAJOR:
case IDE4_MAJOR:
case IDE5_MAJOR:
case IDE6_MAJOR:
case IDE7_MAJOR:
case IDE8_MAJOR:
case IDE9_MAJOR:
case SCSI_DISK0_MAJOR:
case SCSI_DISK1_MAJOR:
case SCSI_DISK2_MAJOR:
case SCSI_DISK3_MAJOR:
case SCSI_DISK4_MAJOR:
case SCSI_DISK5_MAJOR:
case SCSI_DISK6_MAJOR:
case SCSI_DISK7_MAJOR:
case XT_DISK_MAJOR:
return 1;
default:
return 0;
}
}
/* do_emergency_sync helper function */
static void go_sync(struct super_block *sb, int remount_flag)
{
int orig_loglevel;
orig_loglevel = console_loglevel;
console_loglevel = 7;
printk(KERN_INFO "%sing device %s ... ",
remount_flag ? "Remount" : "Sync",
sb->s_id);
if (remount_flag) { /* Remount R/O */
int ret, flags;
struct file *file;
if (sb->s_flags & MS_RDONLY) {
printk("R/O\n");
return;
}
file_list_lock();
list_for_each_entry(file, &sb->s_files, f_list) {
if (file->f_dentry && file_count(file)
&& S_ISREG(file->f_dentry->d_inode->i_mode))
file->f_mode &= ~2;
}
file_list_unlock();
DQUOT_OFF(sb);
fsync_bdev(sb->s_bdev);
flags = MS_RDONLY;
if (sb->s_op && sb->s_op->remount_fs) {
ret = sb->s_op->remount_fs(sb, &flags, NULL);
if (ret)
printk("error %d\n", ret);
else {
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
printk("OK\n");
}
} else
printk("nothing to do\n");
} else { /* Sync only */
fsync_bdev(sb->s_bdev);
printk("OK\n");
}
console_loglevel = orig_loglevel;
}
/*
* Emergency Sync or Unmount. We cannot do it directly, so we set a special
* flag and wake up the bdflush kernel thread which immediately calls this function.
* We process all mounted hard drives first to recover from crashed experimental
* block devices and malfunctional network filesystems.
*/
int emergency_sync_scheduled;
void do_emergency_sync(void) {
struct super_block *sb;
int remount_flag;
int orig_loglevel;
lock_kernel();
remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
emergency_sync_scheduled = 0;
list_for_each_entry(sb, &super_blocks, s_list)
if (sb->s_bdev && is_local_disk(sb->s_bdev))
go_sync(sb, remount_flag);
list_for_each_entry(sb, &super_blocks, s_list)
if (sb->s_bdev && !is_local_disk(sb->s_bdev))
go_sync(sb, remount_flag);
unlock_kernel();
orig_loglevel = console_loglevel;
console_loglevel = 7;
printk(KERN_INFO "Done.\n");
console_loglevel = orig_loglevel;
}
static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
struct tty_struct *tty) struct tty_struct *tty)
{ {
emergency_sync_scheduled = EMERG_SYNC; emergency_sync();
wakeup_bdflush(0);
} }
static struct sysrq_key_op sysrq_sync_op = { static struct sysrq_key_op sysrq_sync_op = {
.handler = sysrq_handle_sync, .handler = sysrq_handle_sync,
.help_msg = "Sync", .help_msg = "Sync",
...@@ -235,9 +123,9 @@ static struct sysrq_key_op sysrq_sync_op = { ...@@ -235,9 +123,9 @@ static struct sysrq_key_op sysrq_sync_op = {
static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
struct tty_struct *tty) struct tty_struct *tty)
{ {
emergency_sync_scheduled = EMERG_REMOUNT; emergency_remount();
wakeup_bdflush(0);
} }
static struct sysrq_key_op sysrq_mountro_op = { static struct sysrq_key_op sysrq_mountro_op = {
.handler = sysrq_handle_mountro, .handler = sysrq_handle_mountro,
.help_msg = "Unmount", .help_msg = "Unmount",
......
...@@ -244,18 +244,28 @@ int fsync_bdev(struct block_device *bdev) ...@@ -244,18 +244,28 @@ int fsync_bdev(struct block_device *bdev)
* sync everything. Start out by waking pdflush, because that writes back * sync everything. Start out by waking pdflush, because that writes back
* all queues in parallel. * all queues in parallel.
*/ */
asmlinkage long sys_sync(void) static void do_sync(unsigned long wait)
{ {
wakeup_bdflush(0); wakeup_bdflush(0);
sync_inodes(0); /* All mappings, inodes and their blockdevs */ sync_inodes(0); /* All mappings, inodes and their blockdevs */
DQUOT_SYNC(NULL); DQUOT_SYNC(NULL);
sync_supers(); /* Write the superblocks */ sync_supers(); /* Write the superblocks */
sync_filesystems(0); /* Start syncing the filesystems */ sync_filesystems(0); /* Start syncing the filesystems */
sync_filesystems(1); /* Waitingly sync the filesystems */ sync_filesystems(wait); /* Waitingly sync the filesystems */
sync_inodes(1); /* Mappings, inodes and blockdevs, again. */ sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
}
asmlinkage long sys_sync(void)
{
do_sync(1);
return 0; return 0;
} }
void emergency_sync(void)
{
pdflush_operation(do_sync, 0);
}
/* /*
* Generic function to fsync a file. * Generic function to fsync a file.
* *
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
extern int do_remount_sb(struct super_block *sb, int flags, void * data);
extern int __init init_rootfs(void); extern int __init init_rootfs(void);
extern int __init fs_subsys_init(void); extern int __init fs_subsys_init(void);
...@@ -326,7 +325,7 @@ static int do_umount(struct vfsmount *mnt, int flags) ...@@ -326,7 +325,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
down_write(&sb->s_umount); down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
lock_kernel(); lock_kernel();
retval = do_remount_sb(sb, MS_RDONLY, 0); retval = do_remount_sb(sb, MS_RDONLY, 0, 0);
unlock_kernel(); unlock_kernel();
} }
up_write(&sb->s_umount); up_write(&sb->s_umount);
...@@ -555,7 +554,7 @@ static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data) ...@@ -555,7 +554,7 @@ static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data)
return -EINVAL; return -EINVAL;
down_write(&sb->s_umount); down_write(&sb->s_umount);
err = do_remount_sb(sb, flags, data); err = do_remount_sb(sb, flags, data, 0);
if (!err) if (!err)
nd->mnt->mnt_flags=mnt_flags; nd->mnt->mnt_flags=mnt_flags;
up_write(&sb->s_umount); up_write(&sb->s_umount);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/writeback.h> /* for the emergency remount stuff */
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -431,6 +432,18 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf) ...@@ -431,6 +432,18 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf)
return err; return err;
} }
static void mark_files_ro(struct super_block *sb)
{
struct file *f;
file_list_lock();
list_for_each_entry(f, &sb->s_files, f_list) {
if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f))
f->f_mode &= ~FMODE_WRITE;
}
file_list_unlock();
}
/** /**
* do_remount_sb - asks filesystem to change mount options. * do_remount_sb - asks filesystem to change mount options.
* @sb: superblock in question * @sb: superblock in question
...@@ -439,21 +452,25 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf) ...@@ -439,21 +452,25 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf)
* *
* Alters the mount options of a mounted file system. * Alters the mount options of a mounted file system.
*/ */
int do_remount_sb(struct super_block *sb, int flags, void *data) int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
{ {
int retval; int retval;
if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
return -EACCES; return -EACCES;
/*flags |= MS_RDONLY;*/
if (flags & MS_RDONLY) if (flags & MS_RDONLY)
acct_auto_close(sb); acct_auto_close(sb);
shrink_dcache_sb(sb); shrink_dcache_sb(sb);
fsync_super(sb); fsync_super(sb);
/* If we are remounting RDONLY, make sure there are no rw files open */ /* If we are remounting RDONLY, make sure there are no rw files open */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
if (!fs_may_remount_ro(sb)) if (force)
mark_files_ro(sb);
else if (!fs_may_remount_ro(sb))
return -EBUSY; return -EBUSY;
}
if (sb->s_op->remount_fs) { if (sb->s_op->remount_fs) {
lock_super(sb); lock_super(sb);
retval = sb->s_op->remount_fs(sb, &flags, data); retval = sb->s_op->remount_fs(sb, &flags, data);
...@@ -465,6 +482,28 @@ int do_remount_sb(struct super_block *sb, int flags, void *data) ...@@ -465,6 +482,28 @@ int do_remount_sb(struct super_block *sb, int flags, void *data)
return 0; return 0;
} }
static void do_emergency_remount(unsigned long foo)
{
struct super_block *sb;
spin_lock(&sb_lock);
list_for_each_entry(sb, &super_blocks, s_list) {
sb->s_count++;
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY))
do_remount_sb(sb, MS_RDONLY, NULL, 1);
drop_super(sb);
spin_lock(&sb_lock);
}
spin_unlock(&sb_lock);
}
void emergency_remount(void)
{
pdflush_operation(do_emergency_remount, 0);
}
/* /*
* Unnamed block devices are dummy devices used by virtual * Unnamed block devices are dummy devices used by virtual
* filesystems which don't use real block-devices. -- jrs * filesystems which don't use real block-devices. -- jrs
...@@ -618,7 +657,7 @@ struct super_block *get_sb_single(struct file_system_type *fs_type, ...@@ -618,7 +657,7 @@ struct super_block *get_sb_single(struct file_system_type *fs_type,
} }
s->s_flags |= MS_ACTIVE; s->s_flags |= MS_ACTIVE;
} }
do_remount_sb(s, flags, data); do_remount_sb(s, flags, data, 0);
return s; return s;
} }
......
...@@ -1113,6 +1113,10 @@ extern int filemap_flush(struct address_space *); ...@@ -1113,6 +1113,10 @@ extern int filemap_flush(struct address_space *);
extern int filemap_fdatawait(struct address_space *); extern int filemap_fdatawait(struct address_space *);
extern void sync_supers(void); extern void sync_supers(void);
extern void sync_filesystems(int wait); extern void sync_filesystems(int wait);
extern void emergency_sync(void);
extern void emergency_remount(void);
extern int do_remount_sb(struct super_block *sb, int flags,
void *data, int force);
extern sector_t bmap(struct inode *, sector_t); extern sector_t bmap(struct inode *, sector_t);
extern int setattr_mask(unsigned int); extern int setattr_mask(unsigned int);
extern int notify_change(struct dentry *, struct iattr *); extern int notify_change(struct dentry *, struct iattr *);
......
...@@ -92,21 +92,3 @@ static inline int __reterr(void) ...@@ -92,21 +92,3 @@ static inline int __reterr(void)
#define unregister_sysrq_key(ig,nore) __reterr() #define unregister_sysrq_key(ig,nore) __reterr()
#endif #endif
/* Deferred actions */
extern int emergency_sync_scheduled;
#define EMERG_SYNC 1
#define EMERG_REMOUNT 2
void do_emergency_sync(void);
#ifdef CONFIG_MAGIC_SYSRQ
#define CHECK_EMERGENCY_SYNC \
if (emergency_sync_scheduled) \
do_emergency_sync();
#else
#define CHECK_EMERGENCY_SYNC
#endif
...@@ -96,9 +96,8 @@ NORET_TYPE void panic(const char * fmt, ...) ...@@ -96,9 +96,8 @@ NORET_TYPE void panic(const char * fmt, ...)
disabled_wait(caller); disabled_wait(caller);
#endif #endif
local_irq_enable(); local_irq_enable();
for(;;) { for (;;)
CHECK_EMERGENCY_SYNC ;
}
} }
/** /**
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysrq.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/mpage.h> #include <linux/mpage.h>
...@@ -237,7 +236,6 @@ static void background_writeout(unsigned long _min_pages) ...@@ -237,7 +236,6 @@ static void background_writeout(unsigned long _min_pages)
.nonblocking = 1, .nonblocking = 1,
}; };
CHECK_EMERGENCY_SYNC
for ( ; ; ) { for ( ; ; ) {
struct page_state ps; struct page_state ps;
long background_thresh; long background_thresh;
......
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