Blame view

fs/hpfs/super.c 19.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   *  linux/fs/hpfs/super.c
   *
   *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
   *
   *  mounting, unmounting, error handling
   */
  
  #include "hpfs_fn.h"
  #include <linux/module.h>
  #include <linux/parser.h>
  #include <linux/init.h>
  #include <linux/statfs.h>
e18fa700c   Jeff Garzik   Move several *_SU...
14
  #include <linux/magic.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
15
  #include <linux/sched.h>
f4c54fcf3   Akinobu Mita   hpfs: use bitmap_...
16
  #include <linux/bitmap.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  
  /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
20
  static void mark_dirty(struct super_block *s, int remount)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  {
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
22
  	if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
  		struct buffer_head *bh;
  		struct hpfs_spare_block *sb;
  		if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
  			sb->dirty = 1;
  			sb->old_wrote = 0;
  			mark_buffer_dirty(bh);
f73976818   Mikulas Patocka   HPFS: When markin...
29
  			sync_dirty_buffer(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
38
39
40
41
42
  			brelse(bh);
  		}
  	}
  }
  
  /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there
     were errors) */
  
  static void unmark_dirty(struct super_block *s)
  {
  	struct buffer_head *bh;
  	struct hpfs_spare_block *sb;
  	if (s->s_flags & MS_RDONLY) return;
f73976818   Mikulas Patocka   HPFS: When markin...
43
  	sync_blockdev(s->s_bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
  	if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
  		sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error;
  		sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error;
  		mark_buffer_dirty(bh);
f73976818   Mikulas Patocka   HPFS: When markin...
48
  		sync_dirty_buffer(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
  		brelse(bh);
  	}
  }
  
  /* Filesystem error... */
352d94d04   Alexey Dobriyan   [PATCH] hpfs: bri...
54
  static char err_buf[1024];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

352d94d04   Alexey Dobriyan   [PATCH] hpfs: bri...
56
  void hpfs_error(struct super_block *s, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  {
352d94d04   Alexey Dobriyan   [PATCH] hpfs: bri...
58
59
60
61
62
63
64
  	va_list args;
  
  	va_start(args, fmt);
  	vsnprintf(err_buf, sizeof(err_buf), fmt, args);
  	va_end(args);
  
  	printk("HPFS: filesystem error: %s", err_buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
  	if (!hpfs_sb(s)->sb_was_error) {
  		if (hpfs_sb(s)->sb_err == 2) {
  			printk("; crashing the system because you wanted it
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
69
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
  			panic("HPFS panic");
  		} else if (hpfs_sb(s)->sb_err == 1) {
  			if (s->s_flags & MS_RDONLY) printk("; already mounted read-only
  ");
  			else {
  				printk("; remounting read-only
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
77
  				mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
84
85
  				s->s_flags |= MS_RDONLY;
  			}
  		} else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only
  ");
  		else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!
  ");
  	} else printk("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	hpfs_sb(s)->sb_was_error = 1;
  }
  
  /* 
   * A little trick to detect cycles in many hpfs structures and don't let the
   * kernel crash on corrupted filesystem. When first called, set c2 to 0.
   *
   * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories
   * nested each in other, chkdsk locked up happilly.
   */
  
  int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2,
  		char *msg)
  {
  	if (*c2 && *c1 == key) {
  		hpfs_error(s, "cycle detected on key %08x in %s", key, msg);
  		return 1;
  	}
  	(*c2)++;
  	if (!((*c2 - 1) & *c2)) *c1 = key;
  	return 0;
  }
30687e0a4   Al Viro   hpfs: make freein...
108
  static void free_sbi(struct hpfs_sb_info *sbi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  {
30687e0a4   Al Viro   hpfs: make freein...
110
111
112
113
  	kfree(sbi->sb_cp_table);
  	kfree(sbi->sb_bmp_dir);
  	kfree(sbi);
  }
6cfd01484   Christoph Hellwig   push BKL down int...
114

30687e0a4   Al Viro   hpfs: make freein...
115
116
117
118
119
120
121
  static void lazy_free_sbi(struct rcu_head *rcu)
  {
  	free_sbi(container_of(rcu, struct hpfs_sb_info, rcu));
  }
  
  static void hpfs_put_super(struct super_block *s)
  {
7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
122
123
124
  	hpfs_lock(s);
  	unmark_dirty(s);
  	hpfs_unlock(s);
30687e0a4   Al Viro   hpfs: make freein...
125
  	call_rcu(&hpfs_sb(s)->rcu, lazy_free_sbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  }
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
127
  static unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
  {
  	struct quad_buffer_head qbh;
f4c54fcf3   Akinobu Mita   hpfs: use bitmap_...
130
131
  	unsigned long *bits;
  	unsigned count;
275f495db   Mikulas Patocka   hpfs: implement p...
132
  	bits = hpfs_map_4sectors(s, secno, &qbh, 0);
f4c54fcf3   Akinobu Mita   hpfs: use bitmap_...
133
  	if (!bits)
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
134
  		return (unsigned)-1;
f4c54fcf3   Akinobu Mita   hpfs: use bitmap_...
135
  	count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
142
143
144
  	hpfs_brelse4(&qbh);
  	return count;
  }
  
  static unsigned count_bitmaps(struct super_block *s)
  {
  	unsigned n, count, n_bands;
  	n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14;
  	count = 0;
275f495db   Mikulas Patocka   hpfs: implement p...
145
146
147
148
  	for (n = 0; n < COUNT_RD_AHEAD; n++) {
  		hpfs_prefetch_bitmap(s, n);
  	}
  	for (n = 0; n < n_bands; n++) {
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
149
  		unsigned c;
275f495db   Mikulas Patocka   hpfs: implement p...
150
  		hpfs_prefetch_bitmap(s, n + COUNT_RD_AHEAD);
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
151
152
153
  		c = hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
  		if (c != (unsigned)-1)
  			count += c;
275f495db   Mikulas Patocka   hpfs: implement p...
154
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
  	return count;
  }
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
157
158
159
160
161
162
163
164
165
166
167
  unsigned hpfs_get_free_dnodes(struct super_block *s)
  {
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
  	if (sbi->sb_n_free_dnodes == (unsigned)-1) {
  		unsigned c = hpfs_count_one_bitmap(s, sbi->sb_dmap);
  		if (c == (unsigned)-1)
  			return 0;
  		sbi->sb_n_free_dnodes = c;
  	}
  	return sbi->sb_n_free_dnodes;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
168
  static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  {
726c33422   David Howells   [PATCH] VFS: Perm...
170
  	struct super_block *s = dentry->d_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
604d295c2   Coly Li   fs/hpfs: return f...
172
  	u64 id = huge_encode_dev(s->s_bdev->bd_dev);
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
173

9a311b96c   Arnd Bergmann   hpfs: remove the BKL
174
  	hpfs_lock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175

2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
176
  	if (sbi->sb_n_free == (unsigned)-1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  		sbi->sb_n_free = count_bitmaps(s);
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
178

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
  	buf->f_type = s->s_magic;
  	buf->f_bsize = 512;
  	buf->f_blocks = sbi->sb_fs_size;
  	buf->f_bfree = sbi->sb_n_free;
  	buf->f_bavail = sbi->sb_n_free;
  	buf->f_files = sbi->sb_dirband_size / 4;
2cbe5c76f   Mikulas Patocka   hpfs: remember fr...
185
  	buf->f_ffree = hpfs_get_free_dnodes(s);
604d295c2   Coly Li   fs/hpfs: return f...
186
187
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  	buf->f_namelen = 254;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
189
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
  
  	return 0;
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
193
  static struct kmem_cache * hpfs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
  
  static struct inode *hpfs_alloc_inode(struct super_block *sb)
  {
  	struct hpfs_inode_info *ei;
e6b4f8da3   Christoph Lameter   [PATCH] slab: rem...
198
  	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
  	if (!ei)
  		return NULL;
  	ei->vfs_inode.i_version = 1;
  	return &ei->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
204
  static void hpfs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
206
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  	kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
209
210
211
212
  static void hpfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, hpfs_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
213
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
  {
  	struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
216
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  }
20c2df83d   Paul Mundt   mm: Remove slab d...
218

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  static int init_inodecache(void)
  {
  	hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
  					     sizeof(struct hpfs_inode_info),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
223
224
  					     0, (SLAB_RECLAIM_ACCOUNT|
  						SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
225
  					     init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
  	if (hpfs_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void destroy_inodecache(void)
  {
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
233
234
235
236
237
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
238
  	kmem_cache_destroy(hpfs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
246
247
248
  }
  
  /*
   * A tiny parser for option strings, stolen from dosfs.
   * Stolen again from read-only hpfs.
   * And updated for table-driven option parsing.
   */
  
  enum {
  	Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
  	Opt_check_none, Opt_check_normal, Opt_check_strict,
  	Opt_err_cont, Opt_err_ro, Opt_err_panic,
  	Opt_eas_no, Opt_eas_ro, Opt_eas_rw,
  	Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always,
  	Opt_timeshift, Opt_err,
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
255
  static const match_table_t tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
  	{Opt_help, "help"},
  	{Opt_uid, "uid=%u"},
  	{Opt_gid, "gid=%u"},
  	{Opt_umask, "umask=%o"},
  	{Opt_case_lower, "case=lower"},
  	{Opt_case_asis, "case=asis"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	{Opt_check_none, "check=none"},
  	{Opt_check_normal, "check=normal"},
  	{Opt_check_strict, "check=strict"},
  	{Opt_err_cont, "errors=continue"},
  	{Opt_err_ro, "errors=remount-ro"},
  	{Opt_err_panic, "errors=panic"},
  	{Opt_eas_no, "eas=no"},
  	{Opt_eas_ro, "eas=ro"},
  	{Opt_eas_rw, "eas=rw"},
  	{Opt_chkdsk_no, "chkdsk=no"},
  	{Opt_chkdsk_errors, "chkdsk=errors"},
  	{Opt_chkdsk_always, "chkdsk=always"},
  	{Opt_timeshift, "timeshift=%d"},
  	{Opt_err, NULL},
  };
0e1a43c71   Eric W. Biederman   userns: Convert h...
277
  static int parse_opts(char *opts, kuid_t *uid, kgid_t *gid, umode_t *umask,
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
278
  		      int *lowercase, int *eas, int *chk, int *errs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  		      int *chkdsk, int *timeshift)
  {
  	char *p;
  	int option;
  
  	if (!opts)
  		return 1;
  
  	/*printk("Parsing opts: '%s'
  ",opts);*/
  
  	while ((p = strsep(&opts, ",")) != NULL) {
  		substring_t args[MAX_OPT_ARGS];
  		int token;
  		if (!*p)
  			continue;
  
  		token = match_token(p, tokens, args);
  		switch (token) {
  		case Opt_help:
  			return 2;
  		case Opt_uid:
  			if (match_int(args, &option))
  				return 0;
0e1a43c71   Eric W. Biederman   userns: Convert h...
303
304
305
  			*uid = make_kuid(current_user_ns(), option);
  			if (!uid_valid(*uid))
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
  			break;
  		case Opt_gid:
  			if (match_int(args, &option))
  				return 0;
0e1a43c71   Eric W. Biederman   userns: Convert h...
310
311
312
  			*gid = make_kgid(current_user_ns(), option);
  			if (!gid_valid(*gid))
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
318
319
320
321
322
323
324
  			break;
  		case Opt_umask:
  			if (match_octal(args, &option))
  				return 0;
  			*umask = option;
  			break;
  		case Opt_case_lower:
  			*lowercase = 1;
  			break;
  		case Opt_case_asis:
  			*lowercase = 0;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  		case Opt_check_none:
  			*chk = 0;
  			break;
  		case Opt_check_normal:
  			*chk = 1;
  			break;
  		case Opt_check_strict:
  			*chk = 2;
  			break;
  		case Opt_err_cont:
  			*errs = 0;
  			break;
  		case Opt_err_ro:
  			*errs = 1;
  			break;
  		case Opt_err_panic:
  			*errs = 2;
  			break;
  		case Opt_eas_no:
  			*eas = 0;
  			break;
  		case Opt_eas_ro:
  			*eas = 1;
  			break;
  		case Opt_eas_rw:
  			*eas = 2;
  			break;
  		case Opt_chkdsk_no:
  			*chkdsk = 0;
  			break;
  		case Opt_chkdsk_errors:
  			*chkdsk = 1;
  			break;
  		case Opt_chkdsk_always:
  			*chkdsk = 2;
  			break;
  		case Opt_timeshift:
  		{
  			int m = 1;
  			char *rhs = args[0].from;
  			if (!rhs || !*rhs)
  				return 0;
  			if (*rhs == '-') m = -1;
  			if (*rhs == '+' || *rhs == '-') rhs++;
  			*timeshift = simple_strtoul(rhs, &rhs, 0) * m;
  			if (*rhs)
  				return 0;
  			break;
  		}
  		default:
  			return 0;
  		}
  	}
  	return 1;
  }
  
  static inline void hpfs_help(void)
  {
  	printk("
  \
  HPFS filesystem options:
  \
        help              do not mount and display this text
  \
        uid=xxx           set uid of files that don't have uid specified in eas
  \
        gid=xxx           set gid of files that don't have gid specified in eas
  \
        umask=xxx         set mode of files that don't have mode specified in eas
  \
        case=lower        lowercase all files
  \
        case=asis         do not lowercase files (default)
  \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
        check=none        no fs checks - kernel may crash on corrupted filesystem
  \
        check=normal      do some checks - it should not crash (default)
  \
        check=strict      do extra time-consuming checks, used for debugging
  \
        errors=continue   continue on errors
  \
        errors=remount-ro remount read-only if errors found (default)
  \
        errors=panic      panic on errors
  \
        chkdsk=no         do not mark fs for chkdsking even if there were errors
  \
        chkdsk=errors     mark fs dirty if errors found (default)
  \
        chkdsk=always     always mark fs dirty - used for debugging
  \
        eas=no            ignore extended attributes
  \
        eas=ro            read but do not write extended attributes
  \
        eas=rw            r/w eas => enables chmod, chown, mknod, ln -s (default)
  \
        timeshift=nnn	add nnn seconds to file times
  \
  
  ");
  }
  
  static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
  {
0e1a43c71   Eric W. Biederman   userns: Convert h...
431
432
  	kuid_t uid;
  	kgid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  	umode_t umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
434
  	int lowercase, eas, chk, errs, chkdsk, timeshift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
  	int o;
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
6d9c1fd42   Miklos Szeredi   mount options: fi...
437
  	char *new_opts = kstrdup(data, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  	
02b9984d6   Theodore Ts'o   fs: push sync_fil...
439
  	sync_filesystem(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  	*flags |= MS_NOATIME;
  	
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
442
  	hpfs_lock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
  	uid = sbi->sb_uid; gid = sbi->sb_gid;
  	umask = 0777 & ~sbi->sb_mode;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
445
  	lowercase = sbi->sb_lowercase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  	eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk;
  	errs = sbi->sb_err; timeshift = sbi->sb_timeshift;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
448
  	if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
  	    &eas, &chk, &errs, &chkdsk, &timeshift))) {
  		printk("HPFS: bad mount options.
  ");
6d9c1fd42   Miklos Szeredi   mount options: fi...
452
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  	}
  	if (o == 2) {
  		hpfs_help();
6d9c1fd42   Miklos Szeredi   mount options: fi...
456
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
  	}
  	if (timeshift != sbi->sb_timeshift) {
  		printk("HPFS: timeshift can't be changed using remount.
  ");
6d9c1fd42   Miklos Szeredi   mount options: fi...
461
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
  	}
  
  	unmark_dirty(s);
  
  	sbi->sb_uid = uid; sbi->sb_gid = gid;
  	sbi->sb_mode = 0777 & ~umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
468
  	sbi->sb_lowercase = lowercase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  	sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk;
  	sbi->sb_err = errs; sbi->sb_timeshift = timeshift;
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
471
  	if (!(*flags & MS_RDONLY)) mark_dirty(s, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

2a32cebd6   Al Viro   Fix races around ...
473
  	replace_mount_options(s, new_opts);
6d9c1fd42   Miklos Szeredi   mount options: fi...
474

9a311b96c   Arnd Bergmann   hpfs: remove the BKL
475
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  	return 0;
6d9c1fd42   Miklos Szeredi   mount options: fi...
477
478
  
  out_err:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
479
  	hpfs_unlock(s);
6d9c1fd42   Miklos Szeredi   mount options: fi...
480
481
  	kfree(new_opts);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
  }
  
  /* Super operations */
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
485
  static const struct super_operations hpfs_sops =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
  {
  	.alloc_inode	= hpfs_alloc_inode,
  	.destroy_inode	= hpfs_destroy_inode,
ea5440092   Al Viro   switch hpfs to ->...
489
  	.evict_inode	= hpfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
  	.put_super	= hpfs_put_super,
  	.statfs		= hpfs_statfs,
  	.remount_fs	= hpfs_remount_fs,
6d9c1fd42   Miklos Szeredi   mount options: fi...
493
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
503
  };
  
  static int hpfs_fill_super(struct super_block *s, void *options, int silent)
  {
  	struct buffer_head *bh0, *bh1, *bh2;
  	struct hpfs_boot_block *bootblock;
  	struct hpfs_super_block *superblock;
  	struct hpfs_spare_block *spareblock;
  	struct hpfs_sb_info *sbi;
  	struct inode *root;
0e1a43c71   Eric W. Biederman   userns: Convert h...
504
505
  	kuid_t uid;
  	kgid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	umode_t umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
507
  	int lowercase, eas, chk, errs, chkdsk, timeshift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
  
  	dnode_secno root_dno;
  	struct hpfs_dirent *de = NULL;
  	struct quad_buffer_head qbh;
  
  	int o;
6d9c1fd42   Miklos Szeredi   mount options: fi...
514
  	save_mount_options(s, options);
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
515
  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
db7192221   Jan Blunck   BKL: Explicitly a...
516
  	if (!sbi) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  		return -ENOMEM;
db7192221   Jan Blunck   BKL: Explicitly a...
518
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	s->s_fs_info = sbi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520

7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
521
522
  	mutex_init(&sbi->hpfs_mutex);
  	hpfs_lock(s);
de395b8ac   David Howells   CRED: Wrap task c...
523
524
  	uid = current_uid();
  	gid = current_gid();
ce3b0f8d5   Al Viro   New helper - curr...
525
  	umask = current_umask();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	lowercase = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
531
  	eas = 2;
  	chk = 1;
  	errs = 1;
  	chkdsk = 1;
  	timeshift = 0;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
532
  	if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  	    &eas, &chk, &errs, &chkdsk, &timeshift))) {
  		printk("HPFS: bad mount options.
  ");
  		goto bail0;
  	}
  	if (o==2) {
  		hpfs_help();
  		goto bail0;
  	}
  
  	/*sbi->sb_mounting = 1;*/
  	sb_set_blocksize(s, 512);
  	sbi->sb_fs_size = -1;
  	if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1;
  	if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2;
  	if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3;
  
  	/* Check magics */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
551
552
553
  	if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC
  	    ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC
  	    || le32_to_cpu(spareblock->magic) != SP_MAGIC) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  		if (!silent) printk("HPFS: Bad magic ... probably not HPFS
  ");
  		goto bail4;
  	}
  
  	/* Check version */
  	if (!(s->s_flags & MS_RDONLY) &&
  	      superblock->funcversion != 2 && superblock->funcversion != 3) {
  		printk("HPFS: Bad version %d,%d. Mount readonly to go around
  ",
  			(int)superblock->version, (int)superblock->funcversion);
  		printk("HPFS: please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - mikulas@artax.karlin.mff.cuni.cz
  ");
  		goto bail4;
  	}
  
  	s->s_flags |= MS_NOATIME;
  
  	/* Fill superblock stuff */
  	s->s_magic = HPFS_SUPER_MAGIC;
  	s->s_op = &hpfs_sops;
43d344d77   Al Viro   switch hpfs
575
  	s->s_d_op = &hpfs_dentry_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576

0b69760be   Mikulas Patocka   HPFS: Fix endiani...
577
578
579
580
581
582
  	sbi->sb_root = le32_to_cpu(superblock->root);
  	sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors);
  	sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps);
  	sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start);
  	sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band);
  	sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
587
588
  	sbi->sb_uid = uid;
  	sbi->sb_gid = gid;
  	sbi->sb_mode = 0777 & ~umask;
  	sbi->sb_n_free = -1;
  	sbi->sb_n_free_dnodes = -1;
  	sbi->sb_lowercase = lowercase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
  	sbi->sb_eas = eas;
  	sbi->sb_chk = chk;
  	sbi->sb_chkdsk = chkdsk;
  	sbi->sb_err = errs;
  	sbi->sb_timeshift = timeshift;
  	sbi->sb_was_error = 0;
  	sbi->sb_cp_table = NULL;
  	sbi->sb_c_bitmap = -1;
  	sbi->sb_max_fwd_alloc = 0xffffff;
3ebacb050   Mikulas Patocka   hpfs: better test...
598
599
600
601
602
603
  
  	if (sbi->sb_fs_size >= 0x80000000) {
  		hpfs_error(s, "invalid size in superblock: %08x",
  			(unsigned)sbi->sb_fs_size);
  		goto bail4;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  	/* Load bitmap directory */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
605
  	if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
  		goto bail4;
  	
  	/* Check for general fs errors*/
  	if (spareblock->dirty && !spareblock->old_wrote) {
  		if (errs == 2) {
  			printk("HPFS: Improperly stopped, not mounted
  ");
  			goto bail4;
  		}
  		hpfs_error(s, "improperly stopped");
  	}
  
  	if (!(s->s_flags & MS_RDONLY)) {
  		spareblock->dirty = 1;
  		spareblock->old_wrote = 0;
  		mark_buffer_dirty(bh2);
  	}
28fe3c196   Al Viro   hpfs: assorted en...
623
  	if (spareblock->hotfixes_used || spareblock->n_spares_used) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
  		if (errs >= 2) {
  			printk("HPFS: Hotfixes not supported here, try chkdsk
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
627
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
633
634
635
  			goto bail4;
  		}
  		hpfs_error(s, "hotfixes not supported here, try chkdsk");
  		if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...
  ");
  		else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.
  ");
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
636
  	if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
  		if (errs >= 2) {
  			printk("HPFS: Spare dnodes used, try chkdsk
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
640
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
  			goto bail4;
  		}
  		hpfs_error(s, "warning: spare dnodes used, try chkdsk");
  		if (errs == 0) printk("HPFS: Proceeding, but your filesystem could be corrupted if you delete files or directories
  ");
  	}
  	if (chk) {
  		unsigned a;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
649
650
  		if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) ||
  		    le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  			hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x",
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
652
  				le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
656
  			goto bail4;
  		}
  		a = sbi->sb_dirband_size;
  		sbi->sb_dirband_size = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
657
658
659
  		if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") ||
  		    hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") ||
  		    hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) {
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
660
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
  			goto bail4;
  		}
  		sbi->sb_dirband_size = a;
  	} else printk("HPFS: You really don't want any checks? You are crazy...
  ");
  
  	/* Load code page table */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
668
669
  	if (le32_to_cpu(spareblock->n_code_pages))
  		if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
675
676
677
678
679
680
681
682
  			printk("HPFS: Warning: code page support is disabled
  ");
  
  	brelse(bh2);
  	brelse(bh1);
  	brelse(bh0);
  
  	root = iget_locked(s, sbi->sb_root);
  	if (!root)
  		goto bail0;
  	hpfs_init_inode(root);
  	hpfs_read_inode(root);
  	unlock_new_inode(root);
48fde701a   Al Viro   switch open-coded...
683
684
  	s->s_root = d_make_root(root);
  	if (!s->s_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  		goto bail0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
694
695
696
  
  	/*
  	 * find the root directory's . pointer & finish filling in the inode
  	 */
  
  	root_dno = hpfs_fnode_dno(s, sbi->sb_root);
  	if (root_dno)
  		de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh);
  	if (!de)
  		hpfs_error(s, "unable to find root dir");
  	else {
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
697
  		root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  		root->i_atime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
699
  		root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  		root->i_mtime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
701
  		root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  		root->i_ctime.tv_nsec = 0;
de5e2b362   Al Viro   hpfs: endianness ...
703
  		hpfs_i(root)->i_ea_size = le32_to_cpu(de->ea_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
710
  		hpfs_i(root)->i_parent_dir = root->i_ino;
  		if (root->i_size == -1)
  			root->i_size = 2048;
  		if (root->i_blocks == -1)
  			root->i_blocks = 5;
  		hpfs_brelse4(&qbh);
  	}
7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
711
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
715
716
717
718
  	return 0;
  
  bail4:	brelse(bh2);
  bail3:	brelse(bh1);
  bail2:	brelse(bh0);
  bail1:
  bail0:
7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
719
  	hpfs_unlock(s);
30687e0a4   Al Viro   hpfs: make freein...
720
  	free_sbi(sbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
  	return -EINVAL;
  }
152a08366   Al Viro   new helper: mount...
723
724
  static struct dentry *hpfs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  {
152a08366   Al Viro   new helper: mount...
726
  	return mount_bdev(fs_type, flags, dev_name, data, hpfs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
  }
  
  static struct file_system_type hpfs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "hpfs",
152a08366   Al Viro   new helper: mount...
732
  	.mount		= hpfs_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
  	.kill_sb	= kill_block_super,
  	.fs_flags	= FS_REQUIRES_DEV,
  };
3e64fe5b2   Eric W. Biederman   fs: Limit sys_mou...
736
  MODULE_ALIAS_FS("hpfs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  
  static int __init init_hpfs_fs(void)
  {
  	int err = init_inodecache();
  	if (err)
  		goto out1;
  	err = register_filesystem(&hpfs_fs_type);
  	if (err)
  		goto out;
  	return 0;
  out:
  	destroy_inodecache();
  out1:
  	return err;
  }
  
  static void __exit exit_hpfs_fs(void)
  {
  	unregister_filesystem(&hpfs_fs_type);
  	destroy_inodecache();
  }
  
  module_init(init_hpfs_fs)
  module_exit(exit_hpfs_fs)
  MODULE_LICENSE("GPL");