2 * linux/fs/adfs/super.c
4 * Copyright (C) 1997-1999 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/buffer_head.h>
13 #include <linux/parser.h>
14 #include <linux/mount.h>
15 #include <linux/seq_file.h>
16 #include <linux/slab.h>
17 #include <linux/statfs.h>
20 #include "dir_fplus.h"
22 #define ADFS_DEFAULT_OWNER_MASK S_IRWXU
23 #define ADFS_DEFAULT_OTHER_MASK (S_IRWXG | S_IRWXO)
25 void __adfs_error(struct super_block
*sb
, const char *function
, const char *fmt
, ...)
31 vsnprintf(error_buf
, sizeof(error_buf
), fmt
, args
);
34 printk(KERN_CRIT
"ADFS-fs error (device %s)%s%s: %s\n",
35 sb
->s_id
, function
? ": " : "",
36 function
? function
: "", error_buf
);
39 static int adfs_checkdiscrecord(struct adfs_discrecord
*dr
)
43 /* sector size must be 256, 512 or 1024 bytes */
44 if (dr
->log2secsize
!= 8 &&
45 dr
->log2secsize
!= 9 &&
46 dr
->log2secsize
!= 10)
49 /* idlen must be at least log2secsize + 3 */
50 if (dr
->idlen
< dr
->log2secsize
+ 3)
53 /* we cannot have such a large disc that we
54 * are unable to represent sector offsets in
55 * 32 bits. This works out at 2.0 TB.
57 if (le32_to_cpu(dr
->disc_size_high
) >> dr
->log2secsize
)
60 /* idlen must be no greater than 19 v2 [1.0] */
64 /* reserved bytes should be zero */
65 for (i
= 0; i
< sizeof(dr
->unused52
); i
++)
66 if (dr
->unused52
[i
] != 0)
72 static unsigned char adfs_calczonecheck(struct super_block
*sb
, unsigned char *map
)
74 unsigned int v0
, v1
, v2
, v3
;
77 v0
= v1
= v2
= v3
= 0;
78 for (i
= sb
->s_blocksize
- 4; i
; i
-= 4) {
79 v0
+= map
[i
] + (v3
>> 8);
81 v1
+= map
[i
+ 1] + (v0
>> 8);
83 v2
+= map
[i
+ 2] + (v1
>> 8);
85 v3
+= map
[i
+ 3] + (v2
>> 8);
89 v1
+= map
[1] + (v0
>> 8);
90 v2
+= map
[2] + (v1
>> 8);
91 v3
+= map
[3] + (v2
>> 8);
93 return v0
^ v1
^ v2
^ v3
;
96 static int adfs_checkmap(struct super_block
*sb
, struct adfs_discmap
*dm
)
98 unsigned char crosscheck
= 0, zonecheck
= 1;
101 for (i
= 0; i
< ADFS_SB(sb
)->s_map_size
; i
++) {
104 map
= dm
[i
].dm_bh
->b_data
;
106 if (adfs_calczonecheck(sb
, map
) != map
[0]) {
107 adfs_error(sb
, "zone %d fails zonecheck", i
);
110 crosscheck
^= map
[3];
112 if (crosscheck
!= 0xff)
113 adfs_error(sb
, "crosscheck != 0xff");
114 return crosscheck
== 0xff && zonecheck
;
117 static void adfs_put_super(struct super_block
*sb
)
120 struct adfs_sb_info
*asb
= ADFS_SB(sb
);
122 for (i
= 0; i
< asb
->s_map_size
; i
++)
123 brelse(asb
->s_map
[i
].dm_bh
);
126 sb
->s_fs_info
= NULL
;
129 static int adfs_show_options(struct seq_file
*seq
, struct vfsmount
*mnt
)
131 struct adfs_sb_info
*asb
= ADFS_SB(mnt
->mnt_sb
);
134 seq_printf(seq
, ",uid=%u", asb
->s_uid
);
136 seq_printf(seq
, ",gid=%u", asb
->s_gid
);
137 if (asb
->s_owner_mask
!= ADFS_DEFAULT_OWNER_MASK
)
138 seq_printf(seq
, ",ownmask=%o", asb
->s_owner_mask
);
139 if (asb
->s_other_mask
!= ADFS_DEFAULT_OTHER_MASK
)
140 seq_printf(seq
, ",othmask=%o", asb
->s_other_mask
);
141 if (asb
->s_ftsuffix
!= 0)
142 seq_printf(seq
, ",ftsuffix=%u", asb
->s_ftsuffix
);
147 enum {Opt_uid
, Opt_gid
, Opt_ownmask
, Opt_othmask
, Opt_ftsuffix
, Opt_err
};
149 static const match_table_t tokens
= {
152 {Opt_ownmask
, "ownmask=%o"},
153 {Opt_othmask
, "othmask=%o"},
154 {Opt_ftsuffix
, "ftsuffix=%u"},
158 static int parse_options(struct super_block
*sb
, char *options
)
161 struct adfs_sb_info
*asb
= ADFS_SB(sb
);
167 while ((p
= strsep(&options
, ",")) != NULL
) {
168 substring_t args
[MAX_OPT_ARGS
];
173 token
= match_token(p
, tokens
, args
);
176 if (match_int(args
, &option
))
181 if (match_int(args
, &option
))
186 if (match_octal(args
, &option
))
188 asb
->s_owner_mask
= option
;
191 if (match_octal(args
, &option
))
193 asb
->s_other_mask
= option
;
196 if (match_int(args
, &option
))
198 asb
->s_ftsuffix
= option
;
201 printk("ADFS-fs: unrecognised mount option \"%s\" "
202 "or missing value\n", p
);
209 static int adfs_remount(struct super_block
*sb
, int *flags
, char *data
)
211 *flags
|= MS_NODIRATIME
;
212 return parse_options(sb
, data
);
215 static int adfs_statfs(struct dentry
*dentry
, struct kstatfs
*buf
)
217 struct super_block
*sb
= dentry
->d_sb
;
218 struct adfs_sb_info
*sbi
= ADFS_SB(sb
);
219 u64 id
= huge_encode_dev(sb
->s_bdev
->bd_dev
);
221 buf
->f_type
= ADFS_SUPER_MAGIC
;
222 buf
->f_namelen
= sbi
->s_namelen
;
223 buf
->f_bsize
= sb
->s_blocksize
;
224 buf
->f_blocks
= sbi
->s_size
;
225 buf
->f_files
= sbi
->s_ids_per_zone
* sbi
->s_map_size
;
227 buf
->f_bfree
= adfs_map_free(sb
);
228 buf
->f_ffree
= (long)(buf
->f_bfree
* buf
->f_files
) / (long)buf
->f_blocks
;
229 buf
->f_fsid
.val
[0] = (u32
)id
;
230 buf
->f_fsid
.val
[1] = (u32
)(id
>> 32);
235 static struct kmem_cache
*adfs_inode_cachep
;
237 static struct inode
*adfs_alloc_inode(struct super_block
*sb
)
239 struct adfs_inode_info
*ei
;
240 ei
= (struct adfs_inode_info
*)kmem_cache_alloc(adfs_inode_cachep
, GFP_KERNEL
);
243 return &ei
->vfs_inode
;
246 static void adfs_i_callback(struct rcu_head
*head
)
248 struct inode
*inode
= container_of(head
, struct inode
, i_rcu
);
249 INIT_LIST_HEAD(&inode
->i_dentry
);
250 kmem_cache_free(adfs_inode_cachep
, ADFS_I(inode
));
253 static void adfs_destroy_inode(struct inode
*inode
)
255 call_rcu(&inode
->i_rcu
, adfs_i_callback
);
258 static void init_once(void *foo
)
260 struct adfs_inode_info
*ei
= (struct adfs_inode_info
*) foo
;
262 inode_init_once(&ei
->vfs_inode
);
265 static int init_inodecache(void)
267 adfs_inode_cachep
= kmem_cache_create("adfs_inode_cache",
268 sizeof(struct adfs_inode_info
),
269 0, (SLAB_RECLAIM_ACCOUNT
|
272 if (adfs_inode_cachep
== NULL
)
277 static void destroy_inodecache(void)
279 kmem_cache_destroy(adfs_inode_cachep
);
282 static const struct super_operations adfs_sops
= {
283 .alloc_inode
= adfs_alloc_inode
,
284 .destroy_inode
= adfs_destroy_inode
,
285 .write_inode
= adfs_write_inode
,
286 .put_super
= adfs_put_super
,
287 .statfs
= adfs_statfs
,
288 .remount_fs
= adfs_remount
,
289 .show_options
= adfs_show_options
,
292 static struct adfs_discmap
*adfs_read_map(struct super_block
*sb
, struct adfs_discrecord
*dr
)
294 struct adfs_discmap
*dm
;
295 unsigned int map_addr
, zone_size
, nzones
;
297 struct adfs_sb_info
*asb
= ADFS_SB(sb
);
299 nzones
= asb
->s_map_size
;
300 zone_size
= (8 << dr
->log2secsize
) - le16_to_cpu(dr
->zone_spare
);
301 map_addr
= (nzones
>> 1) * zone_size
-
302 ((nzones
> 1) ? ADFS_DR_SIZE_BITS
: 0);
303 map_addr
= signed_asl(map_addr
, asb
->s_map2blk
);
305 asb
->s_ids_per_zone
= zone_size
/ (asb
->s_idlen
+ 1);
307 dm
= kmalloc(nzones
* sizeof(*dm
), GFP_KERNEL
);
309 adfs_error(sb
, "not enough memory");
313 for (zone
= 0; zone
< nzones
; zone
++, map_addr
++) {
314 dm
[zone
].dm_startbit
= 0;
315 dm
[zone
].dm_endbit
= zone_size
;
316 dm
[zone
].dm_startblk
= zone
* zone_size
- ADFS_DR_SIZE_BITS
;
317 dm
[zone
].dm_bh
= sb_bread(sb
, map_addr
);
319 if (!dm
[zone
].dm_bh
) {
320 adfs_error(sb
, "unable to read map");
325 /* adjust the limits for the first and last map zones */
327 dm
[0].dm_startblk
= 0;
328 dm
[0].dm_startbit
= ADFS_DR_SIZE_BITS
;
329 dm
[i
].dm_endbit
= (le32_to_cpu(dr
->disc_size_high
) << (32 - dr
->log2bpmb
)) +
330 (le32_to_cpu(dr
->disc_size
) >> dr
->log2bpmb
) +
331 (ADFS_DR_SIZE_BITS
- i
* zone_size
);
333 if (adfs_checkmap(sb
, dm
))
336 adfs_error(sb
, "map corrupted");
340 brelse(dm
[zone
].dm_bh
);
346 static inline unsigned long adfs_discsize(struct adfs_discrecord
*dr
, int block_bits
)
348 unsigned long discsize
;
350 discsize
= le32_to_cpu(dr
->disc_size_high
) << (32 - block_bits
);
351 discsize
|= le32_to_cpu(dr
->disc_size
) >> block_bits
;
356 static int adfs_fill_super(struct super_block
*sb
, void *data
, int silent
)
358 struct adfs_discrecord
*dr
;
359 struct buffer_head
*bh
;
360 struct object_info root_obj
;
361 unsigned char *b_data
;
362 struct adfs_sb_info
*asb
;
365 sb
->s_flags
|= MS_NODIRATIME
;
367 asb
= kzalloc(sizeof(*asb
), GFP_KERNEL
);
372 /* set default options */
375 asb
->s_owner_mask
= ADFS_DEFAULT_OWNER_MASK
;
376 asb
->s_other_mask
= ADFS_DEFAULT_OTHER_MASK
;
379 if (parse_options(sb
, data
))
382 sb_set_blocksize(sb
, BLOCK_SIZE
);
383 if (!(bh
= sb_bread(sb
, ADFS_DISCRECORD
/ BLOCK_SIZE
))) {
384 adfs_error(sb
, "unable to read superblock");
388 b_data
= bh
->b_data
+ (ADFS_DISCRECORD
% BLOCK_SIZE
);
390 if (adfs_checkbblk(b_data
)) {
392 printk("VFS: Can't find an adfs filesystem on dev "
397 dr
= (struct adfs_discrecord
*)(b_data
+ ADFS_DR_OFFSET
);
400 * Do some sanity checks on the ADFS disc record
402 if (adfs_checkdiscrecord(dr
)) {
404 printk("VPS: Can't find an adfs filesystem on dev "
410 if (sb_set_blocksize(sb
, 1 << dr
->log2secsize
)) {
411 bh
= sb_bread(sb
, ADFS_DISCRECORD
/ sb
->s_blocksize
);
413 adfs_error(sb
, "couldn't read superblock on "
417 b_data
= bh
->b_data
+ (ADFS_DISCRECORD
% sb
->s_blocksize
);
418 if (adfs_checkbblk(b_data
)) {
419 adfs_error(sb
, "disc record mismatch, very weird!");
422 dr
= (struct adfs_discrecord
*)(b_data
+ ADFS_DR_OFFSET
);
425 printk(KERN_ERR
"VFS: Unsupported blocksize on dev "
431 * blocksize on this device should now be set to the ADFS log2secsize
434 sb
->s_magic
= ADFS_SUPER_MAGIC
;
435 asb
->s_idlen
= dr
->idlen
;
436 asb
->s_map_size
= dr
->nzones
| (dr
->nzones_high
<< 8);
437 asb
->s_map2blk
= dr
->log2bpmb
- dr
->log2secsize
;
438 asb
->s_size
= adfs_discsize(dr
, sb
->s_blocksize_bits
);
439 asb
->s_version
= dr
->format_version
;
440 asb
->s_log2sharesize
= dr
->log2sharesize
;
442 asb
->s_map
= adfs_read_map(sb
, dr
);
449 * set up enough so that we can read an inode
451 sb
->s_op
= &adfs_sops
;
453 dr
= (struct adfs_discrecord
*)(asb
->s_map
[0].dm_bh
->b_data
+ 4);
455 root_obj
.parent_id
= root_obj
.file_id
= le32_to_cpu(dr
->root
);
456 root_obj
.name_len
= 0;
457 /* Set root object date as 01 Jan 1987 00:00:00 */
458 root_obj
.loadaddr
= 0xfff0003f;
459 root_obj
.execaddr
= 0xec22c000;
460 root_obj
.size
= ADFS_NEWDIR_SIZE
;
461 root_obj
.attr
= ADFS_NDA_DIRECTORY
| ADFS_NDA_OWNER_READ
|
462 ADFS_NDA_OWNER_WRITE
| ADFS_NDA_PUBLIC_READ
;
463 root_obj
.filetype
= -1;
466 * If this is a F+ disk with variable length directories,
467 * get the root_size from the disc record.
469 if (asb
->s_version
) {
470 root_obj
.size
= le32_to_cpu(dr
->root_size
);
471 asb
->s_dir
= &adfs_fplus_dir_ops
;
472 asb
->s_namelen
= ADFS_FPLUS_NAME_LEN
;
474 asb
->s_dir
= &adfs_f_dir_ops
;
475 asb
->s_namelen
= ADFS_F_NAME_LEN
;
478 * ,xyz hex filetype suffix may be added by driver
479 * to files that have valid RISC OS filetype
484 sb
->s_d_op
= &adfs_dentry_operations
;
485 root
= adfs_iget(sb
, &root_obj
);
486 sb
->s_root
= d_alloc_root(root
);
490 for (i
= 0; i
< asb
->s_map_size
; i
++)
491 brelse(asb
->s_map
[i
].dm_bh
);
493 adfs_error(sb
, "get root inode failed\n");
501 sb
->s_fs_info
= NULL
;
506 static struct dentry
*adfs_mount(struct file_system_type
*fs_type
,
507 int flags
, const char *dev_name
, void *data
)
509 return mount_bdev(fs_type
, flags
, dev_name
, data
, adfs_fill_super
);
512 static struct file_system_type adfs_fs_type
= {
513 .owner
= THIS_MODULE
,
516 .kill_sb
= kill_block_super
,
517 .fs_flags
= FS_REQUIRES_DEV
,
520 static int __init
init_adfs_fs(void)
522 int err
= init_inodecache();
525 err
= register_filesystem(&adfs_fs_type
);
530 destroy_inodecache();
535 static void __exit
exit_adfs_fs(void)
537 unregister_filesystem(&adfs_fs_type
);
538 destroy_inodecache();
541 module_init(init_adfs_fs
)
542 module_exit(exit_adfs_fs
)
543 MODULE_LICENSE("GPL");