diff options
| author | Denis Karpov <ext-denis.2.karpov@nokia.com> | 2009-06-03 13:34:22 -0400 |
|---|---|---|
| committer | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2009-06-03 13:34:51 -0400 |
| commit | 85c7859190c4197a7c34066db14c25903c401187 (patch) | |
| tree | 9cf54e894f52eb1edfd35daeff66bfb5697b8360 /fs/fat | |
| parent | 9fa7eb283c5cdc2b0f4a8cfe6387ed82e5e9a3d3 (diff) | |
FAT: add 'errors' mount option
On severe errors FAT remounts itself in read-only mode. Allow to
specify FAT fs desired behavior through 'errors' mount option:
panic, continue or remount read-only.
`mount -t [fat|vfat] -o errors=[panic,remount-ro,continue] \
<bdev> <mount point>`
This is analog to ext2 fs 'errors' mount option.
Signed-off-by: Denis Karpov <ext-denis.2.karpov@nokia.com>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Diffstat (limited to 'fs/fat')
| -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 |
9 files changed, 53 insertions, 22 deletions
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index b4260229808..923990e4f16 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 3a7f603b698..7e7924c2ea3 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 ea440d65819..ed10896d5da 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 da6eea47872..60c31f7e678 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 0a7f4a9918b..6214287210f 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 296785a0dec..2b9052265e3 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 ac39ebcc149..a6c20473dfd 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 da3f361a37d..72f5c6402ef 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 a0e00e3a46e..cb6ddb8c0bc 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 | } |
