diff options
author | Theodore Ts'o <tytso@mit.edu> | 2017-02-05 19:47:14 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-02-05 19:47:14 -0500 |
commit | 783d948544993f55bdacc78b127532e8b6e2fc9f (patch) | |
tree | 9aa172542294f1d75dc033d10f8756c5832ee1e8 | |
parent | 0db1ff222d40f1601c961f0edb86d10426992595 (diff) |
ext4: add EXT4_IOC_GOINGDOWN ioctl
This ioctl is modeled after the xfs's XFS_IOC_GOINGDOWN ioctl. (In
fact, it uses the same code points.)
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | fs/ext4/ext4.h | 10 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 50 | ||||
-rw-r--r-- | fs/ext4/super.c | 2 |
3 files changed, 61 insertions, 1 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 35d93ab7f3fb..55b7a77a0444 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -679,6 +679,16 @@ struct fsxattr { | |||
679 | #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR | 679 | #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR |
680 | #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR | 680 | #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR |
681 | 681 | ||
682 | #define EXT4_IOC_GOINGDOWN _IOR ('X', 125, __u32) | ||
683 | |||
684 | /* | ||
685 | * Flags for going down operation | ||
686 | */ | ||
687 | #define EXT4_GOING_FLAGS_DEFAULT 0x0 /* going down */ | ||
688 | #define EXT4_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ | ||
689 | #define EXT4_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ | ||
690 | |||
691 | |||
682 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | 692 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) |
683 | /* | 693 | /* |
684 | * ioctl commands in 32 bit emulation | 694 | * ioctl commands in 32 bit emulation |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index d534399cf607..b383ebf4020c 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/quotaops.h> | 16 | #include <linux/quotaops.h> |
17 | #include <linux/uuid.h> | 17 | #include <linux/uuid.h> |
18 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
19 | #include <linux/delay.h> | ||
19 | #include "ext4_jbd2.h" | 20 | #include "ext4_jbd2.h" |
20 | #include "ext4.h" | 21 | #include "ext4.h" |
21 | 22 | ||
@@ -442,6 +443,52 @@ static inline unsigned long ext4_xflags_to_iflags(__u32 xflags) | |||
442 | return iflags; | 443 | return iflags; |
443 | } | 444 | } |
444 | 445 | ||
446 | int ext4_goingdown(struct super_block *sb, unsigned long arg) | ||
447 | { | ||
448 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
449 | __u32 flags; | ||
450 | |||
451 | if (!capable(CAP_SYS_ADMIN)) | ||
452 | return -EPERM; | ||
453 | |||
454 | if (get_user(flags, (__u32 __user *)arg)) | ||
455 | return -EFAULT; | ||
456 | |||
457 | if (flags > EXT4_GOING_FLAGS_NOLOGFLUSH) | ||
458 | return -EINVAL; | ||
459 | |||
460 | if (ext4_forced_shutdown(sbi)) | ||
461 | return 0; | ||
462 | |||
463 | ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags); | ||
464 | |||
465 | switch (flags) { | ||
466 | case EXT4_GOING_FLAGS_DEFAULT: | ||
467 | freeze_bdev(sb->s_bdev); | ||
468 | set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); | ||
469 | thaw_bdev(sb->s_bdev, sb); | ||
470 | break; | ||
471 | case EXT4_GOING_FLAGS_LOGFLUSH: | ||
472 | set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); | ||
473 | if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) { | ||
474 | (void) ext4_force_commit(sb); | ||
475 | jbd2_journal_abort(sbi->s_journal, 0); | ||
476 | } | ||
477 | break; | ||
478 | case EXT4_GOING_FLAGS_NOLOGFLUSH: | ||
479 | set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); | ||
480 | if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) { | ||
481 | msleep(100); | ||
482 | jbd2_journal_abort(sbi->s_journal, 0); | ||
483 | } | ||
484 | break; | ||
485 | default: | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | clear_opt(sb, DISCARD); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
445 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 492 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
446 | { | 493 | { |
447 | struct inode *inode = file_inode(filp); | 494 | struct inode *inode = file_inode(filp); |
@@ -893,6 +940,8 @@ resizefs_out: | |||
893 | 940 | ||
894 | return 0; | 941 | return 0; |
895 | } | 942 | } |
943 | case EXT4_IOC_GOINGDOWN: | ||
944 | return ext4_goingdown(sb, arg); | ||
896 | default: | 945 | default: |
897 | return -ENOTTY; | 946 | return -ENOTTY; |
898 | } | 947 | } |
@@ -959,6 +1008,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
959 | case EXT4_IOC_SET_ENCRYPTION_POLICY: | 1008 | case EXT4_IOC_SET_ENCRYPTION_POLICY: |
960 | case EXT4_IOC_GET_ENCRYPTION_PWSALT: | 1009 | case EXT4_IOC_GET_ENCRYPTION_PWSALT: |
961 | case EXT4_IOC_GET_ENCRYPTION_POLICY: | 1010 | case EXT4_IOC_GET_ENCRYPTION_POLICY: |
1011 | case EXT4_IOC_GOINGDOWN: | ||
962 | break; | 1012 | break; |
963 | default: | 1013 | default: |
964 | return -ENOIOCTLCMD; | 1014 | return -ENOIOCTLCMD; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index cfa4ce5a1f80..3db5b6491513 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -4821,7 +4821,7 @@ out: | |||
4821 | */ | 4821 | */ |
4822 | static int ext4_unfreeze(struct super_block *sb) | 4822 | static int ext4_unfreeze(struct super_block *sb) |
4823 | { | 4823 | { |
4824 | if (sb->s_flags & MS_RDONLY) | 4824 | if ((sb->s_flags & MS_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb))) |
4825 | return 0; | 4825 | return 0; |
4826 | 4826 | ||
4827 | if (EXT4_SB(sb)->s_journal) { | 4827 | if (EXT4_SB(sb)->s_journal) { |