Commit 23059a0df5fad3d83b9a21fc2696a39148f49617

Authored by Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/hirofumi/fatfs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/hirofumi/fatfs-2.6:
  fat: split fat_generic_ioctl
  FAT: add 'errors' mount option

Showing 10 changed files Side-by-side Diff

Documentation/filesystems/vfat.txt
... ... @@ -132,6 +132,11 @@
132 132 If you want to use ATTR_RO as read-only flag even for
133 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 140 <bool>: 0,1,yes,no,true,false
136 141  
137 142 TODO
... ... @@ -241,7 +241,7 @@
241 241 while (*fclus < cluster) {
242 242 /* prevent the infinite loop of cluster chain */
243 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 245 " (i_pos %lld)", __func__,
246 246 MSDOS_I(inode)->i_pos);
247 247 nr = -EIO;
... ... @@ -252,7 +252,7 @@
252 252 if (nr < 0)
253 253 goto out;
254 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 256 " (i_pos %lld)", __func__,
257 257 MSDOS_I(inode)->i_pos);
258 258 nr = -EIO;
... ... @@ -285,7 +285,7 @@
285 285 if (ret < 0)
286 286 return ret;
287 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 289 __func__, MSDOS_I(inode)->i_pos);
290 290 return -EIO;
291 291 }
... ... @@ -1334,7 +1334,7 @@
1334 1334 goto error_remove;
1335 1335 }
1336 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 1338 dir->i_size = (dir->i_size + sbi->cluster_size - 1)
1339 1339 & ~((loff_t)sbi->cluster_size - 1);
1340 1340 }
... ... @@ -17,6 +17,10 @@
17 17 #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */
18 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 24 struct fat_mount_options {
21 25 uid_t fs_uid;
22 26 gid_t fs_gid;
... ... @@ -26,6 +30,7 @@
26 30 char *iocharset; /* Charset used for filename input/display */
27 31 unsigned short shortname; /* flags for shortname display/create rule */
28 32 unsigned char name_check; /* r = relaxed, n = normal, s = strict */
  33 + unsigned char errors; /* On error: continue, panic, remount-ro */
29 34 unsigned short allow_utime;/* permission for setting the [am]time */
30 35 unsigned quiet:1, /* set = fake successful chmods and chowns */
31 36 showexec:1, /* set = only set x bit for com/exe/bat */
... ... @@ -316,7 +321,7 @@
316 321 extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
317 322 struct inode *i2);
318 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 325 __attribute__ ((format (printf, 2, 3))) __cold;
321 326 extern void fat_clusters_flush(struct super_block *sb);
322 327 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
... ... @@ -348,7 +348,7 @@
348 348  
349 349 if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
350 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 352 return -EIO;
353 353 }
354 354  
... ... @@ -560,7 +560,7 @@
560 560 err = cluster;
561 561 goto error;
562 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 564 __func__);
565 565 err = -EIO;
566 566 goto error;
... ... @@ -18,106 +18,112 @@
18 18 #include <linux/security.h>
19 19 #include "fat.h"
20 20  
21   -int fat_generic_ioctl(struct inode *inode, struct file *filp,
22   - unsigned int cmd, unsigned long arg)
  21 +static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
23 22 {
24   - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
25   - u32 __user *user_attr = (u32 __user *)arg;
  23 + u32 attr;
26 24  
27   - switch (cmd) {
28   - case FAT_IOCTL_GET_ATTRIBUTES:
29   - {
30   - u32 attr;
  25 + mutex_lock(&inode->i_mutex);
  26 + attr = fat_make_attrs(inode);
  27 + mutex_unlock(&inode->i_mutex);
31 28  
32   - mutex_lock(&inode->i_mutex);
33   - attr = fat_make_attrs(inode);
34   - mutex_unlock(&inode->i_mutex);
  29 + return put_user(attr, user_attr);
  30 +}
35 31  
36   - return put_user(attr, user_attr);
37   - }
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;
  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;
  35 + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  36 + int is_dir = S_ISDIR(inode->i_mode);
  37 + u32 attr, oldattr;
  38 + struct iattr ia;
  39 + int err;
43 40  
44   - err = get_user(attr, user_attr);
45   - if (err)
46   - return err;
  41 + err = get_user(attr, user_attr);
  42 + if (err)
  43 + goto out;
47 44  
48   - mutex_lock(&inode->i_mutex);
  45 + mutex_lock(&inode->i_mutex);
  46 + err = mnt_want_write(file->f_path.mnt);
  47 + if (err)
  48 + goto out_unlock_inode;
49 49  
50   - err = mnt_want_write(filp->f_path.mnt);
51   - if (err)
52   - goto up_no_drop_write;
  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);
53 61  
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);
  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));
  70 + }
65 71  
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   - }
  72 + /* The root directory has no attributes */
  73 + if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
  74 + err = -EINVAL;
  75 + goto out_drop_write;
  76 + }
75 77  
76   - /* The root directory has no attributes */
77   - if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
78   - err = -EINVAL;
79   - goto up;
80   - }
  78 + if (sbi->options.sys_immutable &&
  79 + ((attr | oldattr) & ATTR_SYS) &&
  80 + !capable(CAP_LINUX_IMMUTABLE)) {
  81 + err = -EPERM;
  82 + goto out_drop_write;
  83 + }
81 84  
82   - if (sbi->options.sys_immutable) {
83   - if ((attr | oldattr) & ATTR_SYS) {
84   - if (!capable(CAP_LINUX_IMMUTABLE)) {
85   - err = -EPERM;
86   - goto up;
87   - }
88   - }
89   - }
  85 + /*
  86 + * The security check is questionable... We single
  87 + * out the RO attribute for checking by the security
  88 + * module, just because it maps to a file mode.
  89 + */
  90 + err = security_inode_setattr(file->f_path.dentry, &ia);
  91 + if (err)
  92 + goto out_drop_write;
90 93  
91   - /*
92   - * The security check is questionable... We single
93   - * out the RO attribute for checking by the security
94   - * module, just because it maps to a file mode.
95   - */
96   - err = security_inode_setattr(filp->f_path.dentry, &ia);
97   - if (err)
98   - goto up;
  94 + /* This MUST be done before doing anything irreversible... */
  95 + err = fat_setattr(file->f_path.dentry, &ia);
  96 + if (err)
  97 + goto out_drop_write;
99 98  
100   - /* This MUST be done before doing anything irreversible... */
101   - err = fat_setattr(filp->f_path.dentry, &ia);
102   - if (err)
103   - goto up;
  99 + fsnotify_change(file->f_path.dentry, ia.ia_valid);
  100 + if (sbi->options.sys_immutable) {
  101 + if (attr & ATTR_SYS)
  102 + inode->i_flags |= S_IMMUTABLE;
  103 + else
  104 + inode->i_flags &= S_IMMUTABLE;
  105 + }
104 106  
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   - }
  107 + fat_save_attrs(inode, attr);
  108 + mark_inode_dirty(inode);
  109 +out_drop_write:
  110 + mnt_drop_write(file->f_path.mnt);
  111 +out_unlock_inode:
  112 + mutex_unlock(&inode->i_mutex);
  113 +out:
  114 + return err;
  115 +}
112 116  
113   - fat_save_attrs(inode, attr);
114   - mark_inode_dirty(inode);
115   -up:
116   - mnt_drop_write(filp->f_path.mnt);
117   -up_no_drop_write:
118   - mutex_unlock(&inode->i_mutex);
119   - return err;
120   - }
  117 +int fat_generic_ioctl(struct inode *inode, struct file *filp,
  118 + unsigned int cmd, unsigned long arg)
  119 +{
  120 + u32 __user *user_attr = (u32 __user *)arg;
  121 +
  122 + switch (cmd) {
  123 + case FAT_IOCTL_GET_ATTRIBUTES:
  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 127 default:
122 128 return -ENOTTY; /* Inappropriate ioctl for device */
123 129 }
... ... @@ -225,7 +231,7 @@
225 231 fatent_brelse(&fatent);
226 232 return 0;
227 233 } else if (ret == FAT_ENT_FREE) {
228   - fat_fs_panic(sb,
  234 + fat_fs_error(sb,
229 235 "%s: invalid cluster chain (i_pos %lld)",
230 236 __func__, MSDOS_I(inode)->i_pos);
231 237 ret = -EIO;
... ... @@ -76,7 +76,7 @@
76 76 return 0;
77 77  
78 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 80 MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
81 81 return -EIO;
82 82 }
... ... @@ -856,6 +856,12 @@
856 856 seq_puts(m, ",flush");
857 857 if (opts->tz_utc)
858 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 866 return 0;
861 867 }
... ... @@ -868,7 +874,8 @@
868 874 Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
869 875 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
870 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 881 static const match_table_t fat_tokens = {
... ... @@ -891,6 +898,11 @@
891 898 {Opt_showexec, "showexec"},
892 899 {Opt_debug, "debug"},
893 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 906 {Opt_obsolate, "conv=binary"},
895 907 {Opt_obsolate, "conv=text"},
896 908 {Opt_obsolate, "conv=auto"},
... ... @@ -902,8 +914,6 @@
902 914 {Opt_obsolate, "cvf_format=%20s"},
903 915 {Opt_obsolate, "cvf_options=%100s"},
904 916 {Opt_obsolate, "posix"},
905   - {Opt_flush, "flush"},
906   - {Opt_tz_utc, "tz=UTC"},
907 917 {Opt_err, NULL},
908 918 };
909 919 static const match_table_t msdos_tokens = {
... ... @@ -973,6 +983,7 @@
973 983 opts->numtail = 1;
974 984 opts->usefree = opts->nocase = 0;
975 985 opts->tz_utc = 0;
  986 + opts->errors = FAT_ERRORS_RO;
976 987 *debug = 0;
977 988  
978 989 if (!options)
... ... @@ -1064,6 +1075,15 @@
1064 1075 break;
1065 1076 case Opt_tz_utc:
1066 1077 opts->tz_utc = 1;
  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;
1067 1087 break;
1068 1088  
1069 1089 /* msdos specific */
... ... @@ -12,14 +12,19 @@
12 12 #include "fat.h"
13 13  
14 14 /*
15   - * fat_fs_panic reports a severe file system problem and sets the file system
16   - * read-only. The file system can be made writable again by remounting it.
  15 + * fat_fs_error reports a file system problem that might indicate fa data
  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 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 29 printk(KERN_ERR " ");
25 30 va_start(args, fmt);
26 31  
27 32  
... ... @@ -27,14 +32,15 @@
27 32 va_end(args);
28 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 38 s->s_flags |= MS_RDONLY;
32 39 printk(KERN_ERR " File system has been set read-only\n");
33 40 }
34 41 }
  42 +EXPORT_SYMBOL_GPL(fat_fs_error);
35 43  
36   -EXPORT_SYMBOL_GPL(fat_fs_panic);
37   -
38 44 /* Flushes the number of free clusters on FAT32 */
39 45 /* XXX: Need to write one per FSINFO block. Currently only writes 1 */
40 46 void fat_clusters_flush(struct super_block *sb)
... ... @@ -124,7 +130,7 @@
124 130 mark_inode_dirty(inode);
125 131 }
126 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 134 new_fclus,
129 135 (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
130 136 fat_cache_inval_inode(inode);
fs/fat/namei_msdos.c
... ... @@ -608,7 +608,7 @@
608 608 sinfo.bh = NULL;
609 609 }
610 610 if (corrupt < 0) {
611   - fat_fs_panic(new_dir->i_sb,
  611 + fat_fs_error(new_dir->i_sb,
612 612 "%s: Filesystem corrupted (i_pos %lld)",
613 613 __func__, sinfo.i_pos);
614 614 }
... ... @@ -1030,7 +1030,7 @@
1030 1030 sinfo.bh = NULL;
1031 1031 }
1032 1032 if (corrupt < 0) {
1033   - fat_fs_panic(new_dir->i_sb,
  1033 + fat_fs_error(new_dir->i_sb,
1034 1034 "%s: Filesystem corrupted (i_pos %lld)",
1035 1035 __func__, sinfo.i_pos);
1036 1036 }