diff options
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 | 184 | ||||
-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, 147 insertions, 110 deletions
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 f3500294eec5..3b8e71b412fd 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 e4d88527b5dd..adb0e72a176d 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 */ |
@@ -316,7 +321,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
316 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, | 321 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, |
317 | struct inode *i2); | 322 | struct inode *i2); |
318 | /* fat/misc.c */ | 323 | /* fat/misc.c */ |
319 | extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) | 324 | extern void fat_fs_error(struct super_block *s, const char *fmt, ...) |
320 | __attribute__ ((format (printf, 2, 3))) __cold; | 325 | __attribute__ ((format (printf, 2, 3))) __cold; |
321 | extern void fat_clusters_flush(struct super_block *sb); | 326 | extern void fat_clusters_flush(struct super_block *sb); |
322 | extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); | 327 | 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 618f5305c2e4..a81037721a6f 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) | |||
348 | 348 | ||
349 | if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { | 349 | if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { |
350 | fatent_brelse(fatent); | 350 | fatent_brelse(fatent); |
351 | fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); | 351 | fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); |
352 | return -EIO; | 352 | return -EIO; |
353 | } | 353 | } |
354 | 354 | ||
@@ -560,7 +560,7 @@ int fat_free_clusters(struct inode *inode, int cluster) | |||
560 | err = cluster; | 560 | err = cluster; |
561 | goto error; | 561 | goto error; |
562 | } else if (cluster == FAT_ENT_FREE) { | 562 | } else if (cluster == FAT_ENT_FREE) { |
563 | fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", | 563 | fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", |
564 | __func__); | 564 | __func__); |
565 | err = -EIO; | 565 | err = -EIO; |
566 | goto error; | 566 | goto error; |
diff --git a/fs/fat/file.c b/fs/fat/file.c index e955a56b4e5e..b28ea646ff60 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -18,106 +18,112 @@ | |||
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include "fat.h" | 19 | #include "fat.h" |
20 | 20 | ||
21 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 21 | static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) |
22 | unsigned int cmd, unsigned long arg) | ||
23 | { | 22 | { |
23 | u32 attr; | ||
24 | |||
25 | mutex_lock(&inode->i_mutex); | ||
26 | attr = fat_make_attrs(inode); | ||
27 | mutex_unlock(&inode->i_mutex); | ||
28 | |||
29 | return put_user(attr, user_attr); | ||
30 | } | ||
31 | |||
32 | static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) | ||
33 | { | ||
34 | struct inode *inode = file->f_path.dentry->d_inode; | ||
24 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 35 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
25 | u32 __user *user_attr = (u32 __user *)arg; | 36 | int is_dir = S_ISDIR(inode->i_mode); |
37 | u32 attr, oldattr; | ||
38 | struct iattr ia; | ||
39 | int err; | ||
26 | 40 | ||
27 | switch (cmd) { | 41 | err = get_user(attr, user_attr); |
28 | case FAT_IOCTL_GET_ATTRIBUTES: | 42 | if (err) |
29 | { | 43 | goto out; |
30 | u32 attr; | ||
31 | 44 | ||
32 | mutex_lock(&inode->i_mutex); | 45 | mutex_lock(&inode->i_mutex); |
33 | attr = fat_make_attrs(inode); | 46 | err = mnt_want_write(file->f_path.mnt); |
34 | mutex_unlock(&inode->i_mutex); | 47 | if (err) |
48 | goto out_unlock_inode; | ||
35 | 49 | ||
36 | return put_user(attr, user_attr); | 50 | /* |
51 | * ATTR_VOLUME and ATTR_DIR cannot be changed; this also | ||
52 | * prevents the user from turning us into a VFAT | ||
53 | * longname entry. Also, we obviously can't set | ||
54 | * any of the NTFS attributes in the high 24 bits. | ||
55 | */ | ||
56 | attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); | ||
57 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | ||
58 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | ||
59 | (is_dir ? ATTR_DIR : 0); | ||
60 | oldattr = fat_make_attrs(inode); | ||
61 | |||
62 | /* Equivalent to a chmod() */ | ||
63 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
64 | ia.ia_ctime = current_fs_time(inode->i_sb); | ||
65 | if (is_dir) | ||
66 | ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); | ||
67 | else { | ||
68 | ia.ia_mode = fat_make_mode(sbi, attr, | ||
69 | S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); | ||
37 | } | 70 | } |
38 | case FAT_IOCTL_SET_ATTRIBUTES: | ||
39 | { | ||
40 | u32 attr, oldattr; | ||
41 | int err, is_dir = S_ISDIR(inode->i_mode); | ||
42 | struct iattr ia; | ||
43 | 71 | ||
44 | err = get_user(attr, user_attr); | 72 | /* The root directory has no attributes */ |
45 | if (err) | 73 | if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { |
46 | return err; | 74 | err = -EINVAL; |
75 | goto out_drop_write; | ||
76 | } | ||
47 | 77 | ||
48 | mutex_lock(&inode->i_mutex); | 78 | if (sbi->options.sys_immutable && |
49 | 79 | ((attr | oldattr) & ATTR_SYS) && | |
50 | err = mnt_want_write(filp->f_path.mnt); | 80 | !capable(CAP_LINUX_IMMUTABLE)) { |
51 | if (err) | 81 | err = -EPERM; |
52 | goto up_no_drop_write; | 82 | goto out_drop_write; |
53 | 83 | } | |
54 | /* | ||
55 | * ATTR_VOLUME and ATTR_DIR cannot be changed; this also | ||
56 | * prevents the user from turning us into a VFAT | ||
57 | * longname entry. Also, we obviously can't set | ||
58 | * any of the NTFS attributes in the high 24 bits. | ||
59 | */ | ||
60 | attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); | ||
61 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | ||
62 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | ||
63 | (is_dir ? ATTR_DIR : 0); | ||
64 | oldattr = fat_make_attrs(inode); | ||
65 | |||
66 | /* Equivalent to a chmod() */ | ||
67 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
68 | ia.ia_ctime = current_fs_time(inode->i_sb); | ||
69 | if (is_dir) | ||
70 | ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); | ||
71 | else { | ||
72 | ia.ia_mode = fat_make_mode(sbi, attr, | ||
73 | S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); | ||
74 | } | ||
75 | 84 | ||
76 | /* The root directory has no attributes */ | 85 | /* |
77 | if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { | 86 | * The security check is questionable... We single |
78 | err = -EINVAL; | 87 | * out the RO attribute for checking by the security |
79 | goto up; | 88 | * module, just because it maps to a file mode. |
80 | } | 89 | */ |
90 | err = security_inode_setattr(file->f_path.dentry, &ia); | ||
91 | if (err) | ||
92 | goto out_drop_write; | ||
81 | 93 | ||
82 | if (sbi->options.sys_immutable) { | 94 | /* This MUST be done before doing anything irreversible... */ |
83 | if ((attr | oldattr) & ATTR_SYS) { | 95 | err = fat_setattr(file->f_path.dentry, &ia); |
84 | if (!capable(CAP_LINUX_IMMUTABLE)) { | 96 | if (err) |
85 | err = -EPERM; | 97 | goto out_drop_write; |
86 | goto up; | 98 | |
87 | } | 99 | fsnotify_change(file->f_path.dentry, ia.ia_valid); |
88 | } | 100 | if (sbi->options.sys_immutable) { |
89 | } | 101 | if (attr & ATTR_SYS) |
102 | inode->i_flags |= S_IMMUTABLE; | ||
103 | else | ||
104 | inode->i_flags &= S_IMMUTABLE; | ||
105 | } | ||
90 | 106 | ||
91 | /* | 107 | fat_save_attrs(inode, attr); |
92 | * The security check is questionable... We single | 108 | mark_inode_dirty(inode); |
93 | * out the RO attribute for checking by the security | 109 | out_drop_write: |
94 | * module, just because it maps to a file mode. | 110 | mnt_drop_write(file->f_path.mnt); |
95 | */ | 111 | out_unlock_inode: |
96 | err = security_inode_setattr(filp->f_path.dentry, &ia); | 112 | mutex_unlock(&inode->i_mutex); |
97 | if (err) | 113 | out: |
98 | goto up; | 114 | return err; |
99 | 115 | } | |
100 | /* This MUST be done before doing anything irreversible... */ | ||
101 | err = fat_setattr(filp->f_path.dentry, &ia); | ||
102 | if (err) | ||
103 | goto up; | ||
104 | |||
105 | fsnotify_change(filp->f_path.dentry, ia.ia_valid); | ||
106 | if (sbi->options.sys_immutable) { | ||
107 | if (attr & ATTR_SYS) | ||
108 | inode->i_flags |= S_IMMUTABLE; | ||
109 | else | ||
110 | inode->i_flags &= S_IMMUTABLE; | ||
111 | } | ||
112 | 116 | ||
113 | fat_save_attrs(inode, attr); | 117 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
114 | mark_inode_dirty(inode); | 118 | unsigned int cmd, unsigned long arg) |
115 | up: | 119 | { |
116 | mnt_drop_write(filp->f_path.mnt); | 120 | u32 __user *user_attr = (u32 __user *)arg; |
117 | up_no_drop_write: | 121 | |
118 | mutex_unlock(&inode->i_mutex); | 122 | switch (cmd) { |
119 | return err; | 123 | case FAT_IOCTL_GET_ATTRIBUTES: |
120 | } | 124 | return fat_ioctl_get_attributes(inode, user_attr); |
125 | case FAT_IOCTL_SET_ATTRIBUTES: | ||
126 | return fat_ioctl_set_attributes(filp, user_attr); | ||
121 | default: | 127 | default: |
122 | return -ENOTTY; /* Inappropriate ioctl for device */ | 128 | return -ENOTTY; /* Inappropriate ioctl for device */ |
123 | } | 129 | } |
@@ -225,7 +231,7 @@ static int fat_free(struct inode *inode, int skip) | |||
225 | fatent_brelse(&fatent); | 231 | fatent_brelse(&fatent); |
226 | return 0; | 232 | return 0; |
227 | } else if (ret == FAT_ENT_FREE) { | 233 | } else if (ret == FAT_ENT_FREE) { |
228 | fat_fs_panic(sb, | 234 | fat_fs_error(sb, |
229 | "%s: invalid cluster chain (i_pos %lld)", | 235 | "%s: invalid cluster chain (i_pos %lld)", |
230 | __func__, MSDOS_I(inode)->i_pos); | 236 | __func__, MSDOS_I(inode)->i_pos); |
231 | ret = -EIO; | 237 | ret = -EIO; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 51a5ecf9000a..304b411cb8bc 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 | } |
@@ -856,6 +856,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
856 | seq_puts(m, ",flush"); | 856 | seq_puts(m, ",flush"); |
857 | if (opts->tz_utc) | 857 | if (opts->tz_utc) |
858 | seq_puts(m, ",tz=UTC"); | 858 | seq_puts(m, ",tz=UTC"); |
859 | if (opts->errors == FAT_ERRORS_CONT) | ||
860 | seq_puts(m, ",errors=continue"); | ||
861 | else if (opts->errors == FAT_ERRORS_PANIC) | ||
862 | seq_puts(m, ",errors=panic"); | ||
863 | else | ||
864 | seq_puts(m, ",errors=remount-ro"); | ||
859 | 865 | ||
860 | return 0; | 866 | return 0; |
861 | } | 867 | } |
@@ -868,7 +874,8 @@ enum { | |||
868 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 874 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
869 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 875 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
870 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 876 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
871 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, | 877 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, |
878 | Opt_err_panic, Opt_err_ro, Opt_err, | ||
872 | }; | 879 | }; |
873 | 880 | ||
874 | static const match_table_t fat_tokens = { | 881 | static const match_table_t fat_tokens = { |
@@ -891,6 +898,11 @@ static const match_table_t fat_tokens = { | |||
891 | {Opt_showexec, "showexec"}, | 898 | {Opt_showexec, "showexec"}, |
892 | {Opt_debug, "debug"}, | 899 | {Opt_debug, "debug"}, |
893 | {Opt_immutable, "sys_immutable"}, | 900 | {Opt_immutable, "sys_immutable"}, |
901 | {Opt_flush, "flush"}, | ||
902 | {Opt_tz_utc, "tz=UTC"}, | ||
903 | {Opt_err_cont, "errors=continue"}, | ||
904 | {Opt_err_panic, "errors=panic"}, | ||
905 | {Opt_err_ro, "errors=remount-ro"}, | ||
894 | {Opt_obsolate, "conv=binary"}, | 906 | {Opt_obsolate, "conv=binary"}, |
895 | {Opt_obsolate, "conv=text"}, | 907 | {Opt_obsolate, "conv=text"}, |
896 | {Opt_obsolate, "conv=auto"}, | 908 | {Opt_obsolate, "conv=auto"}, |
@@ -902,8 +914,6 @@ static const match_table_t fat_tokens = { | |||
902 | {Opt_obsolate, "cvf_format=%20s"}, | 914 | {Opt_obsolate, "cvf_format=%20s"}, |
903 | {Opt_obsolate, "cvf_options=%100s"}, | 915 | {Opt_obsolate, "cvf_options=%100s"}, |
904 | {Opt_obsolate, "posix"}, | 916 | {Opt_obsolate, "posix"}, |
905 | {Opt_flush, "flush"}, | ||
906 | {Opt_tz_utc, "tz=UTC"}, | ||
907 | {Opt_err, NULL}, | 917 | {Opt_err, NULL}, |
908 | }; | 918 | }; |
909 | static const match_table_t msdos_tokens = { | 919 | static const match_table_t msdos_tokens = { |
@@ -973,6 +983,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
973 | opts->numtail = 1; | 983 | opts->numtail = 1; |
974 | opts->usefree = opts->nocase = 0; | 984 | opts->usefree = opts->nocase = 0; |
975 | opts->tz_utc = 0; | 985 | opts->tz_utc = 0; |
986 | opts->errors = FAT_ERRORS_RO; | ||
976 | *debug = 0; | 987 | *debug = 0; |
977 | 988 | ||
978 | if (!options) | 989 | if (!options) |
@@ -1065,6 +1076,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1065 | case Opt_tz_utc: | 1076 | case Opt_tz_utc: |
1066 | opts->tz_utc = 1; | 1077 | opts->tz_utc = 1; |
1067 | break; | 1078 | break; |
1079 | case Opt_err_cont: | ||
1080 | opts->errors = FAT_ERRORS_CONT; | ||
1081 | break; | ||
1082 | case Opt_err_panic: | ||
1083 | opts->errors = FAT_ERRORS_PANIC; | ||
1084 | break; | ||
1085 | case Opt_err_ro: | ||
1086 | opts->errors = FAT_ERRORS_RO; | ||
1087 | break; | ||
1068 | 1088 | ||
1069 | /* msdos specific */ | 1089 | /* msdos specific */ |
1070 | case Opt_dots: | 1090 | 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 20f522861355..82f88733b681 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 b50ecbe97f83..8d6fdcfd41df 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 | } |