0ec5aaf47aa7757380b206feabf8d6eef39c03a1
[safe/jmp/linux-2.6] / fs / adfs / super.c
1 /*
2  *  linux/fs/adfs/super.c
3  *
4  *  Copyright (C) 1997-1999 Russell King
5  *
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.
9  */
10 #include <linux/module.h>
11 #include <linux/errno.h>
12 #include <linux/fs.h>
13 #include <linux/adfs_fs.h>
14 #include <linux/slab.h>
15 #include <linux/time.h>
16 #include <linux/stat.h>
17 #include <linux/string.h>
18 #include <linux/init.h>
19 #include <linux/buffer_head.h>
20 #include <linux/vfs.h>
21 #include <linux/parser.h>
22 #include <linux/bitops.h>
23 #include <linux/mount.h>
24 #include <linux/seq_file.h>
25
26 #include <asm/uaccess.h>
27 #include <asm/system.h>
28
29 #include <stdarg.h>
30
31 #include "adfs.h"
32 #include "dir_f.h"
33 #include "dir_fplus.h"
34
35 #define ADFS_DEFAULT_OWNER_MASK S_IRWXU
36 #define ADFS_DEFAULT_OTHER_MASK (S_IRWXG | S_IRWXO)
37
38 void __adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
39 {
40         char error_buf[128];
41         va_list args;
42
43         va_start(args, fmt);
44         vsnprintf(error_buf, sizeof(error_buf), fmt, args);
45         va_end(args);
46
47         printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n",
48                 sb->s_id, function ? ": " : "",
49                 function ? function : "", error_buf);
50 }
51
52 static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
53 {
54         int i;
55
56         /* sector size must be 256, 512 or 1024 bytes */
57         if (dr->log2secsize != 8 &&
58             dr->log2secsize != 9 &&
59             dr->log2secsize != 10)
60                 return 1;
61
62         /* idlen must be at least log2secsize + 3 */
63         if (dr->idlen < dr->log2secsize + 3)
64                 return 1;
65
66         /* we cannot have such a large disc that we
67          * are unable to represent sector offsets in
68          * 32 bits.  This works out at 2.0 TB.
69          */
70         if (le32_to_cpu(dr->disc_size_high) >> dr->log2secsize)
71                 return 1;
72
73         /* idlen must be no greater than 19 v2 [1.0] */
74         if (dr->idlen > 19)
75                 return 1;
76
77         /* reserved bytes should be zero */
78         for (i = 0; i < sizeof(dr->unused52); i++)
79                 if (dr->unused52[i] != 0)
80                         return 1;
81
82         return 0;
83 }
84
85 static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
86 {
87         unsigned int v0, v1, v2, v3;
88         int i;
89
90         v0 = v1 = v2 = v3 = 0;
91         for (i = sb->s_blocksize - 4; i; i -= 4) {
92                 v0 += map[i]     + (v3 >> 8);
93                 v3 &= 0xff;
94                 v1 += map[i + 1] + (v0 >> 8);
95                 v0 &= 0xff;
96                 v2 += map[i + 2] + (v1 >> 8);
97                 v1 &= 0xff;
98                 v3 += map[i + 3] + (v2 >> 8);
99                 v2 &= 0xff;
100         }
101         v0 +=           v3 >> 8;
102         v1 += map[1] + (v0 >> 8);
103         v2 += map[2] + (v1 >> 8);
104         v3 += map[3] + (v2 >> 8);
105
106         return v0 ^ v1 ^ v2 ^ v3;
107 }
108
109 static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
110 {
111         unsigned char crosscheck = 0, zonecheck = 1;
112         int i;
113
114         for (i = 0; i < ADFS_SB(sb)->s_map_size; i++) {
115                 unsigned char *map;
116
117                 map = dm[i].dm_bh->b_data;
118
119                 if (adfs_calczonecheck(sb, map) != map[0]) {
120                         adfs_error(sb, "zone %d fails zonecheck", i);
121                         zonecheck = 0;
122                 }
123                 crosscheck ^= map[3];
124         }
125         if (crosscheck != 0xff)
126                 adfs_error(sb, "crosscheck != 0xff");
127         return crosscheck == 0xff && zonecheck;
128 }
129
130 static void adfs_put_super(struct super_block *sb)
131 {
132         int i;
133         struct adfs_sb_info *asb = ADFS_SB(sb);
134
135         lock_kernel();
136
137         for (i = 0; i < asb->s_map_size; i++)
138                 brelse(asb->s_map[i].dm_bh);
139         kfree(asb->s_map);
140         kfree(asb);
141         sb->s_fs_info = NULL;
142
143         unlock_kernel();
144 }
145
146 static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
147 {
148         struct adfs_sb_info *asb = ADFS_SB(mnt->mnt_sb);
149
150         if (asb->s_uid != 0)
151                 seq_printf(seq, ",uid=%u", asb->s_uid);
152         if (asb->s_gid != 0)
153                 seq_printf(seq, ",gid=%u", asb->s_gid);
154         if (asb->s_owner_mask != ADFS_DEFAULT_OWNER_MASK)
155                 seq_printf(seq, ",ownmask=%o", asb->s_owner_mask);
156         if (asb->s_other_mask != ADFS_DEFAULT_OTHER_MASK)
157                 seq_printf(seq, ",othmask=%o", asb->s_other_mask);
158
159         return 0;
160 }
161
162 enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
163
164 static const match_table_t tokens = {
165         {Opt_uid, "uid=%u"},
166         {Opt_gid, "gid=%u"},
167         {Opt_ownmask, "ownmask=%o"},
168         {Opt_othmask, "othmask=%o"},
169         {Opt_err, NULL}
170 };
171
172 static int parse_options(struct super_block *sb, char *options)
173 {
174         char *p;
175         struct adfs_sb_info *asb = ADFS_SB(sb);
176         int option;
177
178         if (!options)
179                 return 0;
180
181         while ((p = strsep(&options, ",")) != NULL) {
182                 substring_t args[MAX_OPT_ARGS];
183                 int token;
184                 if (!*p)
185                         continue;
186
187                 token = match_token(p, tokens, args);
188                 switch (token) {
189                 case Opt_uid:
190                         if (match_int(args, &option))
191                                 return -EINVAL;
192                         asb->s_uid = option;
193                         break;
194                 case Opt_gid:
195                         if (match_int(args, &option))
196                                 return -EINVAL;
197                         asb->s_gid = option;
198                         break;
199                 case Opt_ownmask:
200                         if (match_octal(args, &option))
201                                 return -EINVAL;
202                         asb->s_owner_mask = option;
203                         break;
204                 case Opt_othmask:
205                         if (match_octal(args, &option))
206                                 return -EINVAL;
207                         asb->s_other_mask = option;
208                         break;
209                 default:
210                         printk("ADFS-fs: unrecognised mount option \"%s\" "
211                                         "or missing value\n", p);
212                         return -EINVAL;
213                 }
214         }
215         return 0;
216 }
217
218 static int adfs_remount(struct super_block *sb, int *flags, char *data)
219 {
220         *flags |= MS_NODIRATIME;
221         return parse_options(sb, data);
222 }
223
224 static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
225 {
226         struct super_block *sb = dentry->d_sb;
227         struct adfs_sb_info *sbi = ADFS_SB(sb);
228         u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
229
230         buf->f_type    = ADFS_SUPER_MAGIC;
231         buf->f_namelen = sbi->s_namelen;
232         buf->f_bsize   = sb->s_blocksize;
233         buf->f_blocks  = sbi->s_size;
234         buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
235         buf->f_bavail  =
236         buf->f_bfree   = adfs_map_free(sb);
237         buf->f_ffree   = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
238         buf->f_fsid.val[0] = (u32)id;
239         buf->f_fsid.val[1] = (u32)(id >> 32);
240
241         return 0;
242 }
243
244 static struct kmem_cache *adfs_inode_cachep;
245
246 static struct inode *adfs_alloc_inode(struct super_block *sb)
247 {
248         struct adfs_inode_info *ei;
249         ei = (struct adfs_inode_info *)kmem_cache_alloc(adfs_inode_cachep, GFP_KERNEL);
250         if (!ei)
251                 return NULL;
252         return &ei->vfs_inode;
253 }
254
255 static void adfs_destroy_inode(struct inode *inode)
256 {
257         kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
258 }
259
260 static void init_once(void *foo)
261 {
262         struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
263
264         inode_init_once(&ei->vfs_inode);
265 }
266
267 static int init_inodecache(void)
268 {
269         adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
270                                              sizeof(struct adfs_inode_info),
271                                              0, (SLAB_RECLAIM_ACCOUNT|
272                                                 SLAB_MEM_SPREAD),
273                                              init_once);
274         if (adfs_inode_cachep == NULL)
275                 return -ENOMEM;
276         return 0;
277 }
278
279 static void destroy_inodecache(void)
280 {
281         kmem_cache_destroy(adfs_inode_cachep);
282 }
283
284 static const struct super_operations adfs_sops = {
285         .alloc_inode    = adfs_alloc_inode,
286         .destroy_inode  = adfs_destroy_inode,
287         .write_inode    = adfs_write_inode,
288         .put_super      = adfs_put_super,
289         .statfs         = adfs_statfs,
290         .remount_fs     = adfs_remount,
291         .show_options   = adfs_show_options,
292 };
293
294 static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
295 {
296         struct adfs_discmap *dm;
297         unsigned int map_addr, zone_size, nzones;
298         int i, zone;
299         struct adfs_sb_info *asb = ADFS_SB(sb);
300
301         nzones    = asb->s_map_size;
302         zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
303         map_addr  = (nzones >> 1) * zone_size -
304                      ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
305         map_addr  = signed_asl(map_addr, asb->s_map2blk);
306
307         asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
308
309         dm = kmalloc(nzones * sizeof(*dm), GFP_KERNEL);
310         if (dm == NULL) {
311                 adfs_error(sb, "not enough memory");
312                 return NULL;
313         }
314
315         for (zone = 0; zone < nzones; zone++, map_addr++) {
316                 dm[zone].dm_startbit = 0;
317                 dm[zone].dm_endbit   = zone_size;
318                 dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
319                 dm[zone].dm_bh       = sb_bread(sb, map_addr);
320
321                 if (!dm[zone].dm_bh) {
322                         adfs_error(sb, "unable to read map");
323                         goto error_free;
324                 }
325         }
326
327         /* adjust the limits for the first and last map zones */
328         i = zone - 1;
329         dm[0].dm_startblk = 0;
330         dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
331         dm[i].dm_endbit   = (le32_to_cpu(dr->disc_size_high) << (32 - dr->log2bpmb)) +
332                             (le32_to_cpu(dr->disc_size) >> dr->log2bpmb) +
333                             (ADFS_DR_SIZE_BITS - i * zone_size);
334
335         if (adfs_checkmap(sb, dm))
336                 return dm;
337
338         adfs_error(sb, "map corrupted");
339
340 error_free:
341         while (--zone >= 0)
342                 brelse(dm[zone].dm_bh);
343
344         kfree(dm);
345         return NULL;
346 }
347
348 static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits)
349 {
350         unsigned long discsize;
351
352         discsize  = le32_to_cpu(dr->disc_size_high) << (32 - block_bits);
353         discsize |= le32_to_cpu(dr->disc_size) >> block_bits;
354
355         return discsize;
356 }
357
358 static int adfs_fill_super(struct super_block *sb, void *data, int silent)
359 {
360         struct adfs_discrecord *dr;
361         struct buffer_head *bh;
362         struct object_info root_obj;
363         unsigned char *b_data;
364         struct adfs_sb_info *asb;
365         struct inode *root;
366
367         sb->s_flags |= MS_NODIRATIME;
368
369         asb = kzalloc(sizeof(*asb), GFP_KERNEL);
370         if (!asb)
371                 return -ENOMEM;
372         sb->s_fs_info = asb;
373
374         /* set default options */
375         asb->s_uid = 0;
376         asb->s_gid = 0;
377         asb->s_owner_mask = ADFS_DEFAULT_OWNER_MASK;
378         asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK;
379
380         if (parse_options(sb, data))
381                 goto error;
382
383         sb_set_blocksize(sb, BLOCK_SIZE);
384         if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
385                 adfs_error(sb, "unable to read superblock");
386                 goto error;
387         }
388
389         b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
390
391         if (adfs_checkbblk(b_data)) {
392                 if (!silent)
393                         printk("VFS: Can't find an adfs filesystem on dev "
394                                 "%s.\n", sb->s_id);
395                 goto error_free_bh;
396         }
397
398         dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
399
400         /*
401          * Do some sanity checks on the ADFS disc record
402          */
403         if (adfs_checkdiscrecord(dr)) {
404                 if (!silent)
405                         printk("VPS: Can't find an adfs filesystem on dev "
406                                 "%s.\n", sb->s_id);
407                 goto error_free_bh;
408         }
409
410         brelse(bh);
411         if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
412                 bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
413                 if (!bh) {
414                         adfs_error(sb, "couldn't read superblock on "
415                                 "2nd try.");
416                         goto error;
417                 }
418                 b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
419                 if (adfs_checkbblk(b_data)) {
420                         adfs_error(sb, "disc record mismatch, very weird!");
421                         goto error_free_bh;
422                 }
423                 dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
424         } else {
425                 if (!silent)
426                         printk(KERN_ERR "VFS: Unsupported blocksize on dev "
427                                 "%s.\n", sb->s_id);
428                 goto error;
429         }
430
431         /*
432          * blocksize on this device should now be set to the ADFS log2secsize
433          */
434
435         sb->s_magic             = ADFS_SUPER_MAGIC;
436         asb->s_idlen            = dr->idlen;
437         asb->s_map_size         = dr->nzones | (dr->nzones_high << 8);
438         asb->s_map2blk          = dr->log2bpmb - dr->log2secsize;
439         asb->s_size             = adfs_discsize(dr, sb->s_blocksize_bits);
440         asb->s_version          = dr->format_version;
441         asb->s_log2sharesize    = dr->log2sharesize;
442         
443         asb->s_map = adfs_read_map(sb, dr);
444         if (!asb->s_map)
445                 goto error_free_bh;
446
447         brelse(bh);
448
449         /*
450          * set up enough so that we can read an inode
451          */
452         sb->s_op = &adfs_sops;
453
454         dr = (struct adfs_discrecord *)(asb->s_map[0].dm_bh->b_data + 4);
455
456         root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
457         root_obj.name_len  = 0;
458         root_obj.loadaddr  = 0;
459         root_obj.execaddr  = 0;
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
464         /*
465          * If this is a F+ disk with variable length directories,
466          * get the root_size from the disc record.
467          */
468         if (asb->s_version) {
469                 root_obj.size = le32_to_cpu(dr->root_size);
470                 asb->s_dir     = &adfs_fplus_dir_ops;
471                 asb->s_namelen = ADFS_FPLUS_NAME_LEN;
472         } else {
473                 asb->s_dir     = &adfs_f_dir_ops;
474                 asb->s_namelen = ADFS_F_NAME_LEN;
475         }
476
477         root = adfs_iget(sb, &root_obj);
478         sb->s_root = d_alloc_root(root);
479         if (!sb->s_root) {
480                 int i;
481                 iput(root);
482                 for (i = 0; i < asb->s_map_size; i++)
483                         brelse(asb->s_map[i].dm_bh);
484                 kfree(asb->s_map);
485                 adfs_error(sb, "get root inode failed\n");
486                 goto error;
487         } else
488                 sb->s_root->d_op = &adfs_dentry_operations;
489         return 0;
490
491 error_free_bh:
492         brelse(bh);
493 error:
494         sb->s_fs_info = NULL;
495         kfree(asb);
496         return -EINVAL;
497 }
498
499 static int adfs_get_sb(struct file_system_type *fs_type,
500         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
501 {
502         return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super,
503                            mnt);
504 }
505
506 static struct file_system_type adfs_fs_type = {
507         .owner          = THIS_MODULE,
508         .name           = "adfs",
509         .get_sb         = adfs_get_sb,
510         .kill_sb        = kill_block_super,
511         .fs_flags       = FS_REQUIRES_DEV,
512 };
513
514 static int __init init_adfs_fs(void)
515 {
516         int err = init_inodecache();
517         if (err)
518                 goto out1;
519         err = register_filesystem(&adfs_fs_type);
520         if (err)
521                 goto out;
522         return 0;
523 out:
524         destroy_inodecache();
525 out1:
526         return err;
527 }
528
529 static void __exit exit_adfs_fs(void)
530 {
531         unregister_filesystem(&adfs_fs_type);
532         destroy_inodecache();
533 }
534
535 module_init(init_adfs_fs)
536 module_exit(exit_adfs_fs)