diff options
-rw-r--r-- | Documentation/filesystems/vfat.txt | 5 | ||||
-rw-r--r-- | fs/fat/cache.c | 6 | ||||
-rw-r--r-- | fs/fat/dir.c | 2 | ||||
-rw-r--r-- | fs/fat/fat.h | 7 | ||||
-rw-r--r-- | fs/fat/fatent.c | 4 | ||||
-rw-r--r-- | fs/fat/file.c | 2 | ||||
-rw-r--r-- | fs/fat/inode.c | 28 | ||||
-rw-r--r-- | fs/fat/misc.c | 22 | ||||
-rw-r--r-- | fs/fat/namei_msdos.c | 2 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 2 |
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 | ||
135 | errors=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 | ||
137 | TODO | 142 | TODO |
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 | |||
20 | struct fat_mount_options { | 24 | struct 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, | |||
310 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, | 315 | extern 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 */ |
313 | extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) | 318 | extern 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; |
315 | extern void fat_clusters_flush(struct super_block *sb); | 320 | extern void fat_clusters_flush(struct super_block *sb); |
316 | extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); | 321 | extern 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 | ||
852 | static const match_table_t fat_tokens = { | 859 | static 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 | }; |
887 | static const match_table_t msdos_tokens = { | 897 | static 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 | */ |
18 | void fat_fs_panic(struct super_block *s, const char *fmt, ...) | 22 | void 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 | 42 | EXPORT_SYMBOL_GPL(fat_fs_error); | |
36 | EXPORT_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 | } |