Blame view

fs/affs/super.c 15.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   *  linux/fs/affs/inode.c
   *
   *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   *
   *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   *
   *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
   *
   *  (C) 1991  Linus Torvalds - minix filesystem
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/statfs.h>
  #include <linux/parser.h>
e18fa700c   Jeff Garzik   Move several *_SU...
17
  #include <linux/magic.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
18
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
3dd847820   Artem Bityutskiy   affs: get rid of ...
20
  #include <linux/writeback.h>
e852d82a5   Pranay Kr. Srivastava   fs/affs: make roo...
21
  #include <linux/blkdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include "affs.h"
726c33422   David Howells   [PATCH] VFS: Perm...
23
  static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  static int affs_remount (struct super_block *sb, int *flags, char *data);
  
  static void
bc86256d2   Artem Bityutskiy   affs: stop settin...
27
  affs_commit_super(struct super_block *sb, int wait)
e28964365   Christoph Hellwig   affs: add ->sync_fs
28
29
30
31
  {
  	struct affs_sb_info *sbi = AFFS_SB(sb);
  	struct buffer_head *bh = sbi->s_root_bh;
  	struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);
a83710743   Artem Bityutskiy   affs: stop using ...
32
  	lock_buffer(bh);
db39c1672   DengChao   fs:affs:Replace t...
33
  	secs_to_datestamp(ktime_get_real_seconds(), &tail->disk_change);
e28964365   Christoph Hellwig   affs: add ->sync_fs
34
  	affs_fix_checksum(sb, bh);
a83710743   Artem Bityutskiy   affs: stop using ...
35
  	unlock_buffer(bh);
e28964365   Christoph Hellwig   affs: add ->sync_fs
36
  	mark_buffer_dirty(bh);
7435d5061   Artem Bityutskiy   AFFS: wait for sb...
37
38
  	if (wait)
  		sync_dirty_buffer(bh);
e28964365   Christoph Hellwig   affs: add ->sync_fs
39
40
41
  }
  
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  affs_put_super(struct super_block *sb)
  {
  	struct affs_sb_info *sbi = AFFS_SB(sb);
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
45
46
  	pr_debug("%s()
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

3dd847820   Artem Bityutskiy   affs: get rid of ...
48
  	cancel_delayed_work_sync(&sbi->sb_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  }
e28964365   Christoph Hellwig   affs: add ->sync_fs
50
51
52
  static int
  affs_sync_fs(struct super_block *sb, int wait)
  {
bc86256d2   Artem Bityutskiy   affs: stop settin...
53
  	affs_commit_super(sb, wait);
e28964365   Christoph Hellwig   affs: add ->sync_fs
54
55
  	return 0;
  }
3dd847820   Artem Bityutskiy   affs: get rid of ...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  static void flush_superblock(struct work_struct *work)
  {
  	struct affs_sb_info *sbi;
  	struct super_block *sb;
  
  	sbi = container_of(work, struct affs_sb_info, sb_work.work);
  	sb = sbi->sb;
  
  	spin_lock(&sbi->work_lock);
  	sbi->work_queued = 0;
  	spin_unlock(&sbi->work_lock);
  
  	affs_commit_super(sb, 1);
  }
  
  void affs_mark_sb_dirty(struct super_block *sb)
  {
  	struct affs_sb_info *sbi = AFFS_SB(sb);
  	unsigned long delay;
  
  	if (sb->s_flags & MS_RDONLY)
  	       return;
  
  	spin_lock(&sbi->work_lock);
  	if (!sbi->work_queued) {
  	       delay = msecs_to_jiffies(dirty_writeback_interval * 10);
  	       queue_delayed_work(system_long_wq, &sbi->sb_work, delay);
  	       sbi->work_queued = 1;
  	}
  	spin_unlock(&sbi->work_lock);
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
87
  static struct kmem_cache * affs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
  
  static struct inode *affs_alloc_inode(struct super_block *sb)
  {
dca3c3365   Roman Zippel   [PATCH] fix reser...
91
92
93
94
  	struct affs_inode_info *i;
  
  	i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
  	if (!i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  		return NULL;
dca3c3365   Roman Zippel   [PATCH] fix reser...
96
97
98
99
100
101
102
  
  	i->vfs_inode.i_version = 1;
  	i->i_lc = NULL;
  	i->i_ext_bh = NULL;
  	i->i_pa_cnt = 0;
  
  	return &i->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
104
  static void affs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
106
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  	kmem_cache_free(affs_inode_cachep, AFFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
109
110
111
112
  static void affs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, affs_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
113
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  {
  	struct affs_inode_info *ei = (struct affs_inode_info *) foo;
756b0322e   Thomas Gleixner   affs: Use sema_in...
116
117
  	sema_init(&ei->i_link_lock, 1);
  	sema_init(&ei->i_ext_lock, 1);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
118
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  }
adbd319e5   Fabian Frederick   affs: add __init ...
120
  static int __init init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
  {
  	affs_inode_cachep = kmem_cache_create("affs_inode_cache",
  					     sizeof(struct affs_inode_info),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
124
  					     0, (SLAB_RECLAIM_ACCOUNT|
5d097056c   Vladimir Davydov   kmemcg: account c...
125
  						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
20c2df83d   Paul Mundt   mm: Remove slab d...
126
  					     init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
  	if (affs_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void destroy_inodecache(void)
  {
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
134
135
136
137
138
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
139
  	kmem_cache_destroy(affs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
141
  static const struct super_operations affs_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  	.alloc_inode	= affs_alloc_inode,
  	.destroy_inode	= affs_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	.write_inode	= affs_write_inode,
f053ddde7   Al Viro   switch affs to ->...
145
  	.evict_inode	= affs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	.put_super	= affs_put_super,
e28964365   Christoph Hellwig   affs: add ->sync_fs
147
  	.sync_fs	= affs_sync_fs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
  	.statfs		= affs_statfs,
  	.remount_fs	= affs_remount,
e9b3961b6   Miklos Szeredi   mount options: fi...
150
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
  };
  
  enum {
8ca577223   Fabian Frederick   affs: add mount o...
154
  	Opt_bs, Opt_mode, Opt_mufs, Opt_notruncate, Opt_prefix, Opt_protect,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
  	Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
  	Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
158
  static const match_table_t tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  	{Opt_bs, "bs=%u"},
  	{Opt_mode, "mode=%o"},
  	{Opt_mufs, "mufs"},
8ca577223   Fabian Frederick   affs: add mount o...
162
  	{Opt_notruncate, "nofilenametruncate"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  	{Opt_prefix, "prefix=%s"},
  	{Opt_protect, "protect"},
  	{Opt_reserved, "reserved=%u"},
  	{Opt_root, "root=%u"},
  	{Opt_setgid, "setgid=%u"},
  	{Opt_setuid, "setuid=%u"},
  	{Opt_verbose, "verbose"},
  	{Opt_volume, "volume=%s"},
  	{Opt_ignore, "grpquota"},
  	{Opt_ignore, "noquota"},
  	{Opt_ignore, "quota"},
  	{Opt_ignore, "usrquota"},
  	{Opt_err, NULL},
  };
  
  static int
8fed10be0   Eric W. Biederman   userns: Convert a...
179
  parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, s32 *root,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  		int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
  {
  	char *p;
  	substring_t args[MAX_OPT_ARGS];
  
  	/* Fill in defaults */
215599815   David Howells   CRED: Wrap task c...
186
187
  	*uid        = current_uid();
  	*gid        = current_gid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  	*reserved   = 2;
  	*root       = -1;
  	*blocksize  = -1;
  	volume[0]   = ':';
  	volume[1]   = 0;
  	*mount_opts = 0;
  	if (!options)
  		return 1;
  
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token, n, option;
  		if (!*p)
  			continue;
  
  		token = match_token(p, tokens, args);
  		switch (token) {
  		case Opt_bs:
  			if (match_int(&args[0], &n))
217686e98   Al Viro   fix affs parse_op...
206
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  			if (n != 512 && n != 1024 && n != 2048
  			    && n != 4096) {
0158de12b   Fabian Frederick   fs/affs: convert ...
209
210
  				pr_warn("Invalid blocksize (512, 1024, 2048, 4096 allowed)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
  				return 0;
  			}
  			*blocksize = n;
  			break;
  		case Opt_mode:
  			if (match_octal(&args[0], &option))
217686e98   Al Viro   fix affs parse_op...
217
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  			*mode = option & 0777;
34f248353   Fabian Frederick   fs/affs/super.c: ...
219
  			affs_set_opt(*mount_opts, SF_SETMODE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  			break;
  		case Opt_mufs:
34f248353   Fabian Frederick   fs/affs/super.c: ...
222
  			affs_set_opt(*mount_opts, SF_MUFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  			break;
8ca577223   Fabian Frederick   affs: add mount o...
224
  		case Opt_notruncate:
34f248353   Fabian Frederick   fs/affs/super.c: ...
225
  			affs_set_opt(*mount_opts, SF_NO_TRUNCATE);
8ca577223   Fabian Frederick   affs: add mount o...
226
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  		case Opt_prefix:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  			*prefix = match_strdup(&args[0]);
  			if (!*prefix)
  				return 0;
34f248353   Fabian Frederick   fs/affs/super.c: ...
231
  			affs_set_opt(*mount_opts, SF_PREFIX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
  			break;
  		case Opt_protect:
34f248353   Fabian Frederick   fs/affs/super.c: ...
234
  			affs_set_opt(*mount_opts, SF_IMMUTABLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  			break;
  		case Opt_reserved:
  			if (match_int(&args[0], reserved))
217686e98   Al Viro   fix affs parse_op...
238
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  			break;
  		case Opt_root:
  			if (match_int(&args[0], root))
217686e98   Al Viro   fix affs parse_op...
242
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  			break;
  		case Opt_setgid:
  			if (match_int(&args[0], &option))
217686e98   Al Viro   fix affs parse_op...
246
  				return 0;
8fed10be0   Eric W. Biederman   userns: Convert a...
247
248
249
  			*gid = make_kgid(current_user_ns(), option);
  			if (!gid_valid(*gid))
  				return 0;
34f248353   Fabian Frederick   fs/affs/super.c: ...
250
  			affs_set_opt(*mount_opts, SF_SETGID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
  			break;
  		case Opt_setuid:
  			if (match_int(&args[0], &option))
217686e98   Al Viro   fix affs parse_op...
254
  				return 0;
8fed10be0   Eric W. Biederman   userns: Convert a...
255
256
257
  			*uid = make_kuid(current_user_ns(), option);
  			if (!uid_valid(*uid))
  				return 0;
34f248353   Fabian Frederick   fs/affs/super.c: ...
258
  			affs_set_opt(*mount_opts, SF_SETUID);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  			break;
  		case Opt_verbose:
34f248353   Fabian Frederick   fs/affs/super.c: ...
261
  			affs_set_opt(*mount_opts, SF_VERBOSE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
  			break;
  		case Opt_volume: {
  			char *vol = match_strdup(&args[0]);
6db27dd9d   Jim Meyering   affs: handle matc...
265
266
  			if (!vol)
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
274
  			strlcpy(volume, vol, 32);
  			kfree(vol);
  			break;
  		}
  		case Opt_ignore:
  		 	/* Silently ignore the quota options */
  			break;
  		default:
0158de12b   Fabian Frederick   fs/affs: convert ...
275
276
277
  			pr_warn("Unrecognized mount option \"%s\" or missing value
  ",
  				p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  			return 0;
  		}
  	}
  	return 1;
  }
  
  /* This function definitely needs to be split up. Some fine day I'll
   * hopefully have the guts to do so. Until then: sorry for the mess.
   */
  
  static int affs_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct affs_sb_info	*sbi;
  	struct buffer_head	*root_bh = NULL;
  	struct buffer_head	*boot_bh;
  	struct inode		*root_inode = NULL;
  	s32			 root_block;
  	int			 size, blocksize;
  	u32			 chksum;
  	int			 num_bm;
  	int			 i, j;
8fed10be0   Eric W. Biederman   userns: Convert a...
299
300
  	kuid_t			 uid;
  	kgid_t			 gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
  	int			 reserved;
  	unsigned long		 mount_flags;
  	int			 tmp_flags;	/* fix remount prototype... */
2b943cf09   Al Viro   [PATCH] fix %s in...
304
  	u8			 sig[4];
842a859db   Al Viro   affs: use ->kill_...
305
  	int			 ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306

e9b3961b6   Miklos Szeredi   mount options: fi...
307
  	save_mount_options(sb, data);
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
308
309
  	pr_debug("read_super(%s)
  ", data ? (const char *)data : "no options");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
  
  	sb->s_magic             = AFFS_SUPER_MAGIC;
  	sb->s_op                = &affs_sops;
  	sb->s_flags |= MS_NODIRATIME;
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
314
  	sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  	if (!sbi)
  		return -ENOMEM;
74c41429a   Jan Blunck   BKL: Remove BKL f...
317

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  	sb->s_fs_info = sbi;
a215fef7e   Artem Bityutskiy   affs: introduce V...
319
  	sbi->sb = sb;
7d135a5d5   Matthias Kaehlcke   affs: convert s_b...
320
  	mutex_init(&sbi->s_bmlock);
29333920a   Al Viro   Fix remount races...
321
  	spin_lock_init(&sbi->symlink_lock);
3dd847820   Artem Bityutskiy   affs: get rid of ...
322
323
  	spin_lock_init(&sbi->work_lock);
  	INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
  
  	if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
  				&blocksize,&sbi->s_prefix,
  				sbi->s_volume, &mount_flags)) {
0158de12b   Fabian Frederick   fs/affs: convert ...
328
329
  		pr_err("Error parsing options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  		return -EINVAL;
  	}
  	/* N.B. after this point s_prefix must be released */
  
  	sbi->s_flags   = mount_flags;
  	sbi->s_mode    = i;
  	sbi->s_uid     = uid;
  	sbi->s_gid     = gid;
  	sbi->s_reserved= reserved;
  
  	/* Get the size of the device in 512-byte blocks.
  	 * If we later see that the partition uses bigger
  	 * blocks, we will have to change it.
  	 */
e852d82a5   Pranay Kr. Srivastava   fs/affs: make roo...
344
  	size = i_size_read(sb->s_bdev->bd_inode) >> 9;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
345
346
  	pr_debug("initial blocksize=%d, #blocks=%d
  ", 512, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
  
  	affs_set_blocksize(sb, PAGE_SIZE);
  	/* Try to find root block. Its location depends on the block size. */
e852d82a5   Pranay Kr. Srivastava   fs/affs: make roo...
350
351
  	i = bdev_logical_block_size(sb->s_bdev);
  	j = PAGE_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
  	if (blocksize > 0) {
  		i = j = blocksize;
  		size = size / (blocksize / 512);
  	}
e852d82a5   Pranay Kr. Srivastava   fs/affs: make roo...
356

1e907f4f1   Fabian Frederick   fs/affs/super.c: ...
357
  	for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  		sbi->s_root_block = root_block;
  		if (root_block < 0)
  			sbi->s_root_block = (reserved + size - 1) / 2;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
361
362
  		pr_debug("setting blocksize to %d
  ", blocksize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  		affs_set_blocksize(sb, blocksize);
  		sbi->s_partition_size = size;
  
  		/* The root block location that was calculated above is not
  		 * correct if the partition size is an odd number of 512-
  		 * byte blocks, which will be rounded down to a number of
  		 * 1024-byte blocks, and if there were an even number of
  		 * reserved blocks. Ideally, all partition checkers should
  		 * report the real number of blocks of the real blocksize,
  		 * but since this just cannot be done, we have to try to
  		 * find the root block anyways. In the above case, it is one
  		 * block behind the calculated one. So we check this one, too.
  		 */
  		for (num_bm = 0; num_bm < 2; num_bm++) {
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
377
  			pr_debug("Dev %s, trying root=%u, bs=%d, "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
388
389
390
  				"size=%d, reserved=%d
  ",
  				sb->s_id,
  				sbi->s_root_block + num_bm,
  				blocksize, size, reserved);
  			root_bh = affs_bread(sb, sbi->s_root_block + num_bm);
  			if (!root_bh)
  				continue;
  			if (!affs_checksum_block(sb, root_bh) &&
  			    be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT &&
  			    be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
  				sbi->s_hashsize    = blocksize / 4 - 56;
  				sbi->s_root_block += num_bm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
  				goto got_root;
  			}
  			affs_brelse(root_bh);
  			root_bh = NULL;
  		}
  	}
  	if (!silent)
0158de12b   Fabian Frederick   fs/affs: convert ...
398
399
  		pr_err("No valid root block on device %s
  ", sb->s_id);
842a859db   Al Viro   affs: use ->kill_...
400
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
  
  	/* N.B. after this point bh must be released */
  got_root:
842a859db   Al Viro   affs: use ->kill_...
404
405
  	/* Keep super block in cache */
  	sbi->s_root_bh = root_bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
  	root_block = sbi->s_root_block;
  
  	/* Find out which kind of FS we have */
  	boot_bh = sb_bread(sb, 0);
  	if (!boot_bh) {
0158de12b   Fabian Frederick   fs/affs: convert ...
411
412
  		pr_err("Cannot read boot block
  ");
842a859db   Al Viro   affs: use ->kill_...
413
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  	}
2b943cf09   Al Viro   [PATCH] fix %s in...
415
  	memcpy(sig, boot_bh->b_data, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  	brelse(boot_bh);
2b943cf09   Al Viro   [PATCH] fix %s in...
417
  	chksum = be32_to_cpu(*(__be32 *)sig);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
424
  
  	/* Dircache filesystems are compatible with non-dircache ones
  	 * when reading. As long as they aren't supported, writing is
  	 * not recommended.
  	 */
  	if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
  	     || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
0158de12b   Fabian Frederick   fs/affs: convert ...
425
426
  		pr_notice("Dircache FS - mounting %s read only
  ", sb->s_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  		sb->s_flags |= MS_RDONLY;
  	}
  	switch (chksum) {
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
430
431
432
  	case MUFS_FS:
  	case MUFS_INTLFFS:
  	case MUFS_DCFFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
433
  		affs_set_opt(sbi->s_flags, SF_MUFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
434
435
436
  		/* fall thru */
  	case FS_INTLFFS:
  	case FS_DCFFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
437
  		affs_set_opt(sbi->s_flags, SF_INTL);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
438
439
  		break;
  	case MUFS_FFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
440
  		affs_set_opt(sbi->s_flags, SF_MUFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
441
442
443
444
  		break;
  	case FS_FFS:
  		break;
  	case MUFS_OFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
445
  		affs_set_opt(sbi->s_flags, SF_MUFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
446
447
  		/* fall thru */
  	case FS_OFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
448
  		affs_set_opt(sbi->s_flags, SF_OFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
449
450
451
452
  		sb->s_flags |= MS_NOEXEC;
  		break;
  	case MUFS_DCOFS:
  	case MUFS_INTLOFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
453
  		affs_set_opt(sbi->s_flags, SF_MUFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
454
455
  	case FS_DCOFS:
  	case FS_INTLOFS:
34f248353   Fabian Frederick   fs/affs/super.c: ...
456
457
  		affs_set_opt(sbi->s_flags, SF_INTL);
  		affs_set_opt(sbi->s_flags, SF_OFS);
0445f01a5   Fabian Frederick   fs/affs/super.c: ...
458
459
460
461
462
463
464
  		sb->s_flags |= MS_NOEXEC;
  		break;
  	default:
  		pr_err("Unknown filesystem on device %s: %08X
  ",
  		       sb->s_id, chksum);
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  	}
79bda4d51   Fabian Frederick   fs/affs: use affs...
466
  	if (affs_test_opt(mount_flags, SF_VERBOSE)) {
2b943cf09   Al Viro   [PATCH] fix %s in...
467
  		u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
0158de12b   Fabian Frederick   fs/affs: convert ...
468
469
  		pr_notice("Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d
  ",
2b943cf09   Al Viro   [PATCH] fix %s in...
470
  			len > 31 ? 31 : len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  			AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
2b943cf09   Al Viro   [PATCH] fix %s in...
472
  			sig, sig[3] + '0', blocksize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
  	}
  
  	sb->s_flags |= MS_NODEV | MS_NOSUID;
  
  	sbi->s_data_blksize = sb->s_blocksize;
79bda4d51   Fabian Frederick   fs/affs: use affs...
478
  	if (affs_test_opt(sbi->s_flags, SF_OFS))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  		sbi->s_data_blksize -= 24;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	tmp_flags = sb->s_flags;
842a859db   Al Viro   affs: use ->kill_...
481
482
483
  	ret = affs_init_bitmap(sb, &tmp_flags);
  	if (ret)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
  	sb->s_flags = tmp_flags;
  
  	/* set up enough so that it can read an inode */
210f85596   David Howells   iget: stop AFFS f...
487
  	root_inode = affs_iget(sb, root_block);
842a859db   Al Viro   affs: use ->kill_...
488
489
  	if (IS_ERR(root_inode))
  		return PTR_ERR(root_inode);
210f85596   David Howells   iget: stop AFFS f...
490

79bda4d51   Fabian Frederick   fs/affs: use affs...
491
  	if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL))
a129880da   Al Viro   switch affs
492
493
494
  		sb->s_d_op = &affs_intl_dentry_operations;
  	else
  		sb->s_d_op = &affs_dentry_operations;
48fde701a   Al Viro   switch open-coded...
495
  	sb->s_root = d_make_root(root_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	if (!sb->s_root) {
0158de12b   Fabian Frederick   fs/affs: convert ...
497
498
  		pr_err("AFFS: Get root inode failed
  ");
842a859db   Al Viro   affs: use ->kill_...
499
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501

9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
502
503
  	pr_debug("s_flags=%lX
  ", sb->s_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
  }
  
  static int
  affs_remount(struct super_block *sb, int *flags, char *data)
  {
  	struct affs_sb_info	*sbi = AFFS_SB(sb);
  	int			 blocksize;
8fed10be0   Eric W. Biederman   userns: Convert a...
512
513
  	kuid_t			 uid;
  	kgid_t			 gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
  	int			 mode;
  	int			 reserved;
  	int			 root_block;
  	unsigned long		 mount_flags;
  	int			 res = 0;
c8f33d0be   Sanidhya Kashyap   affs: kstrdup() m...
519
  	char			*new_opts;
29333920a   Al Viro   Fix remount races...
520
521
  	char			 volume[32];
  	char			*prefix = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

c8f33d0be   Sanidhya Kashyap   affs: kstrdup() m...
523
  	new_opts = kstrdup(data, GFP_KERNEL);
01d6e0871   Mikulas Patocka   affs: fix remount...
524
  	if (data && !new_opts)
c8f33d0be   Sanidhya Kashyap   affs: kstrdup() m...
525
  		return -ENOMEM;
9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
526
527
  	pr_debug("%s(flags=0x%x,opts=\"%s\")
  ", __func__, *flags, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528

02b9984d6   Theodore Ts'o   fs: push sync_fil...
529
  	sync_filesystem(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	*flags |= MS_NODIRATIME;
29333920a   Al Viro   Fix remount races...
531
  	memcpy(volume, sbi->s_volume, 32);
e9b3961b6   Miklos Szeredi   mount options: fi...
532
  	if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block,
29333920a   Al Viro   Fix remount races...
533
  			   &blocksize, &prefix, volume,
e9b3961b6   Miklos Szeredi   mount options: fi...
534
  			   &mount_flags)) {
29333920a   Al Viro   Fix remount races...
535
  		kfree(prefix);
e9b3961b6   Miklos Szeredi   mount options: fi...
536
  		kfree(new_opts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		return -EINVAL;
e9b3961b6   Miklos Szeredi   mount options: fi...
538
  	}
74c41429a   Jan Blunck   BKL: Remove BKL f...
539

43829731d   Tejun Heo   workqueue: deprec...
540
  	flush_delayed_work(&sbi->sb_work);
01d6e0871   Mikulas Patocka   affs: fix remount...
541
542
  	if (new_opts)
  		replace_mount_options(sb, new_opts);
e9b3961b6   Miklos Szeredi   mount options: fi...
543

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
  	sbi->s_flags = mount_flags;
  	sbi->s_mode  = mode;
  	sbi->s_uid   = uid;
  	sbi->s_gid   = gid;
29333920a   Al Viro   Fix remount races...
548
549
550
551
552
553
554
555
  	/* protect against readers */
  	spin_lock(&sbi->symlink_lock);
  	if (prefix) {
  		kfree(sbi->s_prefix);
  		sbi->s_prefix = prefix;
  	}
  	memcpy(sbi->s_volume, volume, 32);
  	spin_unlock(&sbi->symlink_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

74c41429a   Jan Blunck   BKL: Remove BKL f...
557
  	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		return 0;
74c41429a   Jan Blunck   BKL: Remove BKL f...
559

0164b1a32   Artem Bityutskiy   affs: remove usel...
560
  	if (*flags & MS_RDONLY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  		affs_free_bitmap(sb);
0164b1a32   Artem Bityutskiy   affs: remove usel...
562
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
  		res = affs_init_bitmap(sb, flags);
  
  	return res;
  }
  
  static int
726c33422   David Howells   [PATCH] VFS: Perm...
569
  affs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  {
726c33422   David Howells   [PATCH] VFS: Perm...
571
  	struct super_block *sb = dentry->d_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  	int		 free;
a6a2a73c4   Coly Li   fs/affs: return f...
573
  	u64		 id = huge_encode_dev(sb->s_bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574

9606d9aa8   Fabian Frederick   fs/affs: pr_debug...
575
576
577
578
  	pr_debug("%s() partsize=%d, reserved=%d
  ",
  		 __func__, AFFS_SB(sb)->s_partition_size,
  		 AFFS_SB(sb)->s_reserved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
583
584
585
  
  	free          = affs_count_free_blocks(sb);
  	buf->f_type    = AFFS_SUPER_MAGIC;
  	buf->f_bsize   = sb->s_blocksize;
  	buf->f_blocks  = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
  	buf->f_bfree   = free;
  	buf->f_bavail  = free;
a6a2a73c4   Coly Li   fs/affs: return f...
586
587
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
f157853e4   Fabian Frederick   fs/affs: define A...
588
  	buf->f_namelen = AFFSNAMEMAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
  	return 0;
  }
152a08366   Al Viro   new helper: mount...
591
592
  static struct dentry *affs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
  {
152a08366   Al Viro   new helper: mount...
594
  	return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  }
842a859db   Al Viro   affs: use ->kill_...
596
597
598
599
600
601
602
603
  static void affs_kill_sb(struct super_block *sb)
  {
  	struct affs_sb_info *sbi = AFFS_SB(sb);
  	kill_block_super(sb);
  	if (sbi) {
  		affs_free_bitmap(sb);
  		affs_brelse(sbi->s_root_bh);
  		kfree(sbi->s_prefix);
4d29e571e   Fabian Frederick   fs/affs/super.c: ...
604
  		mutex_destroy(&sbi->s_bmlock);
842a859db   Al Viro   affs: use ->kill_...
605
606
607
  		kfree(sbi);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
  static struct file_system_type affs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "affs",
152a08366   Al Viro   new helper: mount...
611
  	.mount		= affs_mount,
842a859db   Al Viro   affs: use ->kill_...
612
  	.kill_sb	= affs_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
  	.fs_flags	= FS_REQUIRES_DEV,
  };
7f78e0351   Eric W. Biederman   fs: Limit sys_mou...
615
  MODULE_ALIAS_FS("affs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  
  static int __init init_affs_fs(void)
  {
  	int err = init_inodecache();
  	if (err)
  		goto out1;
  	err = register_filesystem(&affs_fs_type);
  	if (err)
  		goto out;
  	return 0;
  out:
  	destroy_inodecache();
  out1:
  	return err;
  }
  
  static void __exit exit_affs_fs(void)
  {
  	unregister_filesystem(&affs_fs_type);
  	destroy_inodecache();
  }
  
  MODULE_DESCRIPTION("Amiga filesystem support for Linux");
  MODULE_LICENSE("GPL");
  
  module_init(init_affs_fs)
  module_exit(exit_affs_fs)