2 * linux/fs/hpfs/super.c
4 * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
6 * mouning, unmounting, error handling
9 #include <linux/string.h>
11 #include <linux/module.h>
13 /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
15 static void mark_dirty(struct super_block
*s
)
17 if (s
->s_hpfs_chkdsk
&& !(s
->s_flags
& MS_RDONLY
)) {
18 struct buffer_head
*bh
;
19 struct hpfs_spare_block
*sb
;
20 if ((sb
= hpfs_map_sector(s
, 17, &bh
, 0))) {
23 mark_buffer_dirty(bh
, 1);
29 /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there
32 static void unmark_dirty(struct super_block
*s
)
34 struct buffer_head
*bh
;
35 struct hpfs_spare_block
*sb
;
36 if (s
->s_flags
& MS_RDONLY
) return;
37 if ((sb
= hpfs_map_sector(s
, 17, &bh
, 0))) {
38 sb
->dirty
= s
->s_hpfs_chkdsk
> 1 - s
->s_hpfs_was_error
;
39 sb
->old_wrote
= s
->s_hpfs_chkdsk
>= 2 && !s
->s_hpfs_was_error
;
40 mark_buffer_dirty(bh
, 1);
45 /* Filesystem error... */
47 #define ERR_BUF_SIZE 1024
49 void hpfs_error(struct super_block
*s
, char *m
,...)
54 if (!(buf
= kmalloc(ERR_BUF_SIZE
, GFP_KERNEL
)))
55 printk("HPFS: No memory for error message '%s'\n",m
);
56 else if (vsprintf(buf
, m
, l
) >= ERR_BUF_SIZE
)
57 printk("HPFS: Grrrr... Kernel memory corrupted ... going on, but it'll crash very soon :-(\n");
58 printk("HPFS: filesystem error: ");
59 if (buf
) printk("%s", buf
);
60 else printk("%s\n",m
);
61 if (!s
->s_hpfs_was_error
) {
62 if (s
->s_hpfs_err
== 2) {
63 printk("; crashing the system because you wanted it\n");
66 } else if (s
->s_hpfs_err
== 1) {
67 if (s
->s_flags
& MS_RDONLY
) printk("; already mounted read-only\n");
69 printk("; remounting read-only\n");
71 s
->s_flags
|= MS_RDONLY
;
73 } else if (s
->s_flags
& MS_RDONLY
) printk("; going on - but anything won't be destroyed because it's read-only\n");
74 else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n");
77 s
->s_hpfs_was_error
= 1;
81 * A little trick to detect cycles in many hpfs structures and don't let the
82 * kernel crash on corrupted filesystem. When first called, set c2 to 0.
84 * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories
85 * nested each in other, chkdsk locked up happilly.
88 int hpfs_stop_cycles(struct super_block
*s
, int key
, int *c1
, int *c2
,
91 if (*c2
&& *c1
== key
) {
92 hpfs_error(s
, "cycle detected on key %08x in %s", key
, msg
);
96 if (!((*c2
- 1) & *c2
)) *c1
= key
;
100 void hpfs_put_super(struct super_block
*s
)
102 if (s
->s_hpfs_cp_table
) kfree(s
->s_hpfs_cp_table
);
103 if (s
->s_hpfs_bmp_dir
) kfree(s
->s_hpfs_bmp_dir
);
109 unsigned hpfs_count_one_bitmap(struct super_block
*s
, secno secno
)
111 struct quad_buffer_head qbh
;
114 if (!(bits
= hpfs_map_4sectors(s
, secno
, &qbh
, 4))) return 0;
116 for (i
= 0; i
< 2048 / sizeof(unsigned); i
++) {
118 if (!bits
[i
]) continue;
119 for (b
= bits
[i
]; b
; b
>>=1) count
+= b
& 1;
125 static unsigned count_bitmaps(struct super_block
*s
)
127 unsigned n
, count
, n_bands
;
128 n_bands
= (s
->s_hpfs_fs_size
+ 0x3fff) >> 14;
130 for (n
= 0; n
< n_bands
; n
++)
131 count
+= hpfs_count_one_bitmap(s
, s
->s_hpfs_bmp_dir
[n
]);
135 int hpfs_statfs(struct super_block
*s
, struct statfs
*buf
, int bufsiz
)
138 /*if (s->s_hpfs_n_free == -1) {*/
139 s
->s_hpfs_n_free
= count_bitmaps(s
);
140 s
->s_hpfs_n_free_dnodes
= hpfs_count_one_bitmap(s
, s
->s_hpfs_dmap
);
142 tmp
.f_type
= s
->s_magic
;
144 tmp
.f_blocks
= s
->s_hpfs_fs_size
;
145 tmp
.f_bfree
= s
->s_hpfs_n_free
;
146 tmp
.f_bavail
= s
->s_hpfs_n_free
;
147 tmp
.f_files
= s
->s_hpfs_dirband_size
/ 4;
148 tmp
.f_ffree
= s
->s_hpfs_n_free_dnodes
;
150 return copy_to_user(buf
, &tmp
, bufsiz
) ? -EFAULT
: 0;
153 /* Super operations */
155 static struct super_operations hpfs_sops
=
157 read_inode
: hpfs_read_inode
,
158 delete_inode
: hpfs_delete_inode
,
159 put_super
: hpfs_put_super
,
161 remount_fs
: hpfs_remount_fs
,
165 * A tiny parser for option strings, stolen from dosfs.
167 * Stolen again from read-only hpfs.
170 int parse_opts(char *opts
, uid_t
*uid
, gid_t
*gid
, umode_t
*umask
,
171 int *lowercase
, int *conv
, int *eas
, int *chk
, int *errs
,
172 int *chkdsk
, int *timeshift
)
179 /*printk("Parsing opts: '%s'\n",opts);*/
181 for (p
= strtok(opts
, ","); p
!= 0; p
= strtok(0, ",")) {
182 if ((rhs
= strchr(p
, '=')) != 0)
184 if (!strcmp(p
, "help")) return 2;
185 if (!strcmp(p
, "uid")) {
188 *uid
= simple_strtoul(rhs
, &rhs
, 0);
192 else if (!strcmp(p
, "gid")) {
195 *gid
= simple_strtoul(rhs
, &rhs
, 0);
199 else if (!strcmp(p
, "umask")) {
202 *umask
= simple_strtoul(rhs
, &rhs
, 8);
206 else if (!strcmp(p
, "timeshift")) {
210 if (*rhs
== '-') m
= -1;
211 if (*rhs
== '+' || *rhs
== '-') rhs
++;
212 *timeshift
= simple_strtoul(rhs
, &rhs
, 0) * m
;
216 else if (!strcmp(p
, "case")) {
217 if (!strcmp(rhs
, "lower"))
219 else if (!strcmp(rhs
, "asis"))
224 else if (!strcmp(p
, "conv")) {
225 if (!strcmp(rhs
, "binary"))
227 else if (!strcmp(rhs
, "text"))
229 else if (!strcmp(rhs
, "auto"))
234 else if (!strcmp(p
, "check")) {
235 if (!strcmp(rhs
, "none"))
237 else if (!strcmp(rhs
, "normal"))
239 else if (!strcmp(rhs
, "strict"))
244 else if (!strcmp(p
, "errors")) {
245 if (!strcmp(rhs
, "continue"))
247 else if (!strcmp(rhs
, "remount-ro"))
249 else if (!strcmp(rhs
, "panic"))
254 else if (!strcmp(p
, "eas")) {
255 if (!strcmp(rhs
, "no"))
257 else if (!strcmp(rhs
, "ro"))
259 else if (!strcmp(rhs
, "rw"))
264 else if (!strcmp(p
, "chkdsk")) {
265 if (!strcmp(rhs
, "no"))
267 else if (!strcmp(rhs
, "errors"))
269 else if (!strcmp(rhs
, "always"))
280 static inline void hpfs_help(void)
283 HPFS filesystem options:\n\
284 help do not mount and display this text\n\
285 uid=xxx set uid of files that don't have uid specified in eas\n\
286 gid=xxx set gid of files that don't have gid specified in eas\n\
287 umask=xxx set mode of files that don't have mode specified in eas\n\
288 case=lower lowercase all files\n\
289 case=asis do not lowercase files (default)\n\
290 conv=binary do not convert CR/LF -> LF (default)\n\
291 conv=auto convert only files with known text extensions\n\
292 conv=text convert all files\n\
293 check=none no fs checks - kernel may crash on corrupted filesystem\n\
294 check=normal do some checks - it should not crash (default)\n\
295 check=strict do extra time-consuming checks, used for debugging\n\
296 errors=continue continue on errors\n\
297 errors=remount-ro remount read-only if errors found (default)\n\
298 errors=panic panic on errors\n\
299 chkdsk=no do not mark fs for chkdsking even if there were errors\n\
300 chkdsk=errors mark fs dirty if errors found (default)\n\
301 chkdsk=always always mark fs dirty - used for debugging\n\
302 eas=no ignore extended attributes\n\
303 eas=ro read but do not write extended attributes\n\
304 eas=rw r/w eas => enables chmod, chown, mknod, ln -s (default)\n\
305 timeshift=nnn add nnn seconds to file times\n\
309 int hpfs_remount_fs(struct super_block
*s
, int *flags
, char *data
)
314 int lowercase
, conv
, eas
, chk
, errs
, chkdsk
, timeshift
;
317 *flags
|= MS_NOATIME
;
319 uid
= s
->s_hpfs_uid
; gid
= s
->s_hpfs_gid
;
320 umask
= 0777 & ~s
->s_hpfs_mode
;
321 lowercase
= s
->s_hpfs_lowercase
; conv
= s
->s_hpfs_conv
;
322 eas
= s
->s_hpfs_eas
; chk
= s
->s_hpfs_chk
; chkdsk
= s
->s_hpfs_chkdsk
;
323 errs
= s
->s_hpfs_err
; timeshift
= s
->s_hpfs_timeshift
;
325 if (!(o
= parse_opts(data
, &uid
, &gid
, &umask
, &lowercase
, &conv
,
326 &eas
, &chk
, &errs
, &chkdsk
, ×hift
))) {
327 printk("HPFS: bad mount options.\n");
334 if (timeshift
!= s
->s_hpfs_timeshift
) {
335 printk("HPFS: timeshift can't be changed using remount.\n");
341 s
->s_hpfs_uid
= uid
; s
->s_hpfs_gid
= gid
;
342 s
->s_hpfs_mode
= 0777 & ~umask
;
343 s
->s_hpfs_lowercase
= lowercase
; s
->s_hpfs_conv
= conv
;
344 s
->s_hpfs_eas
= eas
; s
->s_hpfs_chk
= chk
; s
->s_hpfs_chkdsk
= chkdsk
;
345 s
->s_hpfs_err
= errs
; s
->s_hpfs_timeshift
= timeshift
;
347 if (!(*flags
& MS_RDONLY
)) mark_dirty(s
);
352 struct super_block
*hpfs_read_super(struct super_block
*s
, void *options
,
356 struct buffer_head
*bh0
, *bh1
, *bh2
;
357 struct hpfs_boot_block
*bootblock
;
358 struct hpfs_super_block
*superblock
;
359 struct hpfs_spare_block
*spareblock
;
364 int lowercase
, conv
, eas
, chk
, errs
, chkdsk
, timeshift
;
366 dnode_secno root_dno
;
367 struct hpfs_dirent
*de
= NULL
;
368 struct quad_buffer_head qbh
;
374 s
->s_hpfs_bmp_dir
= NULL
;
375 s
->s_hpfs_cp_table
= NULL
;
377 s
->s_hpfs_creation_de_lock
= s
->s_hpfs_rd_inode
= 0;
378 init_waitqueue_head(&s
->s_hpfs_creation_de
);
379 init_waitqueue_head(&s
->s_hpfs_iget_q
);
383 umask
= current
->fs
->umask
;
392 if (!(o
= parse_opts(options
, &uid
, &gid
, &umask
, &lowercase
, &conv
,
393 &eas
, &chk
, &errs
, &chkdsk
, ×hift
))) {
394 printk("HPFS: bad mount options.\n");
402 /*s->s_hpfs_mounting = 1;*/
405 set_blocksize(dev
, 512);
406 s
->s_hpfs_fs_size
= -1;
407 if (!(bootblock
= hpfs_map_sector(s
, 0, &bh0
, 0))) goto bail1
;
408 if (!(superblock
= hpfs_map_sector(s
, 16, &bh1
, 1))) goto bail2
;
409 if (!(spareblock
= hpfs_map_sector(s
, 17, &bh2
, 0))) goto bail3
;
412 if (/*bootblock->magic != BB_MAGIC
413 ||*/ superblock
->magic
!= SB_MAGIC
414 || spareblock
->magic
!= SP_MAGIC
) {
415 if (!silent
) printk("HPFS: Bad magic ... probably not HPFS\n");
420 if (!(s
->s_flags
& MS_RDONLY
) &&
421 superblock
->funcversion
!= 2 && superblock
->funcversion
!= 3) {
422 printk("HPFS: Bad version %d,%d. Mount readonly to go around\n",
423 (int)superblock
->version
, (int)superblock
->funcversion
);
424 printk("HPFS: 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");
428 s
->s_flags
|= MS_NOATIME
;
430 /* Fill superblock stuff */
431 s
->s_magic
= HPFS_SUPER_MAGIC
;
432 s
->s_blocksize
= 512;
433 s
->s_blocksize_bits
= 9;
434 s
->s_op
= &hpfs_sops
;
436 s
->s_hpfs_root
= superblock
->root
;
437 s
->s_hpfs_fs_size
= superblock
->n_sectors
;
438 s
->s_hpfs_bitmaps
= superblock
->bitmaps
;
439 s
->s_hpfs_dirband_start
= superblock
->dir_band_start
;
440 s
->s_hpfs_dirband_size
= superblock
->n_dir_band
;
441 s
->s_hpfs_dmap
= superblock
->dir_band_bitmap
;
444 s
->s_hpfs_mode
= 0777 & ~umask
;
445 s
->s_hpfs_n_free
= -1;
446 s
->s_hpfs_n_free_dnodes
= -1;
447 s
->s_hpfs_lowercase
= lowercase
;
448 s
->s_hpfs_conv
= conv
;
451 s
->s_hpfs_chkdsk
= chkdsk
;
452 s
->s_hpfs_err
= errs
;
453 s
->s_hpfs_timeshift
= timeshift
;
454 s
->s_hpfs_was_error
= 0;
455 s
->s_hpfs_cp_table
= NULL
;
456 s
->s_hpfs_c_bitmap
= -1;
458 /* Load bitmap directory */
459 if (!(s
->s_hpfs_bmp_dir
= hpfs_load_bitmap_directory(s
, superblock
->bitmaps
)))
462 /* Check for general fs errors*/
463 if (spareblock
->dirty
&& !spareblock
->old_wrote
) {
465 printk("HPFS: Improperly stopped, not mounted\n");
468 hpfs_error(s
, "improperly stopped");
471 if (!(s
->s_flags
& MS_RDONLY
)) {
472 spareblock
->dirty
= 1;
473 spareblock
->old_wrote
= 0;
474 mark_buffer_dirty(bh2
, 1);
477 if (spareblock
->hotfixes_used
|| spareblock
->n_spares_used
) {
479 printk("HPFS: Hotfixes not supported here, try chkdsk\n");
483 hpfs_error(s
, "hotfixes not supported here, try chkdsk");
484 if (errs
== 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n");
485 else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.\n");
487 if (spareblock
->n_dnode_spares
!= spareblock
->n_dnode_spares_free
) {
489 printk("HPFS: Spare dnodes used, try chkdsk\n");
493 hpfs_error(s
, "warning: spare dnodes used, try chkdsk");
494 if (errs
== 0) printk("HPFS: Proceeding, but your filesystem could be corrupted if you delete files or directories\n");
498 if (superblock
->dir_band_end
- superblock
->dir_band_start
+ 1 != superblock
->n_dir_band
||
499 superblock
->dir_band_end
< superblock
->dir_band_start
|| superblock
->n_dir_band
> 0x4000) {
500 hpfs_error(s
, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x",
501 superblock
->dir_band_start
, superblock
->dir_band_end
, superblock
->n_dir_band
);
504 a
= s
->s_hpfs_dirband_size
;
505 s
->s_hpfs_dirband_size
= 0;
506 if (hpfs_chk_sectors(s
, superblock
->dir_band_start
, superblock
->n_dir_band
, "dir_band") ||
507 hpfs_chk_sectors(s
, superblock
->dir_band_bitmap
, 4, "dir_band_bitmap") ||
508 hpfs_chk_sectors(s
, superblock
->bitmaps
, 4, "bitmaps")) {
512 s
->s_hpfs_dirband_size
= a
;
513 } else printk("HPFS: You really don't want any checks? You are crazy...\n");
515 /* Load code page table */
516 if (spareblock
->n_code_pages
)
517 if (!(s
->s_hpfs_cp_table
= hpfs_load_code_page(s
, spareblock
->code_page_dir
)))
518 printk("HPFS: Warning: code page support is disabled\n");
524 hpfs_lock_iget(s
, 1);
525 s
->s_root
= d_alloc_root(iget(s
, s
->s_hpfs_root
));
528 if (!s
->s_root
|| !s
->s_root
->d_inode
) {
529 printk("HPFS: iget failed. Why???\n");
532 hpfs_set_dentry_operations(s
->s_root
);
535 * find the root directory's . pointer & finish filling in the inode
538 root_dno
= hpfs_fnode_dno(s
, s
->s_hpfs_root
);
540 de
= map_dirent(s
->s_root
->d_inode
, root_dno
, "\001\001", 2, NULL
, &qbh
);
541 if (!root_dno
|| !de
) hpfs_error(s
, "unable to find root dir");
543 s
->s_root
->d_inode
->i_atime
= local_to_gmt(s
, de
->read_date
);
544 s
->s_root
->d_inode
->i_mtime
= local_to_gmt(s
, de
->write_date
);
545 s
->s_root
->d_inode
->i_ctime
= local_to_gmt(s
, de
->creation_date
);
546 s
->s_root
->d_inode
->i_hpfs_ea_size
= de
->ea_size
;
547 s
->s_root
->d_inode
->i_hpfs_parent_dir
= s
->s_root
->d_inode
->i_ino
;
548 if (s
->s_root
->d_inode
->i_size
== -1) s
->s_root
->d_inode
->i_size
= 2048;
549 if (s
->s_root
->d_inode
->i_blocks
== -1) s
->s_root
->d_inode
->i_blocks
= 5;
551 if (de
) hpfs_brelse4(&qbh
);
558 bail1
: unlock_super(s
);
560 if (s
->s_hpfs_bmp_dir
) kfree(s
->s_hpfs_bmp_dir
);
561 if (s
->s_hpfs_cp_table
) kfree(s
->s_hpfs_cp_table
);
566 struct file_system_type hpfs_fs_type
= {
567 "hpfs", FS_REQUIRES_DEV
, hpfs_read_super
, NULL
570 int init_hpfs_fs(void)
572 return register_filesystem(&hpfs_fs_type
);
577 /*int register_symtab_from(struct symbol_table *, long *);*/
579 int init_module(void)
582 if (!(status = init_hpfs_fs())) register_symtab(NULL);
584 return init_hpfs_fs();
587 void cleanup_module(void)
589 unregister_filesystem(&hpfs_fs_type
);