2 * linux/fs/adfs/super.c
4 * Copyright (C) 1997 Russell King
7 #include <linux/module.h>
8 #include <linux/errno.h>
10 #include <linux/adfs_fs.h>
11 #include <linux/malloc.h>
12 #include <linux/sched.h>
13 #include <linux/stat.h>
14 #include <linux/string.h>
15 #include <linux/locks.h>
16 #include <linux/init.h>
18 #include <asm/bitops.h>
19 #include <asm/uaccess.h>
20 #include <asm/system.h>
24 static void adfs_put_super(struct super_block
*sb
);
25 static int adfs_remount(struct super_block
*sb
, int *flags
, char *data
);
26 static int adfs_statfs(struct super_block
*sb
, struct statfs
*buf
, int bufsiz
);
27 void adfs_read_inode(struct inode
*inode
);
29 void adfs_error(struct super_block
*sb
, const char *function
, const char *fmt
, ...)
35 vsprintf(error_buf
, fmt
, args
);
38 printk(KERN_CRIT
"ADFS-fs error (device %s)%s%s: %s\n",
39 kdevname(sb
->s_dev
), function
? ": " : "",
40 function
? function
: "", error_buf
);
43 static unsigned char adfs_calczonecheck(struct super_block
*sb
, char *map
)
45 unsigned int v0
, v1
, v2
, v3
;
48 v0
= v1
= v2
= v3
= 0;
49 for (i
= sb
->s_blocksize
- 4; i
; i
-= 4) {
50 v0
+= map
[i
] + (v3
>> 8);
52 v1
+= map
[i
+ 1] + (v0
>> 8);
54 v2
+= map
[i
+ 2] + (v1
>> 8);
56 v3
+= map
[i
+ 3] + (v2
>> 8);
60 v1
+= map
[1] + (v0
>> 8);
61 v2
+= map
[2] + (v1
>> 8);
62 v3
+= map
[3] + (v2
>> 8);
64 return v0
^ v1
^ v2
^ v3
;
67 static int adfs_checkmap(struct super_block
*sb
)
69 unsigned char crosscheck
= 0, zonecheck
= 1;
72 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++) {
75 map
= sb
->u
.adfs_sb
.s_map
[i
]->b_data
;
76 if (adfs_calczonecheck(sb
, map
) != map
[0]) {
77 adfs_error(sb
, "adfs_checkmap", "zone %d fails zonecheck", i
);
82 if (crosscheck
!= 0xff)
83 adfs_error(sb
, "adfs_checkmap", "crosscheck != 0xff");
84 return crosscheck
== 0xff && zonecheck
;
87 static struct super_operations adfs_sops
= {
99 static void adfs_put_super(struct super_block
*sb
)
103 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++)
104 brelse(sb
->u
.adfs_sb
.s_map
[i
]);
105 kfree(sb
->u
.adfs_sb
.s_map
);
106 brelse(sb
->u
.adfs_sb
.s_sbh
);
110 static int parse_options(struct super_block
*sb
, char *options
)
117 for (opt
= strtok(options
, ","); opt
!= NULL
; opt
= strtok(NULL
, ",")) {
118 value
= strchr(opt
, '=');
122 if (!strcmp(opt
, "uid")) { /* owner of all files */
123 if (!value
|| !*value
)
125 sb
->u
.adfs_sb
.s_uid
= simple_strtoul(value
, &value
, 0);
129 if (!strcmp(opt
, "gid")) { /* group owner of all files */
130 if (!value
|| !*value
)
132 sb
->u
.adfs_sb
.s_gid
= simple_strtoul(value
, &value
, 0);
136 if (!strcmp(opt
, "ownmask")) { /* owner permission mask */
137 if (!value
|| !*value
)
139 sb
->u
.adfs_sb
.s_owner_mask
= simple_strtoul(value
, &value
, 8);
143 if (!strcmp(opt
, "othmask")) { /* others permission mask */
144 if (!value
|| !*value
)
146 sb
->u
.adfs_sb
.s_other_mask
= simple_strtoul(value
, &value
, 8);
149 } else { /* eh? say again. */
150 printk("ADFS-fs: unrecognised mount option %s\n", opt
);
157 static int adfs_remount(struct super_block
*sb
, int *flags
, char *data
)
159 return parse_options(sb
, data
);
162 struct super_block
*adfs_read_super(struct super_block
*sb
, void *data
, int silent
)
164 struct adfs_discrecord
*dr
;
165 struct buffer_head
*bh
;
166 unsigned char *b_data
;
167 kdev_t dev
= sb
->s_dev
;
170 /* set default options */
171 sb
->u
.adfs_sb
.s_uid
= 0;
172 sb
->u
.adfs_sb
.s_gid
= 0;
173 sb
->u
.adfs_sb
.s_owner_mask
= S_IRWXU
;
174 sb
->u
.adfs_sb
.s_other_mask
= S_IRWXG
| S_IRWXO
;
176 if (parse_options(sb
, data
))
181 set_blocksize(dev
, BLOCK_SIZE
);
182 if (!(bh
= bread(dev
, ADFS_DISCRECORD
/ BLOCK_SIZE
, BLOCK_SIZE
))) {
183 adfs_error(sb
, NULL
, "unable to read superblock");
187 b_data
= bh
->b_data
+ (ADFS_DISCRECORD
% BLOCK_SIZE
);
189 if (adfs_checkbblk(b_data
)) {
191 printk("VFS: Can't find an adfs filesystem on dev "
192 "%s.\n", kdevname(dev
));
195 dr
= (struct adfs_discrecord
*)(b_data
+ ADFS_DR_OFFSET
);
197 sb
->s_blocksize_bits
= dr
->log2secsize
;
198 sb
->s_blocksize
= 1 << sb
->s_blocksize_bits
;
199 if (sb
->s_blocksize
!= BLOCK_SIZE
&&
200 (sb
->s_blocksize
== 512 || sb
->s_blocksize
== 1024 ||
201 sb
->s_blocksize
== 2048 || sb
->s_blocksize
== 4096)) {
204 set_blocksize(dev
, sb
->s_blocksize
);
205 bh
= bread(dev
, ADFS_DISCRECORD
/ sb
->s_blocksize
, sb
->s_blocksize
);
207 adfs_error(sb
, NULL
, "couldn't read superblock on "
211 b_data
= bh
->b_data
+ (ADFS_DISCRECORD
% sb
->s_blocksize
);
212 if (adfs_checkbblk(b_data
)) {
213 adfs_error(sb
, NULL
, "disc record mismatch, very weird!");
216 dr
= (struct adfs_discrecord
*)(b_data
+ ADFS_DR_OFFSET
);
218 if (sb
->s_blocksize
!= bh
->b_size
) {
220 printk(KERN_ERR
"VFS: Unsupported blocksize on dev "
221 "%s.\n", kdevname(dev
));
224 /* blocksize on this device should now be set to the adfs log2secsize */
226 sb
->u
.adfs_sb
.s_sbh
= bh
;
227 sb
->u
.adfs_sb
.s_dr
= dr
;
229 /* s_zone_size = size of 1 zone (1 sector) * bits_in_byte - zone_spare =>
230 * number of map bits in a zone
232 sb
->u
.adfs_sb
.s_zone_size
= (8 << dr
->log2secsize
) - dr
->zone_spare
;
234 /* s_ids_per_zone = bit size of 1 zone / min. length of fragment block =>
235 * number of ids in one zone
237 sb
->u
.adfs_sb
.s_ids_per_zone
= sb
->u
.adfs_sb
.s_zone_size
/ (dr
->idlen
+ 1);
239 /* s_idlen = length of 1 id */
240 sb
->u
.adfs_sb
.s_idlen
= dr
->idlen
;
242 /* map size (in sectors) = number of zones */
243 sb
->u
.adfs_sb
.s_map_size
= dr
->nzones
;
245 /* zonesize = size of sector - zonespare */
246 sb
->u
.adfs_sb
.s_zonesize
= (sb
->s_blocksize
<< 3) - dr
->zone_spare
;
248 /* map start (in sectors) = start of zone (number of zones) / 2 */
249 sb
->u
.adfs_sb
.s_map_block
= (dr
->nzones
>> 1) * sb
->u
.adfs_sb
.s_zone_size
-
250 ((dr
->nzones
> 1) ? 8 * ADFS_DR_SIZE
: 0);
252 /* (signed) number of bits to shift left a map address to a sector address */
253 sb
->u
.adfs_sb
.s_map2blk
= dr
->log2bpmb
- dr
->log2secsize
;
255 if (sb
->u
.adfs_sb
.s_map2blk
>= 0)
256 sb
->u
.adfs_sb
.s_map_block
<<= sb
->u
.adfs_sb
.s_map2blk
;
258 sb
->u
.adfs_sb
.s_map_block
>>= -sb
->u
.adfs_sb
.s_map2blk
;
260 printk(KERN_DEBUG
"ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n",
261 sb
->u
.adfs_sb
.s_zone_size
, sb
->u
.adfs_sb
.s_ids_per_zone
,
262 sb
->u
.adfs_sb
.s_map_block
, sb
->u
.adfs_sb
.s_map_size
);
263 printk(KERN_DEBUG
"ADFS: sector size %d, map bit size %d, share size %d\n",
264 1 << dr
->log2secsize
, 1 << dr
->log2bpmb
,
265 1 << (dr
->log2secsize
+ dr
->log2sharesize
));
267 sb
->s_magic
= ADFS_SUPER_MAGIC
;
269 sb
->u
.adfs_sb
.s_map
= kmalloc(sb
->u
.adfs_sb
.s_map_size
*
270 sizeof(struct buffer_head
*), GFP_KERNEL
);
271 if (sb
->u
.adfs_sb
.s_map
== NULL
) {
272 adfs_error(sb
, NULL
, "not enough memory");
276 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++) {
277 sb
->u
.adfs_sb
.s_map
[i
] = bread(dev
,
278 sb
->u
.adfs_sb
.s_map_block
+ i
,
280 if (!sb
->u
.adfs_sb
.s_map
[i
]) {
281 for (j
= 0; j
< i
; j
++)
282 brelse(sb
->u
.adfs_sb
.s_map
[j
]);
283 kfree(sb
->u
.adfs_sb
.s_map
);
284 adfs_error(sb
, NULL
, "unable to read map");
288 if (!adfs_checkmap(sb
)) {
289 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++)
290 brelse(sb
->u
.adfs_sb
.s_map
[i
]);
291 adfs_error(sb
, NULL
, "map corrupted");
295 dr
= (struct adfs_discrecord
*)(sb
->u
.adfs_sb
.s_map
[0]->b_data
+ 4);
299 * set up enough so that it can read an inode
301 sb
->s_op
= &adfs_sops
;
302 sb
->u
.adfs_sb
.s_root
= adfs_inode_generate(dr
->root
, 0);
303 sb
->s_root
= d_alloc_root(iget(sb
, sb
->u
.adfs_sb
.s_root
), NULL
);
306 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++)
307 brelse(sb
->u
.adfs_sb
.s_map
[i
]);
309 adfs_error(sb
, NULL
, "get root inode failed\n");
326 static int adfs_statfs(struct super_block
*sb
, struct statfs
*buf
, int bufsiz
)
329 const unsigned int nidlen
= sb
->u
.adfs_sb
.s_idlen
+ 1;
331 tmp
.f_type
= ADFS_SUPER_MAGIC
;
332 tmp
.f_bsize
= sb
->s_blocksize
;
333 tmp
.f_blocks
= sb
->u
.adfs_sb
.s_dr
->disc_size_high
<< (32 - sb
->s_blocksize_bits
) |
334 sb
->u
.adfs_sb
.s_dr
->disc_size
>> sb
->s_blocksize_bits
;
335 tmp
.f_files
= tmp
.f_blocks
>> nidlen
;
337 unsigned int i
, j
= 0;
338 const unsigned mask
= (1 << (nidlen
- 1)) - 1;
339 for (i
= 0; i
< sb
->u
.adfs_sb
.s_map_size
; i
++) {
340 const char *map
= sb
->u
.adfs_sb
.s_map
[i
]->b_data
;
341 unsigned freelink
, mapindex
= 24;
344 unsigned char k
, l
, m
;
345 unsigned off
= (mapindex
- nidlen
) >> 3;
347 const unsigned boff
= mapindex
& 7;
349 /* get next freelink */
354 freelink
= (m
<< 16) | (l
<< 8) | k
;
355 rem
= freelink
>> (boff
+ nidlen
- 1);
356 freelink
= (freelink
>> boff
) & mask
;
357 mapindex
+= freelink
;
359 /* find its length and add it to running total */
365 if ((rem
& 0xff) == 0) j
+=8, rem
>>=8;
366 if ((rem
& 0xf) == 0) j
+=4, rem
>>=4;
367 if ((rem
& 0x3) == 0) j
+=2, rem
>>=2;
368 if ((rem
& 0x1) == 0) j
+=1;
370 if (freelink
<= nidlen
) break;
371 } while (mapindex
< 8 * sb
->s_blocksize
);
372 if (mapindex
> 8 * sb
->s_blocksize
)
373 adfs_error(sb
, NULL
, "oversized free fragment\n");
375 adfs_error(sb
, NULL
, "undersized free fragment\n");
377 tmp
.f_bfree
= tmp
.f_bavail
= j
<<
378 (sb
->u
.adfs_sb
.s_dr
->log2bpmb
- sb
->s_blocksize_bits
);
380 tmp
.f_ffree
= tmp
.f_bfree
>> nidlen
;
381 tmp
.f_namelen
= ADFS_NAME_LEN
;
382 return copy_to_user(buf
, &tmp
, bufsiz
) ? -EFAULT
: 0;
385 static struct file_system_type adfs_fs_type
= {
386 "adfs", FS_REQUIRES_DEV
, adfs_read_super
, NULL
389 __initfunc(int init_adfs_fs(void))
391 return register_filesystem(&adfs_fs_type
);
395 int init_module(void)
397 return init_adfs_fs();
400 void cleanup_module(void)
402 unregister_filesystem(&adfs_fs_type
);