diff options
author | Jan Kara <jack@suse.cz> | 2008-07-25 04:46:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:33 -0400 |
commit | 00b441970a0ab48185244300ac7d4e4eb76df692 (patch) | |
tree | 5e0e7b72b0388dd889da267e669dd1e427e82946 /fs | |
parent | 4506567b24d3ea707e46e8aad64caef539382f4b (diff) |
reiserfs: correct mount option parsing to detect when quota options can be changed
We should not allow user to change quota mount options when quota is just
suspended. It would make mount options and internal quota state inconsistent.
Also we should not allow user to change quota format when quota is turned on.
On the other hand we can just silently ignore when some option is set to the
value it already has (some mount versions do this on remount). Finally, we
should not discard current quota options if parsing of mount options fails.
Cc: <reiserfs-devel@vger.kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/reiserfs/super.c | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f723604c5d9b..a10a6d2a8870 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -876,7 +876,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
876 | mount options were selected. */ | 876 | mount options were selected. */ |
877 | unsigned long *blocks, /* strtol-ed from NNN of resize=NNN */ | 877 | unsigned long *blocks, /* strtol-ed from NNN of resize=NNN */ |
878 | char **jdev_name, | 878 | char **jdev_name, |
879 | unsigned int *commit_max_age) | 879 | unsigned int *commit_max_age, |
880 | char **qf_names, | ||
881 | unsigned int *qfmt) | ||
880 | { | 882 | { |
881 | int c; | 883 | int c; |
882 | char *arg = NULL; | 884 | char *arg = NULL; |
@@ -992,7 +994,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
992 | if (c == 'u' || c == 'g') { | 994 | if (c == 'u' || c == 'g') { |
993 | int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; | 995 | int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; |
994 | 996 | ||
995 | if (sb_any_quota_enabled(s)) { | 997 | if ((sb_any_quota_enabled(s) || |
998 | sb_any_quota_suspended(s)) && | ||
999 | (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) { | ||
996 | reiserfs_warning(s, | 1000 | reiserfs_warning(s, |
997 | "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); | 1001 | "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); |
998 | return 0; | 1002 | return 0; |
@@ -1011,30 +1015,39 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
1011 | "reiserfs_parse_options: quotafile must be on filesystem root."); | 1015 | "reiserfs_parse_options: quotafile must be on filesystem root."); |
1012 | return 0; | 1016 | return 0; |
1013 | } | 1017 | } |
1014 | REISERFS_SB(s)->s_qf_names[qtype] = | 1018 | qf_names[qtype] = |
1015 | kmalloc(strlen(arg) + 1, GFP_KERNEL); | 1019 | kmalloc(strlen(arg) + 1, GFP_KERNEL); |
1016 | if (!REISERFS_SB(s)->s_qf_names[qtype]) { | 1020 | if (!qf_names[qtype]) { |
1017 | reiserfs_warning(s, | 1021 | reiserfs_warning(s, |
1018 | "reiserfs_parse_options: not enough memory for storing quotafile name."); | 1022 | "reiserfs_parse_options: not enough memory for storing quotafile name."); |
1019 | return 0; | 1023 | return 0; |
1020 | } | 1024 | } |
1021 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); | 1025 | strcpy(qf_names[qtype], arg); |
1022 | *mount_options |= 1 << REISERFS_QUOTA; | 1026 | *mount_options |= 1 << REISERFS_QUOTA; |
1023 | } else { | 1027 | } else { |
1024 | kfree(REISERFS_SB(s)->s_qf_names[qtype]); | 1028 | if (qf_names[qtype] != |
1025 | REISERFS_SB(s)->s_qf_names[qtype] = NULL; | 1029 | REISERFS_SB(s)->s_qf_names[qtype]) |
1030 | kfree(qf_names[qtype]); | ||
1031 | qf_names[qtype] = NULL; | ||
1026 | } | 1032 | } |
1027 | } | 1033 | } |
1028 | if (c == 'f') { | 1034 | if (c == 'f') { |
1029 | if (!strcmp(arg, "vfsold")) | 1035 | if (!strcmp(arg, "vfsold")) |
1030 | REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD; | 1036 | *qfmt = QFMT_VFS_OLD; |
1031 | else if (!strcmp(arg, "vfsv0")) | 1037 | else if (!strcmp(arg, "vfsv0")) |
1032 | REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0; | 1038 | *qfmt = QFMT_VFS_V0; |
1033 | else { | 1039 | else { |
1034 | reiserfs_warning(s, | 1040 | reiserfs_warning(s, |
1035 | "reiserfs_parse_options: unknown quota format specified."); | 1041 | "reiserfs_parse_options: unknown quota format specified."); |
1036 | return 0; | 1042 | return 0; |
1037 | } | 1043 | } |
1044 | if ((sb_any_quota_enabled(s) || | ||
1045 | sb_any_quota_suspended(s)) && | ||
1046 | *qfmt != REISERFS_SB(s)->s_jquota_fmt) { | ||
1047 | reiserfs_warning(s, | ||
1048 | "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); | ||
1049 | return 0; | ||
1050 | } | ||
1038 | } | 1051 | } |
1039 | #else | 1052 | #else |
1040 | if (c == 'u' || c == 'g' || c == 'f') { | 1053 | if (c == 'u' || c == 'g' || c == 'f') { |
@@ -1046,9 +1059,8 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
1046 | } | 1059 | } |
1047 | 1060 | ||
1048 | #ifdef CONFIG_QUOTA | 1061 | #ifdef CONFIG_QUOTA |
1049 | if (!REISERFS_SB(s)->s_jquota_fmt | 1062 | if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt |
1050 | && (REISERFS_SB(s)->s_qf_names[USRQUOTA] | 1063 | && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) { |
1051 | || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) { | ||
1052 | reiserfs_warning(s, | 1064 | reiserfs_warning(s, |
1053 | "reiserfs_parse_options: journaled quota format not specified."); | 1065 | "reiserfs_parse_options: journaled quota format not specified."); |
1054 | return 0; | 1066 | return 0; |
@@ -1130,6 +1142,21 @@ static void handle_attrs(struct super_block *s) | |||
1130 | } | 1142 | } |
1131 | } | 1143 | } |
1132 | 1144 | ||
1145 | #ifdef CONFIG_QUOTA | ||
1146 | static void handle_quota_files(struct super_block *s, char **qf_names, | ||
1147 | unsigned int *qfmt) | ||
1148 | { | ||
1149 | int i; | ||
1150 | |||
1151 | for (i = 0; i < MAXQUOTAS; i++) { | ||
1152 | if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i]) | ||
1153 | kfree(REISERFS_SB(s)->s_qf_names[i]); | ||
1154 | REISERFS_SB(s)->s_qf_names[i] = qf_names[i]; | ||
1155 | } | ||
1156 | REISERFS_SB(s)->s_jquota_fmt = *qfmt; | ||
1157 | } | ||
1158 | #endif | ||
1159 | |||
1133 | static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | 1160 | static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) |
1134 | { | 1161 | { |
1135 | struct reiserfs_super_block *rs; | 1162 | struct reiserfs_super_block *rs; |
@@ -1141,23 +1168,30 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
1141 | struct reiserfs_journal *journal = SB_JOURNAL(s); | 1168 | struct reiserfs_journal *journal = SB_JOURNAL(s); |
1142 | char *new_opts = kstrdup(arg, GFP_KERNEL); | 1169 | char *new_opts = kstrdup(arg, GFP_KERNEL); |
1143 | int err; | 1170 | int err; |
1171 | char *qf_names[MAXQUOTAS]; | ||
1172 | unsigned int qfmt = 0; | ||
1144 | #ifdef CONFIG_QUOTA | 1173 | #ifdef CONFIG_QUOTA |
1145 | int i; | 1174 | int i; |
1175 | |||
1176 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); | ||
1146 | #endif | 1177 | #endif |
1147 | 1178 | ||
1148 | rs = SB_DISK_SUPER_BLOCK(s); | 1179 | rs = SB_DISK_SUPER_BLOCK(s); |
1149 | 1180 | ||
1150 | if (!reiserfs_parse_options | 1181 | if (!reiserfs_parse_options |
1151 | (s, arg, &mount_options, &blocks, NULL, &commit_max_age)) { | 1182 | (s, arg, &mount_options, &blocks, NULL, &commit_max_age, |
1183 | qf_names, &qfmt)) { | ||
1152 | #ifdef CONFIG_QUOTA | 1184 | #ifdef CONFIG_QUOTA |
1153 | for (i = 0; i < MAXQUOTAS; i++) { | 1185 | for (i = 0; i < MAXQUOTAS; i++) |
1154 | kfree(REISERFS_SB(s)->s_qf_names[i]); | 1186 | if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i]) |
1155 | REISERFS_SB(s)->s_qf_names[i] = NULL; | 1187 | kfree(qf_names[i]); |
1156 | } | ||
1157 | #endif | 1188 | #endif |
1158 | err = -EINVAL; | 1189 | err = -EINVAL; |
1159 | goto out_err; | 1190 | goto out_err; |
1160 | } | 1191 | } |
1192 | #ifdef CONFIG_QUOTA | ||
1193 | handle_quota_files(s, qf_names, &qfmt); | ||
1194 | #endif | ||
1161 | 1195 | ||
1162 | handle_attrs(s); | 1196 | handle_attrs(s); |
1163 | 1197 | ||
@@ -1570,6 +1604,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1570 | char *jdev_name; | 1604 | char *jdev_name; |
1571 | struct reiserfs_sb_info *sbi; | 1605 | struct reiserfs_sb_info *sbi; |
1572 | int errval = -EINVAL; | 1606 | int errval = -EINVAL; |
1607 | char *qf_names[MAXQUOTAS] = {}; | ||
1608 | unsigned int qfmt = 0; | ||
1573 | 1609 | ||
1574 | save_mount_options(s, data); | 1610 | save_mount_options(s, data); |
1575 | 1611 | ||
@@ -1597,9 +1633,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1597 | jdev_name = NULL; | 1633 | jdev_name = NULL; |
1598 | if (reiserfs_parse_options | 1634 | if (reiserfs_parse_options |
1599 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, | 1635 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, |
1600 | &commit_max_age) == 0) { | 1636 | &commit_max_age, qf_names, &qfmt) == 0) { |
1601 | goto error; | 1637 | goto error; |
1602 | } | 1638 | } |
1639 | #ifdef CONFIG_QUOTA | ||
1640 | handle_quota_files(s, qf_names, &qfmt); | ||
1641 | #endif | ||
1603 | 1642 | ||
1604 | if (blocks) { | 1643 | if (blocks) { |
1605 | SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option " | 1644 | SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option " |
@@ -1819,7 +1858,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1819 | 1858 | ||
1820 | return (0); | 1859 | return (0); |
1821 | 1860 | ||
1822 | error: | 1861 | error: |
1823 | if (jinit_done) { /* kill the commit thread, free journal ram */ | 1862 | if (jinit_done) { /* kill the commit thread, free journal ram */ |
1824 | journal_release_error(NULL, s); | 1863 | journal_release_error(NULL, s); |
1825 | } | 1864 | } |
@@ -1830,10 +1869,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
1830 | #ifdef CONFIG_QUOTA | 1869 | #ifdef CONFIG_QUOTA |
1831 | { | 1870 | { |
1832 | int j; | 1871 | int j; |
1833 | for (j = 0; j < MAXQUOTAS; j++) { | 1872 | for (j = 0; j < MAXQUOTAS; j++) |
1834 | kfree(sbi->s_qf_names[j]); | 1873 | kfree(qf_names[j]); |
1835 | sbi->s_qf_names[j] = NULL; | ||
1836 | } | ||
1837 | } | 1874 | } |
1838 | #endif | 1875 | #endif |
1839 | kfree(sbi); | 1876 | kfree(sbi); |