Sync up to get to minimally functional lazy journalling patches
[ext4-patch-queue.git] / add-shutdown-ioctl
blobf83da6d27ce370fc69e09f7dd68e35b8a789b0f3
1 ext4: add EXT4_IOC_GOINGDOWN ioctl
3 This ioctl is modeled after the xfs's XFS_IOC_GOINGDOWN ioctl.  (In
4 fact, it uses the same code points.)
6 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
7 ---
8  fs/ext4/ext4.h  | 10 ++++++++++
9  fs/ext4/ioctl.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
10  fs/ext4/super.c |  2 +-
11  3 files changed, 61 insertions(+), 1 deletion(-)
13 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
14 index 35d93ab7f3fb..55b7a77a0444 100644
15 --- a/fs/ext4/ext4.h
16 +++ b/fs/ext4/ext4.h
17 @@ -679,6 +679,16 @@ struct fsxattr {
18  #define EXT4_IOC_FSGETXATTR            FS_IOC_FSGETXATTR
19  #define EXT4_IOC_FSSETXATTR            FS_IOC_FSSETXATTR
21 +#define EXT4_IOC_GOINGDOWN _IOR ('X', 125, __u32)
23 +/*
24 + * Flags for going down operation
25 + */
26 +#define EXT4_GOING_FLAGS_DEFAULT               0x0     /* going down */
27 +#define EXT4_GOING_FLAGS_LOGFLUSH              0x1     /* flush log but not data */
28 +#define EXT4_GOING_FLAGS_NOLOGFLUSH            0x2     /* don't flush log nor data */
31  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
32  /*
33   * ioctl commands in 32 bit emulation
34 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
35 index d534399cf607..b383ebf4020c 100644
36 --- a/fs/ext4/ioctl.c
37 +++ b/fs/ext4/ioctl.c
38 @@ -16,6 +16,7 @@
39  #include <linux/quotaops.h>
40  #include <linux/uuid.h>
41  #include <linux/uaccess.h>
42 +#include <linux/delay.h>
43  #include "ext4_jbd2.h"
44  #include "ext4.h"
46 @@ -442,6 +443,52 @@ static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
47         return iflags;
48  }
50 +int ext4_goingdown(struct super_block *sb, unsigned long arg)
52 +       struct ext4_sb_info *sbi = EXT4_SB(sb);
53 +       __u32 flags;
55 +       if (!capable(CAP_SYS_ADMIN))
56 +               return -EPERM;
58 +       if (get_user(flags, (__u32 __user *)arg))
59 +               return -EFAULT;
61 +       if (flags > EXT4_GOING_FLAGS_NOLOGFLUSH)
62 +               return -EINVAL;
64 +       if (ext4_forced_shutdown(sbi))
65 +               return 0;
67 +       ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags);
69 +       switch (flags) {
70 +       case EXT4_GOING_FLAGS_DEFAULT:
71 +               freeze_bdev(sb->s_bdev);
72 +               set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
73 +               thaw_bdev(sb->s_bdev, sb);
74 +               break;
75 +       case EXT4_GOING_FLAGS_LOGFLUSH:
76 +               set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
77 +               if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) {
78 +                       (void) ext4_force_commit(sb);
79 +                       jbd2_journal_abort(sbi->s_journal, 0);
80 +               }
81 +               break;
82 +       case EXT4_GOING_FLAGS_NOLOGFLUSH:
83 +               set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
84 +               if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) {
85 +                       msleep(100);
86 +                       jbd2_journal_abort(sbi->s_journal, 0);
87 +               }
88 +               break;
89 +       default:
90 +               return -EINVAL;
91 +       }
92 +       clear_opt(sb, DISCARD);
93 +       return 0;
96  long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
97  {
98         struct inode *inode = file_inode(filp);
99 @@ -893,6 +940,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
101                 return 0;
102         }
103 +       case EXT4_IOC_GOINGDOWN:
104 +               return ext4_goingdown(sb, arg);
105         default:
106                 return -ENOTTY;
107         }
108 @@ -959,6 +1008,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
109         case EXT4_IOC_SET_ENCRYPTION_POLICY:
110         case EXT4_IOC_GET_ENCRYPTION_PWSALT:
111         case EXT4_IOC_GET_ENCRYPTION_POLICY:
112 +       case EXT4_IOC_GOINGDOWN:
113                 break;
114         default:
115                 return -ENOIOCTLCMD;
116 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
117 index 91d6a6199fe0..f9a2252610a8 100644
118 --- a/fs/ext4/super.c
119 +++ b/fs/ext4/super.c
120 @@ -4817,7 +4817,7 @@ static int ext4_freeze(struct super_block *sb)
121   */
122  static int ext4_unfreeze(struct super_block *sb)
124 -       if (sb->s_flags & MS_RDONLY)
125 +       if ((sb->s_flags & MS_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb)))
126                 return 0;
128         if (EXT4_SB(sb)->s_journal) {