Commit 037369b872940cd923835a0a589763180c4a36bc
Committed by
Linus Torvalds
1 parent
01d6e08711
Exists in
smarct4x-processor-sdk-04.01.00.06
and in
1 other branch
hpfs: implement the show_options method
The HPFS filesystem used generic_show_options to produce string that is displayed in /proc/mounts. However, there is a problem that the options may disappear after remount. If we mount the filesystem with option1 and then remount it with option2, /proc/mounts should show both option1 and option2, however it only shows option2 because the whole option string is replaced with replace_mount_options in hpfs_remount_fs. To fix this bug, implement the hpfs_show_options function that prints options that are currently selected. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 32 additions and 11 deletions Inline Diff
fs/hpfs/super.c
1 | /* | 1 | /* |
2 | * linux/fs/hpfs/super.c | 2 | * linux/fs/hpfs/super.c |
3 | * | 3 | * |
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | 4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 |
5 | * | 5 | * |
6 | * mounting, unmounting, error handling | 6 | * mounting, unmounting, error handling |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "hpfs_fn.h" | 9 | #include "hpfs_fn.h" |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/parser.h> | 11 | #include <linux/parser.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/statfs.h> | 13 | #include <linux/statfs.h> |
14 | #include <linux/magic.h> | 14 | #include <linux/magic.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/bitmap.h> | 16 | #include <linux/bitmap.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/seq_file.h> | ||
18 | 19 | ||
19 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ | 20 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ |
20 | 21 | ||
21 | static void mark_dirty(struct super_block *s, int remount) | 22 | static void mark_dirty(struct super_block *s, int remount) |
22 | { | 23 | { |
23 | if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) { | 24 | if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) { |
24 | struct buffer_head *bh; | 25 | struct buffer_head *bh; |
25 | struct hpfs_spare_block *sb; | 26 | struct hpfs_spare_block *sb; |
26 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { | 27 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { |
27 | sb->dirty = 1; | 28 | sb->dirty = 1; |
28 | sb->old_wrote = 0; | 29 | sb->old_wrote = 0; |
29 | mark_buffer_dirty(bh); | 30 | mark_buffer_dirty(bh); |
30 | sync_dirty_buffer(bh); | 31 | sync_dirty_buffer(bh); |
31 | brelse(bh); | 32 | brelse(bh); |
32 | } | 33 | } |
33 | } | 34 | } |
34 | } | 35 | } |
35 | 36 | ||
36 | /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there | 37 | /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there |
37 | were errors) */ | 38 | were errors) */ |
38 | 39 | ||
39 | static void unmark_dirty(struct super_block *s) | 40 | static void unmark_dirty(struct super_block *s) |
40 | { | 41 | { |
41 | struct buffer_head *bh; | 42 | struct buffer_head *bh; |
42 | struct hpfs_spare_block *sb; | 43 | struct hpfs_spare_block *sb; |
43 | if (s->s_flags & MS_RDONLY) return; | 44 | if (s->s_flags & MS_RDONLY) return; |
44 | sync_blockdev(s->s_bdev); | 45 | sync_blockdev(s->s_bdev); |
45 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { | 46 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { |
46 | sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error; | 47 | sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error; |
47 | sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error; | 48 | sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error; |
48 | mark_buffer_dirty(bh); | 49 | mark_buffer_dirty(bh); |
49 | sync_dirty_buffer(bh); | 50 | sync_dirty_buffer(bh); |
50 | brelse(bh); | 51 | brelse(bh); |
51 | } | 52 | } |
52 | } | 53 | } |
53 | 54 | ||
54 | /* Filesystem error... */ | 55 | /* Filesystem error... */ |
55 | void hpfs_error(struct super_block *s, const char *fmt, ...) | 56 | void hpfs_error(struct super_block *s, const char *fmt, ...) |
56 | { | 57 | { |
57 | struct va_format vaf; | 58 | struct va_format vaf; |
58 | va_list args; | 59 | va_list args; |
59 | 60 | ||
60 | va_start(args, fmt); | 61 | va_start(args, fmt); |
61 | 62 | ||
62 | vaf.fmt = fmt; | 63 | vaf.fmt = fmt; |
63 | vaf.va = &args; | 64 | vaf.va = &args; |
64 | 65 | ||
65 | pr_err("filesystem error: %pV", &vaf); | 66 | pr_err("filesystem error: %pV", &vaf); |
66 | 67 | ||
67 | va_end(args); | 68 | va_end(args); |
68 | 69 | ||
69 | if (!hpfs_sb(s)->sb_was_error) { | 70 | if (!hpfs_sb(s)->sb_was_error) { |
70 | if (hpfs_sb(s)->sb_err == 2) { | 71 | if (hpfs_sb(s)->sb_err == 2) { |
71 | pr_cont("; crashing the system because you wanted it\n"); | 72 | pr_cont("; crashing the system because you wanted it\n"); |
72 | mark_dirty(s, 0); | 73 | mark_dirty(s, 0); |
73 | panic("HPFS panic"); | 74 | panic("HPFS panic"); |
74 | } else if (hpfs_sb(s)->sb_err == 1) { | 75 | } else if (hpfs_sb(s)->sb_err == 1) { |
75 | if (s->s_flags & MS_RDONLY) | 76 | if (s->s_flags & MS_RDONLY) |
76 | pr_cont("; already mounted read-only\n"); | 77 | pr_cont("; already mounted read-only\n"); |
77 | else { | 78 | else { |
78 | pr_cont("; remounting read-only\n"); | 79 | pr_cont("; remounting read-only\n"); |
79 | mark_dirty(s, 0); | 80 | mark_dirty(s, 0); |
80 | s->s_flags |= MS_RDONLY; | 81 | s->s_flags |= MS_RDONLY; |
81 | } | 82 | } |
82 | } else if (s->s_flags & MS_RDONLY) | 83 | } else if (s->s_flags & MS_RDONLY) |
83 | pr_cont("; going on - but anything won't be destroyed because it's read-only\n"); | 84 | pr_cont("; going on - but anything won't be destroyed because it's read-only\n"); |
84 | else | 85 | else |
85 | pr_cont("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n"); | 86 | pr_cont("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n"); |
86 | } else | 87 | } else |
87 | pr_cont("\n"); | 88 | pr_cont("\n"); |
88 | hpfs_sb(s)->sb_was_error = 1; | 89 | hpfs_sb(s)->sb_was_error = 1; |
89 | } | 90 | } |
90 | 91 | ||
91 | /* | 92 | /* |
92 | * A little trick to detect cycles in many hpfs structures and don't let the | 93 | * A little trick to detect cycles in many hpfs structures and don't let the |
93 | * kernel crash on corrupted filesystem. When first called, set c2 to 0. | 94 | * kernel crash on corrupted filesystem. When first called, set c2 to 0. |
94 | * | 95 | * |
95 | * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories | 96 | * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories |
96 | * nested each in other, chkdsk locked up happilly. | 97 | * nested each in other, chkdsk locked up happilly. |
97 | */ | 98 | */ |
98 | 99 | ||
99 | int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, | 100 | int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, |
100 | char *msg) | 101 | char *msg) |
101 | { | 102 | { |
102 | if (*c2 && *c1 == key) { | 103 | if (*c2 && *c1 == key) { |
103 | hpfs_error(s, "cycle detected on key %08x in %s", key, msg); | 104 | hpfs_error(s, "cycle detected on key %08x in %s", key, msg); |
104 | return 1; | 105 | return 1; |
105 | } | 106 | } |
106 | (*c2)++; | 107 | (*c2)++; |
107 | if (!((*c2 - 1) & *c2)) *c1 = key; | 108 | if (!((*c2 - 1) & *c2)) *c1 = key; |
108 | return 0; | 109 | return 0; |
109 | } | 110 | } |
110 | 111 | ||
111 | static void free_sbi(struct hpfs_sb_info *sbi) | 112 | static void free_sbi(struct hpfs_sb_info *sbi) |
112 | { | 113 | { |
113 | kfree(sbi->sb_cp_table); | 114 | kfree(sbi->sb_cp_table); |
114 | kfree(sbi->sb_bmp_dir); | 115 | kfree(sbi->sb_bmp_dir); |
115 | kfree(sbi); | 116 | kfree(sbi); |
116 | } | 117 | } |
117 | 118 | ||
118 | static void lazy_free_sbi(struct rcu_head *rcu) | 119 | static void lazy_free_sbi(struct rcu_head *rcu) |
119 | { | 120 | { |
120 | free_sbi(container_of(rcu, struct hpfs_sb_info, rcu)); | 121 | free_sbi(container_of(rcu, struct hpfs_sb_info, rcu)); |
121 | } | 122 | } |
122 | 123 | ||
123 | static void hpfs_put_super(struct super_block *s) | 124 | static void hpfs_put_super(struct super_block *s) |
124 | { | 125 | { |
125 | hpfs_lock(s); | 126 | hpfs_lock(s); |
126 | unmark_dirty(s); | 127 | unmark_dirty(s); |
127 | hpfs_unlock(s); | 128 | hpfs_unlock(s); |
128 | call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi); | 129 | call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi); |
129 | } | 130 | } |
130 | 131 | ||
131 | static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) | 132 | static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) |
132 | { | 133 | { |
133 | struct quad_buffer_head qbh; | 134 | struct quad_buffer_head qbh; |
134 | unsigned long *bits; | 135 | unsigned long *bits; |
135 | unsigned count; | 136 | unsigned count; |
136 | 137 | ||
137 | bits = hpfs_map_4sectors(s, secno, &qbh, 0); | 138 | bits = hpfs_map_4sectors(s, secno, &qbh, 0); |
138 | if (!bits) | 139 | if (!bits) |
139 | return (unsigned)-1; | 140 | return (unsigned)-1; |
140 | count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); | 141 | count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); |
141 | hpfs_brelse4(&qbh); | 142 | hpfs_brelse4(&qbh); |
142 | return count; | 143 | return count; |
143 | } | 144 | } |
144 | 145 | ||
145 | static unsigned count_bitmaps(struct super_block *s) | 146 | static unsigned count_bitmaps(struct super_block *s) |
146 | { | 147 | { |
147 | unsigned n, count, n_bands; | 148 | unsigned n, count, n_bands; |
148 | n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14; | 149 | n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14; |
149 | count = 0; | 150 | count = 0; |
150 | for (n = 0; n < COUNT_RD_AHEAD; n++) { | 151 | for (n = 0; n < COUNT_RD_AHEAD; n++) { |
151 | hpfs_prefetch_bitmap(s, n); | 152 | hpfs_prefetch_bitmap(s, n); |
152 | } | 153 | } |
153 | for (n = 0; n < n_bands; n++) { | 154 | for (n = 0; n < n_bands; n++) { |
154 | unsigned c; | 155 | unsigned c; |
155 | hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD); | 156 | hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD); |
156 | c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); | 157 | c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); |
157 | if (c != (unsigned)-1) | 158 | if (c != (unsigned)-1) |
158 | count += c; | 159 | count += c; |
159 | } | 160 | } |
160 | return count; | 161 | return count; |
161 | } | 162 | } |
162 | 163 | ||
163 | unsigned hpfs_get_free_dnodes(struct super_block *s) | 164 | unsigned hpfs_get_free_dnodes(struct super_block *s) |
164 | { | 165 | { |
165 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 166 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
166 | if (sbi->sb_n_free_dnodes == (unsigned)-1) { | 167 | if (sbi->sb_n_free_dnodes == (unsigned)-1) { |
167 | unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap); | 168 | unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap); |
168 | if (c == (unsigned)-1) | 169 | if (c == (unsigned)-1) |
169 | return 0; | 170 | return 0; |
170 | sbi->sb_n_free_dnodes = c; | 171 | sbi->sb_n_free_dnodes = c; |
171 | } | 172 | } |
172 | return sbi->sb_n_free_dnodes; | 173 | return sbi->sb_n_free_dnodes; |
173 | } | 174 | } |
174 | 175 | ||
175 | static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 176 | static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
176 | { | 177 | { |
177 | struct super_block *s = dentry->d_sb; | 178 | struct super_block *s = dentry->d_sb; |
178 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 179 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
179 | u64 id = huge_encode_dev(s->s_bdev->bd_dev); | 180 | u64 id = huge_encode_dev(s->s_bdev->bd_dev); |
180 | 181 | ||
181 | hpfs_lock(s); | 182 | hpfs_lock(s); |
182 | 183 | ||
183 | if (sbi->sb_n_free == (unsigned)-1) | 184 | if (sbi->sb_n_free == (unsigned)-1) |
184 | sbi->sb_n_free = count_bitmaps(s); | 185 | sbi->sb_n_free = count_bitmaps(s); |
185 | 186 | ||
186 | buf->f_type = s->s_magic; | 187 | buf->f_type = s->s_magic; |
187 | buf->f_bsize = 512; | 188 | buf->f_bsize = 512; |
188 | buf->f_blocks = sbi->sb_fs_size; | 189 | buf->f_blocks = sbi->sb_fs_size; |
189 | buf->f_bfree = sbi->sb_n_free; | 190 | buf->f_bfree = sbi->sb_n_free; |
190 | buf->f_bavail = sbi->sb_n_free; | 191 | buf->f_bavail = sbi->sb_n_free; |
191 | buf->f_files = sbi->sb_dirband_size / 4; | 192 | buf->f_files = sbi->sb_dirband_size / 4; |
192 | buf->f_ffree = hpfs_get_free_dnodes(s); | 193 | buf->f_ffree = hpfs_get_free_dnodes(s); |
193 | buf->f_fsid.val[0] = (u32)id; | 194 | buf->f_fsid.val[0] = (u32)id; |
194 | buf->f_fsid.val[1] = (u32)(id >> 32); | 195 | buf->f_fsid.val[1] = (u32)(id >> 32); |
195 | buf->f_namelen = 254; | 196 | buf->f_namelen = 254; |
196 | 197 | ||
197 | hpfs_unlock(s); | 198 | hpfs_unlock(s); |
198 | 199 | ||
199 | return 0; | 200 | return 0; |
200 | } | 201 | } |
201 | 202 | ||
202 | 203 | ||
203 | long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg) | 204 | long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
204 | { | 205 | { |
205 | switch (cmd) { | 206 | switch (cmd) { |
206 | case FITRIM: { | 207 | case FITRIM: { |
207 | struct fstrim_range range; | 208 | struct fstrim_range range; |
208 | secno n_trimmed; | 209 | secno n_trimmed; |
209 | int r; | 210 | int r; |
210 | if (!capable(CAP_SYS_ADMIN)) | 211 | if (!capable(CAP_SYS_ADMIN)) |
211 | return -EPERM; | 212 | return -EPERM; |
212 | if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) | 213 | if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) |
213 | return -EFAULT; | 214 | return -EFAULT; |
214 | r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed); | 215 | r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed); |
215 | if (r) | 216 | if (r) |
216 | return r; | 217 | return r; |
217 | range.len = (u64)n_trimmed << 9; | 218 | range.len = (u64)n_trimmed << 9; |
218 | if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range))) | 219 | if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range))) |
219 | return -EFAULT; | 220 | return -EFAULT; |
220 | return 0; | 221 | return 0; |
221 | } | 222 | } |
222 | default: { | 223 | default: { |
223 | return -ENOIOCTLCMD; | 224 | return -ENOIOCTLCMD; |
224 | } | 225 | } |
225 | } | 226 | } |
226 | } | 227 | } |
227 | 228 | ||
228 | 229 | ||
229 | static struct kmem_cache * hpfs_inode_cachep; | 230 | static struct kmem_cache * hpfs_inode_cachep; |
230 | 231 | ||
231 | static struct inode *hpfs_alloc_inode(struct super_block *sb) | 232 | static struct inode *hpfs_alloc_inode(struct super_block *sb) |
232 | { | 233 | { |
233 | struct hpfs_inode_info *ei; | 234 | struct hpfs_inode_info *ei; |
234 | ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); | 235 | ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS); |
235 | if (!ei) | 236 | if (!ei) |
236 | return NULL; | 237 | return NULL; |
237 | ei->vfs_inode.i_version = 1; | 238 | ei->vfs_inode.i_version = 1; |
238 | return &ei->vfs_inode; | 239 | return &ei->vfs_inode; |
239 | } | 240 | } |
240 | 241 | ||
241 | static void hpfs_i_callback(struct rcu_head *head) | 242 | static void hpfs_i_callback(struct rcu_head *head) |
242 | { | 243 | { |
243 | struct inode *inode = container_of(head, struct inode, i_rcu); | 244 | struct inode *inode = container_of(head, struct inode, i_rcu); |
244 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); | 245 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); |
245 | } | 246 | } |
246 | 247 | ||
247 | static void hpfs_destroy_inode(struct inode *inode) | 248 | static void hpfs_destroy_inode(struct inode *inode) |
248 | { | 249 | { |
249 | call_rcu(&inode->i_rcu, hpfs_i_callback); | 250 | call_rcu(&inode->i_rcu, hpfs_i_callback); |
250 | } | 251 | } |
251 | 252 | ||
252 | static void init_once(void *foo) | 253 | static void init_once(void *foo) |
253 | { | 254 | { |
254 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; | 255 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; |
255 | 256 | ||
256 | inode_init_once(&ei->vfs_inode); | 257 | inode_init_once(&ei->vfs_inode); |
257 | } | 258 | } |
258 | 259 | ||
259 | static int init_inodecache(void) | 260 | static int init_inodecache(void) |
260 | { | 261 | { |
261 | hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache", | 262 | hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache", |
262 | sizeof(struct hpfs_inode_info), | 263 | sizeof(struct hpfs_inode_info), |
263 | 0, (SLAB_RECLAIM_ACCOUNT| | 264 | 0, (SLAB_RECLAIM_ACCOUNT| |
264 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), | 265 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), |
265 | init_once); | 266 | init_once); |
266 | if (hpfs_inode_cachep == NULL) | 267 | if (hpfs_inode_cachep == NULL) |
267 | return -ENOMEM; | 268 | return -ENOMEM; |
268 | return 0; | 269 | return 0; |
269 | } | 270 | } |
270 | 271 | ||
271 | static void destroy_inodecache(void) | 272 | static void destroy_inodecache(void) |
272 | { | 273 | { |
273 | /* | 274 | /* |
274 | * Make sure all delayed rcu free inodes are flushed before we | 275 | * Make sure all delayed rcu free inodes are flushed before we |
275 | * destroy cache. | 276 | * destroy cache. |
276 | */ | 277 | */ |
277 | rcu_barrier(); | 278 | rcu_barrier(); |
278 | kmem_cache_destroy(hpfs_inode_cachep); | 279 | kmem_cache_destroy(hpfs_inode_cachep); |
279 | } | 280 | } |
280 | 281 | ||
281 | /* | 282 | /* |
282 | * A tiny parser for option strings, stolen from dosfs. | 283 | * A tiny parser for option strings, stolen from dosfs. |
283 | * Stolen again from read-only hpfs. | 284 | * Stolen again from read-only hpfs. |
284 | * And updated for table-driven option parsing. | 285 | * And updated for table-driven option parsing. |
285 | */ | 286 | */ |
286 | 287 | ||
287 | enum { | 288 | enum { |
288 | Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis, | 289 | Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis, |
289 | Opt_check_none, Opt_check_normal, Opt_check_strict, | 290 | Opt_check_none, Opt_check_normal, Opt_check_strict, |
290 | Opt_err_cont, Opt_err_ro, Opt_err_panic, | 291 | Opt_err_cont, Opt_err_ro, Opt_err_panic, |
291 | Opt_eas_no, Opt_eas_ro, Opt_eas_rw, | 292 | Opt_eas_no, Opt_eas_ro, Opt_eas_rw, |
292 | Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always, | 293 | Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always, |
293 | Opt_timeshift, Opt_err, | 294 | Opt_timeshift, Opt_err, |
294 | }; | 295 | }; |
295 | 296 | ||
296 | static const match_table_t tokens = { | 297 | static const match_table_t tokens = { |
297 | {Opt_help, "help"}, | 298 | {Opt_help, "help"}, |
298 | {Opt_uid, "uid=%u"}, | 299 | {Opt_uid, "uid=%u"}, |
299 | {Opt_gid, "gid=%u"}, | 300 | {Opt_gid, "gid=%u"}, |
300 | {Opt_umask, "umask=%o"}, | 301 | {Opt_umask, "umask=%o"}, |
301 | {Opt_case_lower, "case=lower"}, | 302 | {Opt_case_lower, "case=lower"}, |
302 | {Opt_case_asis, "case=asis"}, | 303 | {Opt_case_asis, "case=asis"}, |
303 | {Opt_check_none, "check=none"}, | 304 | {Opt_check_none, "check=none"}, |
304 | {Opt_check_normal, "check=normal"}, | 305 | {Opt_check_normal, "check=normal"}, |
305 | {Opt_check_strict, "check=strict"}, | 306 | {Opt_check_strict, "check=strict"}, |
306 | {Opt_err_cont, "errors=continue"}, | 307 | {Opt_err_cont, "errors=continue"}, |
307 | {Opt_err_ro, "errors=remount-ro"}, | 308 | {Opt_err_ro, "errors=remount-ro"}, |
308 | {Opt_err_panic, "errors=panic"}, | 309 | {Opt_err_panic, "errors=panic"}, |
309 | {Opt_eas_no, "eas=no"}, | 310 | {Opt_eas_no, "eas=no"}, |
310 | {Opt_eas_ro, "eas=ro"}, | 311 | {Opt_eas_ro, "eas=ro"}, |
311 | {Opt_eas_rw, "eas=rw"}, | 312 | {Opt_eas_rw, "eas=rw"}, |
312 | {Opt_chkdsk_no, "chkdsk=no"}, | 313 | {Opt_chkdsk_no, "chkdsk=no"}, |
313 | {Opt_chkdsk_errors, "chkdsk=errors"}, | 314 | {Opt_chkdsk_errors, "chkdsk=errors"}, |
314 | {Opt_chkdsk_always, "chkdsk=always"}, | 315 | {Opt_chkdsk_always, "chkdsk=always"}, |
315 | {Opt_timeshift, "timeshift=%d"}, | 316 | {Opt_timeshift, "timeshift=%d"}, |
316 | {Opt_err, NULL}, | 317 | {Opt_err, NULL}, |
317 | }; | 318 | }; |
318 | 319 | ||
319 | static int parse_opts(char *opts, kuid_t *uid, kgid_t *gid, umode_t *umask, | 320 | static int parse_opts(char *opts, kuid_t *uid, kgid_t *gid, umode_t *umask, |
320 | int *lowercase, int *eas, int *chk, int *errs, | 321 | int *lowercase, int *eas, int *chk, int *errs, |
321 | int *chkdsk, int *timeshift) | 322 | int *chkdsk, int *timeshift) |
322 | { | 323 | { |
323 | char *p; | 324 | char *p; |
324 | int option; | 325 | int option; |
325 | 326 | ||
326 | if (!opts) | 327 | if (!opts) |
327 | return 1; | 328 | return 1; |
328 | 329 | ||
329 | /*pr_info("Parsing opts: '%s'\n",opts);*/ | 330 | /*pr_info("Parsing opts: '%s'\n",opts);*/ |
330 | 331 | ||
331 | while ((p = strsep(&opts, ",")) != NULL) { | 332 | while ((p = strsep(&opts, ",")) != NULL) { |
332 | substring_t args[MAX_OPT_ARGS]; | 333 | substring_t args[MAX_OPT_ARGS]; |
333 | int token; | 334 | int token; |
334 | if (!*p) | 335 | if (!*p) |
335 | continue; | 336 | continue; |
336 | 337 | ||
337 | token = match_token(p, tokens, args); | 338 | token = match_token(p, tokens, args); |
338 | switch (token) { | 339 | switch (token) { |
339 | case Opt_help: | 340 | case Opt_help: |
340 | return 2; | 341 | return 2; |
341 | case Opt_uid: | 342 | case Opt_uid: |
342 | if (match_int(args, &option)) | 343 | if (match_int(args, &option)) |
343 | return 0; | 344 | return 0; |
344 | *uid = make_kuid(current_user_ns(), option); | 345 | *uid = make_kuid(current_user_ns(), option); |
345 | if (!uid_valid(*uid)) | 346 | if (!uid_valid(*uid)) |
346 | return 0; | 347 | return 0; |
347 | break; | 348 | break; |
348 | case Opt_gid: | 349 | case Opt_gid: |
349 | if (match_int(args, &option)) | 350 | if (match_int(args, &option)) |
350 | return 0; | 351 | return 0; |
351 | *gid = make_kgid(current_user_ns(), option); | 352 | *gid = make_kgid(current_user_ns(), option); |
352 | if (!gid_valid(*gid)) | 353 | if (!gid_valid(*gid)) |
353 | return 0; | 354 | return 0; |
354 | break; | 355 | break; |
355 | case Opt_umask: | 356 | case Opt_umask: |
356 | if (match_octal(args, &option)) | 357 | if (match_octal(args, &option)) |
357 | return 0; | 358 | return 0; |
358 | *umask = option; | 359 | *umask = option; |
359 | break; | 360 | break; |
360 | case Opt_case_lower: | 361 | case Opt_case_lower: |
361 | *lowercase = 1; | 362 | *lowercase = 1; |
362 | break; | 363 | break; |
363 | case Opt_case_asis: | 364 | case Opt_case_asis: |
364 | *lowercase = 0; | 365 | *lowercase = 0; |
365 | break; | 366 | break; |
366 | case Opt_check_none: | 367 | case Opt_check_none: |
367 | *chk = 0; | 368 | *chk = 0; |
368 | break; | 369 | break; |
369 | case Opt_check_normal: | 370 | case Opt_check_normal: |
370 | *chk = 1; | 371 | *chk = 1; |
371 | break; | 372 | break; |
372 | case Opt_check_strict: | 373 | case Opt_check_strict: |
373 | *chk = 2; | 374 | *chk = 2; |
374 | break; | 375 | break; |
375 | case Opt_err_cont: | 376 | case Opt_err_cont: |
376 | *errs = 0; | 377 | *errs = 0; |
377 | break; | 378 | break; |
378 | case Opt_err_ro: | 379 | case Opt_err_ro: |
379 | *errs = 1; | 380 | *errs = 1; |
380 | break; | 381 | break; |
381 | case Opt_err_panic: | 382 | case Opt_err_panic: |
382 | *errs = 2; | 383 | *errs = 2; |
383 | break; | 384 | break; |
384 | case Opt_eas_no: | 385 | case Opt_eas_no: |
385 | *eas = 0; | 386 | *eas = 0; |
386 | break; | 387 | break; |
387 | case Opt_eas_ro: | 388 | case Opt_eas_ro: |
388 | *eas = 1; | 389 | *eas = 1; |
389 | break; | 390 | break; |
390 | case Opt_eas_rw: | 391 | case Opt_eas_rw: |
391 | *eas = 2; | 392 | *eas = 2; |
392 | break; | 393 | break; |
393 | case Opt_chkdsk_no: | 394 | case Opt_chkdsk_no: |
394 | *chkdsk = 0; | 395 | *chkdsk = 0; |
395 | break; | 396 | break; |
396 | case Opt_chkdsk_errors: | 397 | case Opt_chkdsk_errors: |
397 | *chkdsk = 1; | 398 | *chkdsk = 1; |
398 | break; | 399 | break; |
399 | case Opt_chkdsk_always: | 400 | case Opt_chkdsk_always: |
400 | *chkdsk = 2; | 401 | *chkdsk = 2; |
401 | break; | 402 | break; |
402 | case Opt_timeshift: | 403 | case Opt_timeshift: |
403 | { | 404 | { |
404 | int m = 1; | 405 | int m = 1; |
405 | char *rhs = args[0].from; | 406 | char *rhs = args[0].from; |
406 | if (!rhs || !*rhs) | 407 | if (!rhs || !*rhs) |
407 | return 0; | 408 | return 0; |
408 | if (*rhs == '-') m = -1; | 409 | if (*rhs == '-') m = -1; |
409 | if (*rhs == '+' || *rhs == '-') rhs++; | 410 | if (*rhs == '+' || *rhs == '-') rhs++; |
410 | *timeshift = simple_strtoul(rhs, &rhs, 0) * m; | 411 | *timeshift = simple_strtoul(rhs, &rhs, 0) * m; |
411 | if (*rhs) | 412 | if (*rhs) |
412 | return 0; | 413 | return 0; |
413 | break; | 414 | break; |
414 | } | 415 | } |
415 | default: | 416 | default: |
416 | return 0; | 417 | return 0; |
417 | } | 418 | } |
418 | } | 419 | } |
419 | return 1; | 420 | return 1; |
420 | } | 421 | } |
421 | 422 | ||
422 | static inline void hpfs_help(void) | 423 | static inline void hpfs_help(void) |
423 | { | 424 | { |
424 | pr_info("\n\ | 425 | pr_info("\n\ |
425 | HPFS filesystem options:\n\ | 426 | HPFS filesystem options:\n\ |
426 | help do not mount and display this text\n\ | 427 | help do not mount and display this text\n\ |
427 | uid=xxx set uid of files that don't have uid specified in eas\n\ | 428 | uid=xxx set uid of files that don't have uid specified in eas\n\ |
428 | gid=xxx set gid of files that don't have gid specified in eas\n\ | 429 | gid=xxx set gid of files that don't have gid specified in eas\n\ |
429 | umask=xxx set mode of files that don't have mode specified in eas\n\ | 430 | umask=xxx set mode of files that don't have mode specified in eas\n\ |
430 | case=lower lowercase all files\n\ | 431 | case=lower lowercase all files\n\ |
431 | case=asis do not lowercase files (default)\n\ | 432 | case=asis do not lowercase files (default)\n\ |
432 | check=none no fs checks - kernel may crash on corrupted filesystem\n\ | 433 | check=none no fs checks - kernel may crash on corrupted filesystem\n\ |
433 | check=normal do some checks - it should not crash (default)\n\ | 434 | check=normal do some checks - it should not crash (default)\n\ |
434 | check=strict do extra time-consuming checks, used for debugging\n\ | 435 | check=strict do extra time-consuming checks, used for debugging\n\ |
435 | errors=continue continue on errors\n\ | 436 | errors=continue continue on errors\n\ |
436 | errors=remount-ro remount read-only if errors found (default)\n\ | 437 | errors=remount-ro remount read-only if errors found (default)\n\ |
437 | errors=panic panic on errors\n\ | 438 | errors=panic panic on errors\n\ |
438 | chkdsk=no do not mark fs for chkdsking even if there were errors\n\ | 439 | chkdsk=no do not mark fs for chkdsking even if there were errors\n\ |
439 | chkdsk=errors mark fs dirty if errors found (default)\n\ | 440 | chkdsk=errors mark fs dirty if errors found (default)\n\ |
440 | chkdsk=always always mark fs dirty - used for debugging\n\ | 441 | chkdsk=always always mark fs dirty - used for debugging\n\ |
441 | eas=no ignore extended attributes\n\ | 442 | eas=no ignore extended attributes\n\ |
442 | eas=ro read but do not write extended attributes\n\ | 443 | eas=ro read but do not write extended attributes\n\ |
443 | eas=rw r/w eas => enables chmod, chown, mknod, ln -s (default)\n\ | 444 | eas=rw r/w eas => enables chmod, chown, mknod, ln -s (default)\n\ |
444 | timeshift=nnn add nnn seconds to file times\n\ | 445 | timeshift=nnn add nnn seconds to file times\n\ |
445 | \n"); | 446 | \n"); |
446 | } | 447 | } |
447 | 448 | ||
448 | static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) | 449 | static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) |
449 | { | 450 | { |
450 | kuid_t uid; | 451 | kuid_t uid; |
451 | kgid_t gid; | 452 | kgid_t gid; |
452 | umode_t umask; | 453 | umode_t umask; |
453 | int lowercase, eas, chk, errs, chkdsk, timeshift; | 454 | int lowercase, eas, chk, errs, chkdsk, timeshift; |
454 | int o; | 455 | int o; |
455 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 456 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
456 | char *new_opts = kstrdup(data, GFP_KERNEL); | ||
457 | 457 | ||
458 | if (data && !new_opts) | ||
459 | return -ENOMEM; | ||
460 | |||
461 | sync_filesystem(s); | 458 | sync_filesystem(s); |
462 | 459 | ||
463 | *flags |= MS_NOATIME; | 460 | *flags |= MS_NOATIME; |
464 | 461 | ||
465 | hpfs_lock(s); | 462 | hpfs_lock(s); |
466 | uid = sbi->sb_uid; gid = sbi->sb_gid; | 463 | uid = sbi->sb_uid; gid = sbi->sb_gid; |
467 | umask = 0777 & ~sbi->sb_mode; | 464 | umask = 0777 & ~sbi->sb_mode; |
468 | lowercase = sbi->sb_lowercase; | 465 | lowercase = sbi->sb_lowercase; |
469 | eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk; | 466 | eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk; |
470 | errs = sbi->sb_err; timeshift = sbi->sb_timeshift; | 467 | errs = sbi->sb_err; timeshift = sbi->sb_timeshift; |
471 | 468 | ||
472 | if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, | 469 | if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, |
473 | &eas, &chk, &errs, &chkdsk, ×hift))) { | 470 | &eas, &chk, &errs, &chkdsk, ×hift))) { |
474 | pr_err("bad mount options.\n"); | 471 | pr_err("bad mount options.\n"); |
475 | goto out_err; | 472 | goto out_err; |
476 | } | 473 | } |
477 | if (o == 2) { | 474 | if (o == 2) { |
478 | hpfs_help(); | 475 | hpfs_help(); |
479 | goto out_err; | 476 | goto out_err; |
480 | } | 477 | } |
481 | if (timeshift != sbi->sb_timeshift) { | 478 | if (timeshift != sbi->sb_timeshift) { |
482 | pr_err("timeshift can't be changed using remount.\n"); | 479 | pr_err("timeshift can't be changed using remount.\n"); |
483 | goto out_err; | 480 | goto out_err; |
484 | } | 481 | } |
485 | 482 | ||
486 | unmark_dirty(s); | 483 | unmark_dirty(s); |
487 | 484 | ||
488 | sbi->sb_uid = uid; sbi->sb_gid = gid; | 485 | sbi->sb_uid = uid; sbi->sb_gid = gid; |
489 | sbi->sb_mode = 0777 & ~umask; | 486 | sbi->sb_mode = 0777 & ~umask; |
490 | sbi->sb_lowercase = lowercase; | 487 | sbi->sb_lowercase = lowercase; |
491 | sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; | 488 | sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; |
492 | sbi->sb_err = errs; sbi->sb_timeshift = timeshift; | 489 | sbi->sb_err = errs; sbi->sb_timeshift = timeshift; |
493 | 490 | ||
494 | if (!(*flags & MS_RDONLY)) mark_dirty(s, 1); | 491 | if (!(*flags & MS_RDONLY)) mark_dirty(s, 1); |
495 | 492 | ||
496 | if (new_opts) | ||
497 | replace_mount_options(s, new_opts); | ||
498 | |||
499 | hpfs_unlock(s); | 493 | hpfs_unlock(s); |
500 | return 0; | 494 | return 0; |
501 | 495 | ||
502 | out_err: | 496 | out_err: |
503 | hpfs_unlock(s); | 497 | hpfs_unlock(s); |
504 | kfree(new_opts); | ||
505 | return -EINVAL; | 498 | return -EINVAL; |
506 | } | 499 | } |
507 | 500 | ||
501 | static int hpfs_show_options(struct seq_file *seq, struct dentry *root) | ||
502 | { | ||
503 | struct hpfs_sb_info *sbi = hpfs_sb(root->d_sb); | ||
504 | |||
505 | seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, sbi->sb_uid)); | ||
506 | seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, sbi->sb_gid)); | ||
507 | seq_printf(seq, ",umask=%03o", (~sbi->sb_mode & 0777)); | ||
508 | if (sbi->sb_lowercase) | ||
509 | seq_printf(seq, ",case=lower"); | ||
510 | if (!sbi->sb_chk) | ||
511 | seq_printf(seq, ",check=none"); | ||
512 | if (sbi->sb_chk == 2) | ||
513 | seq_printf(seq, ",check=strict"); | ||
514 | if (!sbi->sb_err) | ||
515 | seq_printf(seq, ",errors=continue"); | ||
516 | if (sbi->sb_err == 2) | ||
517 | seq_printf(seq, ",errors=panic"); | ||
518 | if (!sbi->sb_chkdsk) | ||
519 | seq_printf(seq, ",chkdsk=no"); | ||
520 | if (sbi->sb_chkdsk == 2) | ||
521 | seq_printf(seq, ",chkdsk=always"); | ||
522 | if (!sbi->sb_eas) | ||
523 | seq_printf(seq, ",eas=no"); | ||
524 | if (sbi->sb_eas == 1) | ||
525 | seq_printf(seq, ",eas=ro"); | ||
526 | if (sbi->sb_timeshift) | ||
527 | seq_printf(seq, ",timeshift=%d", sbi->sb_timeshift); | ||
528 | return 0; | ||
529 | } | ||
530 | |||
508 | /* Super operations */ | 531 | /* Super operations */ |
509 | 532 | ||
510 | static const struct super_operations hpfs_sops = | 533 | static const struct super_operations hpfs_sops = |
511 | { | 534 | { |
512 | .alloc_inode = hpfs_alloc_inode, | 535 | .alloc_inode = hpfs_alloc_inode, |
513 | .destroy_inode = hpfs_destroy_inode, | 536 | .destroy_inode = hpfs_destroy_inode, |
514 | .evict_inode = hpfs_evict_inode, | 537 | .evict_inode = hpfs_evict_inode, |
515 | .put_super = hpfs_put_super, | 538 | .put_super = hpfs_put_super, |
516 | .statfs = hpfs_statfs, | 539 | .statfs = hpfs_statfs, |
517 | .remount_fs = hpfs_remount_fs, | 540 | .remount_fs = hpfs_remount_fs, |
518 | .show_options = generic_show_options, | 541 | .show_options = hpfs_show_options, |
519 | }; | 542 | }; |
520 | 543 | ||
521 | static int hpfs_fill_super(struct super_block *s, void *options, int silent) | 544 | static int hpfs_fill_super(struct super_block *s, void *options, int silent) |
522 | { | 545 | { |
523 | struct buffer_head *bh0, *bh1, *bh2; | 546 | struct buffer_head *bh0, *bh1, *bh2; |
524 | struct hpfs_boot_block *bootblock; | 547 | struct hpfs_boot_block *bootblock; |
525 | struct hpfs_super_block *superblock; | 548 | struct hpfs_super_block *superblock; |
526 | struct hpfs_spare_block *spareblock; | 549 | struct hpfs_spare_block *spareblock; |
527 | struct hpfs_sb_info *sbi; | 550 | struct hpfs_sb_info *sbi; |
528 | struct inode *root; | 551 | struct inode *root; |
529 | 552 | ||
530 | kuid_t uid; | 553 | kuid_t uid; |
531 | kgid_t gid; | 554 | kgid_t gid; |
532 | umode_t umask; | 555 | umode_t umask; |
533 | int lowercase, eas, chk, errs, chkdsk, timeshift; | 556 | int lowercase, eas, chk, errs, chkdsk, timeshift; |
534 | 557 | ||
535 | dnode_secno root_dno; | 558 | dnode_secno root_dno; |
536 | struct hpfs_dirent *de = NULL; | 559 | struct hpfs_dirent *de = NULL; |
537 | struct quad_buffer_head qbh; | 560 | struct quad_buffer_head qbh; |
538 | 561 | ||
539 | int o; | 562 | int o; |
540 | |||
541 | save_mount_options(s, options); | ||
542 | 563 | ||
543 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | 564 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
544 | if (!sbi) { | 565 | if (!sbi) { |
545 | return -ENOMEM; | 566 | return -ENOMEM; |
546 | } | 567 | } |
547 | s->s_fs_info = sbi; | 568 | s->s_fs_info = sbi; |
548 | 569 | ||
549 | mutex_init(&sbi->hpfs_mutex); | 570 | mutex_init(&sbi->hpfs_mutex); |
550 | hpfs_lock(s); | 571 | hpfs_lock(s); |
551 | 572 | ||
552 | uid = current_uid(); | 573 | uid = current_uid(); |
553 | gid = current_gid(); | 574 | gid = current_gid(); |
554 | umask = current_umask(); | 575 | umask = current_umask(); |
555 | lowercase = 0; | 576 | lowercase = 0; |
556 | eas = 2; | 577 | eas = 2; |
557 | chk = 1; | 578 | chk = 1; |
558 | errs = 1; | 579 | errs = 1; |
559 | chkdsk = 1; | 580 | chkdsk = 1; |
560 | timeshift = 0; | 581 | timeshift = 0; |
561 | 582 | ||
562 | if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, | 583 | if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, |
563 | &eas, &chk, &errs, &chkdsk, ×hift))) { | 584 | &eas, &chk, &errs, &chkdsk, ×hift))) { |
564 | pr_err("bad mount options.\n"); | 585 | pr_err("bad mount options.\n"); |
565 | goto bail0; | 586 | goto bail0; |
566 | } | 587 | } |
567 | if (o==2) { | 588 | if (o==2) { |
568 | hpfs_help(); | 589 | hpfs_help(); |
569 | goto bail0; | 590 | goto bail0; |
570 | } | 591 | } |
571 | 592 | ||
572 | /*sbi->sb_mounting = 1;*/ | 593 | /*sbi->sb_mounting = 1;*/ |
573 | sb_set_blocksize(s, 512); | 594 | sb_set_blocksize(s, 512); |
574 | sbi->sb_fs_size = -1; | 595 | sbi->sb_fs_size = -1; |
575 | if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1; | 596 | if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1; |
576 | if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2; | 597 | if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2; |
577 | if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3; | 598 | if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3; |
578 | 599 | ||
579 | /* Check magics */ | 600 | /* Check magics */ |
580 | if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC | 601 | if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC |
581 | ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC | 602 | ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC |
582 | || le32_to_cpu(spareblock->magic) != SP_MAGIC) { | 603 | || le32_to_cpu(spareblock->magic) != SP_MAGIC) { |
583 | if (!silent) | 604 | if (!silent) |
584 | pr_err("Bad magic ... probably not HPFS\n"); | 605 | pr_err("Bad magic ... probably not HPFS\n"); |
585 | goto bail4; | 606 | goto bail4; |
586 | } | 607 | } |
587 | 608 | ||
588 | /* Check version */ | 609 | /* Check version */ |
589 | if (!(s->s_flags & MS_RDONLY) && | 610 | if (!(s->s_flags & MS_RDONLY) && |
590 | superblock->funcversion != 2 && superblock->funcversion != 3) { | 611 | superblock->funcversion != 2 && superblock->funcversion != 3) { |
591 | pr_err("Bad version %d,%d. Mount readonly to go around\n", | 612 | pr_err("Bad version %d,%d. Mount readonly to go around\n", |
592 | (int)superblock->version, (int)superblock->funcversion); | 613 | (int)superblock->version, (int)superblock->funcversion); |
593 | pr_err("please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - mikulas@artax.karlin.mff.cuni.cz\n"); | 614 | pr_err("please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - mikulas@artax.karlin.mff.cuni.cz\n"); |
594 | goto bail4; | 615 | goto bail4; |
595 | } | 616 | } |
596 | 617 | ||
597 | s->s_flags |= MS_NOATIME; | 618 | s->s_flags |= MS_NOATIME; |
598 | 619 | ||
599 | /* Fill superblock stuff */ | 620 | /* Fill superblock stuff */ |
600 | s->s_magic = HPFS_SUPER_MAGIC; | 621 | s->s_magic = HPFS_SUPER_MAGIC; |
601 | s->s_op = &hpfs_sops; | 622 | s->s_op = &hpfs_sops; |
602 | s->s_d_op = &hpfs_dentry_operations; | 623 | s->s_d_op = &hpfs_dentry_operations; |
603 | 624 | ||
604 | sbi->sb_root = le32_to_cpu(superblock->root); | 625 | sbi->sb_root = le32_to_cpu(superblock->root); |
605 | sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors); | 626 | sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors); |
606 | sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps); | 627 | sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps); |
607 | sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start); | 628 | sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start); |
608 | sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band); | 629 | sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band); |
609 | sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap); | 630 | sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap); |
610 | sbi->sb_uid = uid; | 631 | sbi->sb_uid = uid; |
611 | sbi->sb_gid = gid; | 632 | sbi->sb_gid = gid; |
612 | sbi->sb_mode = 0777 & ~umask; | 633 | sbi->sb_mode = 0777 & ~umask; |
613 | sbi->sb_n_free = -1; | 634 | sbi->sb_n_free = -1; |
614 | sbi->sb_n_free_dnodes = -1; | 635 | sbi->sb_n_free_dnodes = -1; |
615 | sbi->sb_lowercase = lowercase; | 636 | sbi->sb_lowercase = lowercase; |
616 | sbi->sb_eas = eas; | 637 | sbi->sb_eas = eas; |
617 | sbi->sb_chk = chk; | 638 | sbi->sb_chk = chk; |
618 | sbi->sb_chkdsk = chkdsk; | 639 | sbi->sb_chkdsk = chkdsk; |
619 | sbi->sb_err = errs; | 640 | sbi->sb_err = errs; |
620 | sbi->sb_timeshift = timeshift; | 641 | sbi->sb_timeshift = timeshift; |
621 | sbi->sb_was_error = 0; | 642 | sbi->sb_was_error = 0; |
622 | sbi->sb_cp_table = NULL; | 643 | sbi->sb_cp_table = NULL; |
623 | sbi->sb_c_bitmap = -1; | 644 | sbi->sb_c_bitmap = -1; |
624 | sbi->sb_max_fwd_alloc = 0xffffff; | 645 | sbi->sb_max_fwd_alloc = 0xffffff; |
625 | 646 | ||
626 | if (sbi->sb_fs_size >= 0x80000000) { | 647 | if (sbi->sb_fs_size >= 0x80000000) { |
627 | hpfs_error(s, "invalid size in superblock: %08x", | 648 | hpfs_error(s, "invalid size in superblock: %08x", |
628 | (unsigned)sbi->sb_fs_size); | 649 | (unsigned)sbi->sb_fs_size); |
629 | goto bail4; | 650 | goto bail4; |
630 | } | 651 | } |
631 | 652 | ||
632 | if (spareblock->n_spares_used) | 653 | if (spareblock->n_spares_used) |
633 | hpfs_load_hotfix_map(s, spareblock); | 654 | hpfs_load_hotfix_map(s, spareblock); |
634 | 655 | ||
635 | /* Load bitmap directory */ | 656 | /* Load bitmap directory */ |
636 | if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) | 657 | if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) |
637 | goto bail4; | 658 | goto bail4; |
638 | 659 | ||
639 | /* Check for general fs errors*/ | 660 | /* Check for general fs errors*/ |
640 | if (spareblock->dirty && !spareblock->old_wrote) { | 661 | if (spareblock->dirty && !spareblock->old_wrote) { |
641 | if (errs == 2) { | 662 | if (errs == 2) { |
642 | pr_err("Improperly stopped, not mounted\n"); | 663 | pr_err("Improperly stopped, not mounted\n"); |
643 | goto bail4; | 664 | goto bail4; |
644 | } | 665 | } |
645 | hpfs_error(s, "improperly stopped"); | 666 | hpfs_error(s, "improperly stopped"); |
646 | } | 667 | } |
647 | 668 | ||
648 | if (!(s->s_flags & MS_RDONLY)) { | 669 | if (!(s->s_flags & MS_RDONLY)) { |
649 | spareblock->dirty = 1; | 670 | spareblock->dirty = 1; |
650 | spareblock->old_wrote = 0; | 671 | spareblock->old_wrote = 0; |
651 | mark_buffer_dirty(bh2); | 672 | mark_buffer_dirty(bh2); |
652 | } | 673 | } |
653 | 674 | ||
654 | if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { | 675 | if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { |
655 | if (errs >= 2) { | 676 | if (errs >= 2) { |
656 | pr_err("Spare dnodes used, try chkdsk\n"); | 677 | pr_err("Spare dnodes used, try chkdsk\n"); |
657 | mark_dirty(s, 0); | 678 | mark_dirty(s, 0); |
658 | goto bail4; | 679 | goto bail4; |
659 | } | 680 | } |
660 | hpfs_error(s, "warning: spare dnodes used, try chkdsk"); | 681 | hpfs_error(s, "warning: spare dnodes used, try chkdsk"); |
661 | if (errs == 0) | 682 | if (errs == 0) |
662 | pr_err("Proceeding, but your filesystem could be corrupted if you delete files or directories\n"); | 683 | pr_err("Proceeding, but your filesystem could be corrupted if you delete files or directories\n"); |
663 | } | 684 | } |
664 | if (chk) { | 685 | if (chk) { |
665 | unsigned a; | 686 | unsigned a; |
666 | if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) || | 687 | if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) || |
667 | le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) { | 688 | le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) { |
668 | hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x", | 689 | hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x", |
669 | le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band)); | 690 | le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band)); |
670 | goto bail4; | 691 | goto bail4; |
671 | } | 692 | } |
672 | a = sbi->sb_dirband_size; | 693 | a = sbi->sb_dirband_size; |
673 | sbi->sb_dirband_size = 0; | 694 | sbi->sb_dirband_size = 0; |
674 | if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") || | 695 | if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") || |
675 | hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") || | 696 | hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") || |
676 | hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) { | 697 | hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) { |
677 | mark_dirty(s, 0); | 698 | mark_dirty(s, 0); |
678 | goto bail4; | 699 | goto bail4; |
679 | } | 700 | } |
680 | sbi->sb_dirband_size = a; | 701 | sbi->sb_dirband_size = a; |
681 | } else | 702 | } else |
682 | pr_err("You really don't want any checks? You are crazy...\n"); | 703 | pr_err("You really don't want any checks? You are crazy...\n"); |
683 | 704 | ||
684 | /* Load code page table */ | 705 | /* Load code page table */ |
685 | if (le32_to_cpu(spareblock->n_code_pages)) | 706 | if (le32_to_cpu(spareblock->n_code_pages)) |
686 | if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir)))) | 707 | if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir)))) |
687 | pr_err("code page support is disabled\n"); | 708 | pr_err("code page support is disabled\n"); |
688 | 709 | ||
689 | brelse(bh2); | 710 | brelse(bh2); |
690 | brelse(bh1); | 711 | brelse(bh1); |
691 | brelse(bh0); | 712 | brelse(bh0); |
692 | 713 | ||
693 | root = iget_locked(s, sbi->sb_root); | 714 | root = iget_locked(s, sbi->sb_root); |
694 | if (!root) | 715 | if (!root) |
695 | goto bail0; | 716 | goto bail0; |
696 | hpfs_init_inode(root); | 717 | hpfs_init_inode(root); |
697 | hpfs_read_inode(root); | 718 | hpfs_read_inode(root); |
698 | unlock_new_inode(root); | 719 | unlock_new_inode(root); |
699 | s->s_root = d_make_root(root); | 720 | s->s_root = d_make_root(root); |
700 | if (!s->s_root) | 721 | if (!s->s_root) |
701 | goto bail0; | 722 | goto bail0; |
702 | 723 | ||
703 | /* | 724 | /* |
704 | * find the root directory's . pointer & finish filling in the inode | 725 | * find the root directory's . pointer & finish filling in the inode |
705 | */ | 726 | */ |
706 | 727 | ||
707 | root_dno = hpfs_fnode_dno(s, sbi->sb_root); | 728 | root_dno = hpfs_fnode_dno(s, sbi->sb_root); |
708 | if (root_dno) | 729 | if (root_dno) |
709 | de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh); | 730 | de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh); |
710 | if (!de) | 731 | if (!de) |
711 | hpfs_error(s, "unable to find root dir"); | 732 | hpfs_error(s, "unable to find root dir"); |
712 | else { | 733 | else { |
713 | root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date)); | 734 | root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date)); |
714 | root->i_atime.tv_nsec = 0; | 735 | root->i_atime.tv_nsec = 0; |
715 | root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date)); | 736 | root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date)); |
716 | root->i_mtime.tv_nsec = 0; | 737 | root->i_mtime.tv_nsec = 0; |
717 | root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date)); | 738 | root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date)); |
718 | root->i_ctime.tv_nsec = 0; | 739 | root->i_ctime.tv_nsec = 0; |
719 | hpfs_i(root)->i_ea_size = le32_to_cpu(de->ea_size); | 740 | hpfs_i(root)->i_ea_size = le32_to_cpu(de->ea_size); |
720 | hpfs_i(root)->i_parent_dir = root->i_ino; | 741 | hpfs_i(root)->i_parent_dir = root->i_ino; |
721 | if (root->i_size == -1) | 742 | if (root->i_size == -1) |
722 | root->i_size = 2048; | 743 | root->i_size = 2048; |
723 | if (root->i_blocks == -1) | 744 | if (root->i_blocks == -1) |
724 | root->i_blocks = 5; | 745 | root->i_blocks = 5; |
725 | hpfs_brelse4(&qbh); | 746 | hpfs_brelse4(&qbh); |
726 | } | 747 | } |
727 | hpfs_unlock(s); | 748 | hpfs_unlock(s); |
728 | return 0; | 749 | return 0; |
729 | 750 | ||
730 | bail4: brelse(bh2); | 751 | bail4: brelse(bh2); |
731 | bail3: brelse(bh1); | 752 | bail3: brelse(bh1); |
732 | bail2: brelse(bh0); | 753 | bail2: brelse(bh0); |
733 | bail1: | 754 | bail1: |
734 | bail0: | 755 | bail0: |
735 | hpfs_unlock(s); | 756 | hpfs_unlock(s); |
736 | free_sbi(sbi); | 757 | free_sbi(sbi); |
737 | return -EINVAL; | 758 | return -EINVAL; |
738 | } | 759 | } |
739 | 760 | ||
740 | static struct dentry *hpfs_mount(struct file_system_type *fs_type, | 761 | static struct dentry *hpfs_mount(struct file_system_type *fs_type, |
741 | int flags, const char *dev_name, void *data) | 762 | int flags, const char *dev_name, void *data) |
742 | { | 763 | { |
743 | return mount_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); | 764 | return mount_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); |
744 | } | 765 | } |
745 | 766 | ||
746 | static struct file_system_type hpfs_fs_type = { | 767 | static struct file_system_type hpfs_fs_type = { |
747 | .owner = THIS_MODULE, | 768 | .owner = THIS_MODULE, |
748 | .name = "hpfs", | 769 | .name = "hpfs", |
749 | .mount = hpfs_mount, | 770 | .mount = hpfs_mount, |
750 | .kill_sb = kill_block_super, | 771 | .kill_sb = kill_block_super, |
751 | .fs_flags = FS_REQUIRES_DEV, | 772 | .fs_flags = FS_REQUIRES_DEV, |
752 | }; | 773 | }; |
753 | MODULE_ALIAS_FS("hpfs"); | 774 | MODULE_ALIAS_FS("hpfs"); |
754 | 775 | ||
755 | static int __init init_hpfs_fs(void) | 776 | static int __init init_hpfs_fs(void) |
756 | { | 777 | { |
757 | int err = init_inodecache(); | 778 | int err = init_inodecache(); |
758 | if (err) | 779 | if (err) |
759 | goto out1; | 780 | goto out1; |
760 | err = register_filesystem(&hpfs_fs_type); | 781 | err = register_filesystem(&hpfs_fs_type); |
761 | if (err) | 782 | if (err) |
762 | goto out; | 783 | goto out; |
763 | return 0; | 784 | return 0; |
764 | out: | 785 | out: |
765 | destroy_inodecache(); | 786 | destroy_inodecache(); |
766 | out1: | 787 | out1: |
767 | return err; | 788 | return err; |
768 | } | 789 | } |
769 | 790 |