Import 2.2.5pre2
[davej-history.git] / fs / adfs / super.c
blob8c2fbe8fa62347032c27c18ad6160ffb61f250f0
1 /*
2 * linux/fs/adfs/super.c
4 * Copyright (C) 1997 Russell King
5 */
7 #include <linux/module.h>
8 #include <linux/errno.h>
9 #include <linux/fs.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>
22 #include <stdarg.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, ...)
31 char error_buf[128];
32 va_list args;
34 va_start(args, fmt);
35 vsprintf(error_buf, fmt, args);
36 va_end(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;
46 int i;
48 v0 = v1 = v2 = v3 = 0;
49 for (i = sb->s_blocksize - 4; i; i -= 4) {
50 v0 += map[i] + (v3 >> 8);
51 v3 &= 0xff;
52 v1 += map[i + 1] + (v0 >> 8);
53 v0 &= 0xff;
54 v2 += map[i + 2] + (v1 >> 8);
55 v1 &= 0xff;
56 v3 += map[i + 3] + (v2 >> 8);
57 v2 &= 0xff;
59 v0 += v3 >> 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;
70 int i;
72 for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) {
73 char *map;
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);
78 zonecheck = 0;
80 crosscheck ^= map[3];
82 if (crosscheck != 0xff)
83 adfs_error(sb, "adfs_checkmap", "crosscheck != 0xff");
84 return crosscheck == 0xff && zonecheck;
87 static struct super_operations adfs_sops = {
88 adfs_read_inode,
89 NULL,
90 NULL,
91 NULL,
92 NULL,
93 adfs_put_super,
94 NULL,
95 adfs_statfs,
96 adfs_remount
99 static void adfs_put_super(struct super_block *sb)
101 int i;
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);
107 MOD_DEC_USE_COUNT;
110 static int parse_options(struct super_block *sb, char *options)
112 char *value, *opt;
114 if (!options)
115 return 0;
117 for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) {
118 value = strchr(opt, '=');
119 if (value)
120 *value++ = '\0';
122 if (!strcmp(opt, "uid")) { /* owner of all files */
123 if (!value || !*value)
124 return -EINVAL;
125 sb->u.adfs_sb.s_uid = simple_strtoul(value, &value, 0);
126 if (*value)
127 return -EINVAL;
128 } else
129 if (!strcmp(opt, "gid")) { /* group owner of all files */
130 if (!value || !*value)
131 return -EINVAL;
132 sb->u.adfs_sb.s_gid = simple_strtoul(value, &value, 0);
133 if (*value)
134 return -EINVAL;
135 } else
136 if (!strcmp(opt, "ownmask")) { /* owner permission mask */
137 if (!value || !*value)
138 return -EINVAL;
139 sb->u.adfs_sb.s_owner_mask = simple_strtoul(value, &value, 8);
140 if (*value)
141 return -EINVAL;
142 } else
143 if (!strcmp(opt, "othmask")) { /* others permission mask */
144 if (!value || !*value)
145 return -EINVAL;
146 sb->u.adfs_sb.s_other_mask = simple_strtoul(value, &value, 8);
147 if (*value)
148 return -EINVAL;
149 } else { /* eh? say again. */
150 printk("ADFS-fs: unrecognised mount option %s\n", opt);
151 return -EINVAL;
154 return 0;
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;
168 int i, j;
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))
177 goto error;
179 MOD_INC_USE_COUNT;
180 lock_super(sb);
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");
184 goto error_unlock;
187 b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
189 if (adfs_checkbblk(b_data)) {
190 if (!silent)
191 printk("VFS: Can't find an adfs filesystem on dev "
192 "%s.\n", kdevname(dev));
193 goto error_free_bh;
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)) {
203 brelse(bh);
204 set_blocksize(dev, sb->s_blocksize);
205 bh = bread(dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize);
206 if (!bh) {
207 adfs_error(sb, NULL, "couldn't read superblock on "
208 "2nd try.");
209 goto error_unlock;
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!");
214 goto error_free_bh;
216 dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
218 if (sb->s_blocksize != bh->b_size) {
219 if (!silent)
220 printk(KERN_ERR "VFS: Unsupported blocksize on dev "
221 "%s.\n", kdevname(dev));
222 goto error_free_bh;
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;
257 else
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");
273 goto error_free_bh;
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,
279 sb->s_blocksize);
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");
285 goto error_free_bh;
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");
292 goto error_free_bh;
295 dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0]->b_data + 4);
296 unlock_super(sb);
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);
305 if (!sb->s_root) {
306 for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
307 brelse(sb->u.adfs_sb.s_map[i]);
308 brelse(bh);
309 adfs_error(sb, NULL, "get root inode failed\n");
310 goto error_dec_use;
312 return sb;
314 error_free_bh:
315 if (bh)
316 brelse(bh);
317 error_unlock:
318 unlock_super(sb);
319 error_dec_use:
320 MOD_DEC_USE_COUNT;
321 error:
322 sb->s_dev = 0;
323 return NULL;
326 static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
328 struct statfs tmp;
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;
342 j -= nidlen;
343 do {
344 unsigned char k, l, m;
345 unsigned off = (mapindex - nidlen) >> 3;
346 unsigned rem;
347 const unsigned boff = mapindex & 7;
349 /* get next freelink */
351 k = map[off++];
352 l = map[off++];
353 m = map[off++];
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 */
361 while (rem == 0) {
362 j += 8;
363 rem = map[off++];
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;
369 j += nidlen - boff;
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");
374 else if (freelink)
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);
394 #ifdef MODULE
395 int init_module(void)
397 return init_adfs_fs();
400 void cleanup_module(void)
402 unregister_filesystem(&adfs_fs_type);
404 #endif