aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/vfat.txt5
-rw-r--r--fs/fat/cache.c6
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/fat/fat.h7
-rw-r--r--fs/fat/fatent.c4
-rw-r--r--fs/fat/file.c2
-rw-r--r--fs/fat/inode.c28
-rw-r--r--fs/fat/misc.c22
-rw-r--r--fs/fat/namei_msdos.c2
-rw-r--r--fs/fat/namei_vfat.c2
10 files changed, 58 insertions, 22 deletions
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index 3a5ddc96901a..7d41c0da6344 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -132,6 +132,11 @@ rodir -- FAT has the ATTR_RO (read-only) attribute. But on Windows,
132 If you want to use ATTR_RO as read-only flag even for 132 If you want to use ATTR_RO as read-only flag even for
133 the directory, set this option. 133 the directory, set this option.
134 134
135errors=panic|continue|remount-ro
136 -- specify FAT behavior on critical errors: panic, continue
137 without doing anything or remount the partition in
138 read-only mode (default behavior).
139
135<bool>: 0,1,yes,no,true,false 140<bool>: 0,1,yes,no,true,false
136 141
137TODO 142TODO
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index b42602298087..923990e4f16e 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
241 while (*fclus < cluster) { 241 while (*fclus < cluster) {
242 /* prevent the infinite loop of cluster chain */ 242 /* prevent the infinite loop of cluster chain */
243 if (*fclus > limit) { 243 if (*fclus > limit) {
244 fat_fs_panic(sb, "%s: detected the cluster chain loop" 244 fat_fs_error(sb, "%s: detected the cluster chain loop"
245 " (i_pos %lld)", __func__, 245 " (i_pos %lld)", __func__,
246 MSDOS_I(inode)->i_pos); 246 MSDOS_I(inode)->i_pos);
247 nr = -EIO; 247 nr = -EIO;
@@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
252 if (nr < 0) 252 if (nr < 0)
253 goto out; 253 goto out;
254 else if (nr == FAT_ENT_FREE) { 254 else if (nr == FAT_ENT_FREE) {
255 fat_fs_panic(sb, "%s: invalid cluster chain" 255 fat_fs_error(sb, "%s: invalid cluster chain"
256 " (i_pos %lld)", __func__, 256 " (i_pos %lld)", __func__,
257 MSDOS_I(inode)->i_pos); 257 MSDOS_I(inode)->i_pos);
258 nr = -EIO; 258 nr = -EIO;
@@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
285 if (ret < 0) 285 if (ret < 0)
286 return ret; 286 return ret;
287 else if (ret == FAT_ENT_EOF) { 287 else if (ret == FAT_ENT_EOF) {
288 fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)", 288 fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
289 __func__, MSDOS_I(inode)->i_pos); 289 __func__, MSDOS_I(inode)->i_pos);
290 return -EIO; 290 return -EIO;
291 } 291 }
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 3a7f603b6982..7e7924c2ea30 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -1334,7 +1334,7 @@ found:
1334 goto error_remove; 1334 goto error_remove;
1335 } 1335 }
1336 if (dir->i_size & (sbi->cluster_size - 1)) { 1336 if (dir->i_size & (sbi->cluster_size - 1)) {
1337 fat_fs_panic(sb, "Odd directory size"); 1337 fat_fs_error(sb, "Odd directory size");
1338 dir->i_size = (dir->i_size + sbi->cluster_size - 1) 1338 dir->i_size = (dir->i_size + sbi->cluster_size - 1)
1339 & ~((loff_t)sbi->cluster_size - 1); 1339 & ~((loff_t)sbi->cluster_size - 1);
1340 } 1340 }
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index ea440d65819c..ed10896d5da5 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -17,6 +17,10 @@
17#define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ 17#define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */
18#define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ 18#define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */
19 19
20#define FAT_ERRORS_CONT 1 /* ignore error and continue */
21#define FAT_ERRORS_PANIC 2 /* panic on error */
22#define FAT_ERRORS_RO 3 /* remount r/o on error */
23
20struct fat_mount_options { 24struct fat_mount_options {
21 uid_t fs_uid; 25 uid_t fs_uid;
22 gid_t fs_gid; 26 gid_t fs_gid;
@@ -26,6 +30,7 @@ struct fat_mount_options {
26 char *iocharset; /* Charset used for filename input/display */ 30 char *iocharset; /* Charset used for filename input/display */
27 unsigned short shortname; /* flags for shortname display/create rule */ 31 unsigned short shortname; /* flags for shortname display/create rule */
28 unsigned char name_check; /* r = relaxed, n = normal, s = strict */ 32 unsigned char name_check; /* r = relaxed, n = normal, s = strict */
33 unsigned char errors; /* On error: continue, panic, remount-ro */
29 unsigned short allow_utime;/* permission for setting the [am]time */ 34 unsigned short allow_utime;/* permission for setting the [am]time */
30 unsigned quiet:1, /* set = fake successful chmods and chowns */ 35 unsigned quiet:1, /* set = fake successful chmods and chowns */
31 showexec:1, /* set = only set x bit for com/exe/bat */ 36 showexec:1, /* set = only set x bit for com/exe/bat */
@@ -310,7 +315,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
310extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, 315extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
311 struct inode *i2); 316 struct inode *i2);
312/* fat/misc.c */ 317/* fat/misc.c */
313extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) 318extern void fat_fs_error(struct super_block *s, const char *fmt, ...)
314 __attribute__ ((format (printf, 2, 3))) __cold; 319 __attribute__ ((format (printf, 2, 3))) __cold;
315extern void fat_clusters_flush(struct super_block *sb); 320extern void fat_clusters_flush(struct super_block *sb);
316extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); 321extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index da6eea47872f..60c31f7e678c 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -345,7 +345,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
345 345
346 if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { 346 if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
347 fatent_brelse(fatent); 347 fatent_brelse(fatent);
348 fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); 348 fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
349 return -EIO; 349 return -EIO;
350 } 350 }
351 351
@@ -557,7 +557,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
557 err = cluster; 557 err = cluster;
558 goto error; 558 goto error;
559 } else if (cluster == FAT_ENT_FREE) { 559 } else if (cluster == FAT_ENT_FREE) {
560 fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", 560 fat_fs_error(sb, "%s: deleting FAT entry beyond EOF",
561 __func__); 561 __func__);
562 err = -EIO; 562 err = -EIO;
563 goto error; 563 goto error;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 0a7f4a9918b3..6214287210f5 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -213,7 +213,7 @@ static int fat_free(struct inode *inode, int skip)
213 fatent_brelse(&fatent); 213 fatent_brelse(&fatent);
214 return 0; 214 return 0;
215 } else if (ret == FAT_ENT_FREE) { 215 } else if (ret == FAT_ENT_FREE) {
216 fat_fs_panic(sb, 216 fat_fs_error(sb,
217 "%s: invalid cluster chain (i_pos %lld)", 217 "%s: invalid cluster chain (i_pos %lld)",
218 __func__, MSDOS_I(inode)->i_pos); 218 __func__, MSDOS_I(inode)->i_pos);
219 ret = -EIO; 219 ret = -EIO;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 296785a0dec8..2b9052265e3e 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
76 return 0; 76 return 0;
77 77
78 if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { 78 if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
79 fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", 79 fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
80 MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); 80 MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
81 return -EIO; 81 return -EIO;
82 } 82 }
@@ -834,6 +834,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
834 seq_puts(m, ",flush"); 834 seq_puts(m, ",flush");
835 if (opts->tz_utc) 835 if (opts->tz_utc)
836 seq_puts(m, ",tz=UTC"); 836 seq_puts(m, ",tz=UTC");
837 if (opts->errors == FAT_ERRORS_CONT)
838 seq_puts(m, ",errors=continue");
839 else if (opts->errors == FAT_ERRORS_PANIC)
840 seq_puts(m, ",errors=panic");
841 else
842 seq_puts(m, ",errors=remount-ro");
837 843
838 return 0; 844 return 0;
839} 845}
@@ -846,7 +852,8 @@ enum {
846 Opt_charset, Opt_shortname_lower, Opt_shortname_win95, 852 Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
847 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, 853 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
848 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, 854 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
849 Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, 855 Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
856 Opt_err_panic, Opt_err_ro, Opt_err,
850}; 857};
851 858
852static const match_table_t fat_tokens = { 859static const match_table_t fat_tokens = {
@@ -869,6 +876,11 @@ static const match_table_t fat_tokens = {
869 {Opt_showexec, "showexec"}, 876 {Opt_showexec, "showexec"},
870 {Opt_debug, "debug"}, 877 {Opt_debug, "debug"},
871 {Opt_immutable, "sys_immutable"}, 878 {Opt_immutable, "sys_immutable"},
879 {Opt_flush, "flush"},
880 {Opt_tz_utc, "tz=UTC"},
881 {Opt_err_cont, "errors=continue"},
882 {Opt_err_panic, "errors=panic"},
883 {Opt_err_ro, "errors=remount-ro"},
872 {Opt_obsolate, "conv=binary"}, 884 {Opt_obsolate, "conv=binary"},
873 {Opt_obsolate, "conv=text"}, 885 {Opt_obsolate, "conv=text"},
874 {Opt_obsolate, "conv=auto"}, 886 {Opt_obsolate, "conv=auto"},
@@ -880,8 +892,6 @@ static const match_table_t fat_tokens = {
880 {Opt_obsolate, "cvf_format=%20s"}, 892 {Opt_obsolate, "cvf_format=%20s"},
881 {Opt_obsolate, "cvf_options=%100s"}, 893 {Opt_obsolate, "cvf_options=%100s"},
882 {Opt_obsolate, "posix"}, 894 {Opt_obsolate, "posix"},
883 {Opt_flush, "flush"},
884 {Opt_tz_utc, "tz=UTC"},
885 {Opt_err, NULL}, 895 {Opt_err, NULL},
886}; 896};
887static const match_table_t msdos_tokens = { 897static const match_table_t msdos_tokens = {
@@ -951,6 +961,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
951 opts->numtail = 1; 961 opts->numtail = 1;
952 opts->usefree = opts->nocase = 0; 962 opts->usefree = opts->nocase = 0;
953 opts->tz_utc = 0; 963 opts->tz_utc = 0;
964 opts->errors = FAT_ERRORS_RO;
954 *debug = 0; 965 *debug = 0;
955 966
956 if (!options) 967 if (!options)
@@ -1043,6 +1054,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
1043 case Opt_tz_utc: 1054 case Opt_tz_utc:
1044 opts->tz_utc = 1; 1055 opts->tz_utc = 1;
1045 break; 1056 break;
1057 case Opt_err_cont:
1058 opts->errors = FAT_ERRORS_CONT;
1059 break;
1060 case Opt_err_panic:
1061 opts->errors = FAT_ERRORS_PANIC;
1062 break;
1063 case Opt_err_ro:
1064 opts->errors = FAT_ERRORS_RO;
1065 break;
1046 1066
1047 /* msdos specific */ 1067 /* msdos specific */
1048 case Opt_dots: 1068 case Opt_dots:
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index ac39ebcc1496..a6c20473dfd7 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -12,14 +12,19 @@
12#include "fat.h" 12#include "fat.h"
13 13
14/* 14/*
15 * fat_fs_panic reports a severe file system problem and sets the file system 15 * fat_fs_error reports a file system problem that might indicate fa data
16 * read-only. The file system can be made writable again by remounting it. 16 * corruption/inconsistency. Depending on 'errors' mount option the
17 * panic() is called, or error message is printed FAT and nothing is done,
18 * or filesystem is remounted read-only (default behavior).
19 * In case the file system is remounted read-only, it can be made writable
20 * again by remounting it.
17 */ 21 */
18void fat_fs_panic(struct super_block *s, const char *fmt, ...) 22void fat_fs_error(struct super_block *s, const char *fmt, ...)
19{ 23{
24 struct fat_mount_options *opts = &MSDOS_SB(s)->options;
20 va_list args; 25 va_list args;
21 26
22 printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id); 27 printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
23 28
24 printk(KERN_ERR " "); 29 printk(KERN_ERR " ");
25 va_start(args, fmt); 30 va_start(args, fmt);
@@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...)
27 va_end(args); 32 va_end(args);
28 printk("\n"); 33 printk("\n");
29 34
30 if (!(s->s_flags & MS_RDONLY)) { 35 if (opts->errors == FAT_ERRORS_PANIC)
36 panic(" FAT fs panic from previous error\n");
37 else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) {
31 s->s_flags |= MS_RDONLY; 38 s->s_flags |= MS_RDONLY;
32 printk(KERN_ERR " File system has been set read-only\n"); 39 printk(KERN_ERR " File system has been set read-only\n");
33 } 40 }
34} 41}
35 42EXPORT_SYMBOL_GPL(fat_fs_error);
36EXPORT_SYMBOL_GPL(fat_fs_panic);
37 43
38/* Flushes the number of free clusters on FAT32 */ 44/* Flushes the number of free clusters on FAT32 */
39/* XXX: Need to write one per FSINFO block. Currently only writes 1 */ 45/* XXX: Need to write one per FSINFO block. Currently only writes 1 */
@@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
124 mark_inode_dirty(inode); 130 mark_inode_dirty(inode);
125 } 131 }
126 if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { 132 if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
127 fat_fs_panic(sb, "clusters badly computed (%d != %llu)", 133 fat_fs_error(sb, "clusters badly computed (%d != %llu)",
128 new_fclus, 134 new_fclus,
129 (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); 135 (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
130 fat_cache_inval_inode(inode); 136 fat_cache_inval_inode(inode);
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index da3f361a37dd..72f5c6402ef3 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -608,7 +608,7 @@ error_inode:
608 sinfo.bh = NULL; 608 sinfo.bh = NULL;
609 } 609 }
610 if (corrupt < 0) { 610 if (corrupt < 0) {
611 fat_fs_panic(new_dir->i_sb, 611 fat_fs_error(new_dir->i_sb,
612 "%s: Filesystem corrupted (i_pos %lld)", 612 "%s: Filesystem corrupted (i_pos %lld)",
613 __func__, sinfo.i_pos); 613 __func__, sinfo.i_pos);
614 } 614 }
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index a0e00e3a46e9..cb6ddb8c0bc2 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -1030,7 +1030,7 @@ error_inode:
1030 sinfo.bh = NULL; 1030 sinfo.bh = NULL;
1031 } 1031 }
1032 if (corrupt < 0) { 1032 if (corrupt < 0) {
1033 fat_fs_panic(new_dir->i_sb, 1033 fat_fs_error(new_dir->i_sb,
1034 "%s: Filesystem corrupted (i_pos %lld)", 1034 "%s: Filesystem corrupted (i_pos %lld)",
1035 __func__, sinfo.i_pos); 1035 __func__, sinfo.i_pos);
1036 } 1036 }