Blame view

fs/hpfs/super.c 18.4 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
108
109
110
111
  	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;
  }
  
  static void hpfs_put_super(struct super_block *s)
  {
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
6cfd01484   Christoph Hellwig   push BKL down int...
112

7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
113
114
115
  	hpfs_lock(s);
  	unmark_dirty(s);
  	hpfs_unlock(s);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
116
117
  	kfree(sbi->sb_cp_table);
  	kfree(sbi->sb_bmp_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
  	s->s_fs_info = NULL;
  	kfree(sbi);
  }
  
  unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
  {
  	struct quad_buffer_head qbh;
f4c54fcf3   Akinobu Mita   hpfs: use bitmap_...
125
126
127
128
129
130
131
  	unsigned long *bits;
  	unsigned count;
  
  	bits = hpfs_map_4sectors(s, secno, &qbh, 4);
  	if (!bits)
  		return 0;
  	count = bitmap_weight(bits, 2048 * BITS_PER_BYTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
  	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;
  	for (n = 0; n < n_bands; n++)
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
142
  		count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  	return count;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
145
  static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
726c33422   David Howells   [PATCH] VFS: Perm...
147
  	struct super_block *s = dentry->d_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
604d295c2   Coly Li   fs/hpfs: return f...
149
  	u64 id = huge_encode_dev(s->s_bdev->bd_dev);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
150
  	hpfs_lock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
158
159
160
161
162
  
  	/*if (sbi->sb_n_free == -1) {*/
  		sbi->sb_n_free = count_bitmaps(s);
  		sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap);
  	/*}*/
  	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;
  	buf->f_ffree = sbi->sb_n_free_dnodes;
604d295c2   Coly Li   fs/hpfs: return f...
163
164
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	buf->f_namelen = 254;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
166
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
  
  	return 0;
  }
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
170
  static struct kmem_cache * hpfs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
  
  static struct inode *hpfs_alloc_inode(struct super_block *sb)
  {
  	struct hpfs_inode_info *ei;
e6b4f8da3   Christoph Lameter   [PATCH] slab: rem...
175
  	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
  	if (!ei)
  		return NULL;
  	ei->vfs_inode.i_version = 1;
  	return &ei->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
181
  static void hpfs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
183
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
  	kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
186
187
188
189
  static void hpfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, hpfs_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
190
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  {
  	struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
193
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  }
20c2df83d   Paul Mundt   mm: Remove slab d...
195

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
  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...
200
201
  					     0, (SLAB_RECLAIM_ACCOUNT|
  						SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
202
  					     init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
  	if (hpfs_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void destroy_inodecache(void)
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
210
  	kmem_cache_destroy(hpfs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
217
218
219
220
  }
  
  /*
   * 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
221
222
223
224
225
226
  	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...
227
  static const match_table_t tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
  	{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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	{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},
  };
  
  static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
251
  		      int *lowercase, int *eas, int *chk, int *errs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  		      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;
  			*uid = option;
  			break;
  		case Opt_gid:
  			if (match_int(args, &option))
  				return 0;
  			*gid = option;
  			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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
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
  		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
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
399
400
401
402
        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)
  {
  	uid_t uid;
  	gid_t gid;
  	umode_t umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
403
  	int lowercase, eas, chk, errs, chkdsk, timeshift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  	int o;
  	struct hpfs_sb_info *sbi = hpfs_sb(s);
6d9c1fd42   Miklos Szeredi   mount options: fi...
406
  	char *new_opts = kstrdup(data, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  	
  	*flags |= MS_NOATIME;
  	
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
410
  	hpfs_lock(s);
bbd6851a3   Al Viro   Push lock_super()...
411
  	lock_super(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
  	uid = sbi->sb_uid; gid = sbi->sb_gid;
  	umask = 0777 & ~sbi->sb_mode;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
414
  	lowercase = sbi->sb_lowercase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
  	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...
417
  	if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
  	    &eas, &chk, &errs, &chkdsk, &timeshift))) {
  		printk("HPFS: bad mount options.
  ");
6d9c1fd42   Miklos Szeredi   mount options: fi...
421
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  	}
  	if (o == 2) {
  		hpfs_help();
6d9c1fd42   Miklos Szeredi   mount options: fi...
425
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
  	}
  	if (timeshift != sbi->sb_timeshift) {
  		printk("HPFS: timeshift can't be changed using remount.
  ");
6d9c1fd42   Miklos Szeredi   mount options: fi...
430
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
435
436
  	}
  
  	unmark_dirty(s);
  
  	sbi->sb_uid = uid; sbi->sb_gid = gid;
  	sbi->sb_mode = 0777 & ~umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
437
  	sbi->sb_lowercase = lowercase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	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...
440
  	if (!(*flags & MS_RDONLY)) mark_dirty(s, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441

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

bbd6851a3   Al Viro   Push lock_super()...
444
  	unlock_super(s);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
445
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  	return 0;
6d9c1fd42   Miklos Szeredi   mount options: fi...
447
448
  
  out_err:
bbd6851a3   Al Viro   Push lock_super()...
449
  	unlock_super(s);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
450
  	hpfs_unlock(s);
6d9c1fd42   Miklos Szeredi   mount options: fi...
451
452
  	kfree(new_opts);
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  }
  
  /* Super operations */
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
456
  static const struct super_operations hpfs_sops =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
  {
  	.alloc_inode	= hpfs_alloc_inode,
  	.destroy_inode	= hpfs_destroy_inode,
ea5440092   Al Viro   switch hpfs to ->...
460
  	.evict_inode	= hpfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
  	.put_super	= hpfs_put_super,
  	.statfs		= hpfs_statfs,
  	.remount_fs	= hpfs_remount_fs,
6d9c1fd42   Miklos Szeredi   mount options: fi...
464
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  };
  
  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;
  
  	uid_t uid;
  	gid_t gid;
  	umode_t umask;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
479
  	int lowercase, eas, chk, errs, chkdsk, timeshift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
485
  
  	dnode_secno root_dno;
  	struct hpfs_dirent *de = NULL;
  	struct quad_buffer_head qbh;
  
  	int o;
6d9c1fd42   Miklos Szeredi   mount options: fi...
486
  	save_mount_options(s, options);
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
487
  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
db7192221   Jan Blunck   BKL: Explicitly a...
488
  	if (!sbi) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  		return -ENOMEM;
db7192221   Jan Blunck   BKL: Explicitly a...
490
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  	s->s_fs_info = sbi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
  
  	sbi->sb_bmp_dir = NULL;
  	sbi->sb_cp_table = NULL;
7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
495
496
  	mutex_init(&sbi->hpfs_mutex);
  	hpfs_lock(s);
de395b8ac   David Howells   CRED: Wrap task c...
497
498
  	uid = current_uid();
  	gid = current_gid();
ce3b0f8d5   Al Viro   New helper - curr...
499
  	umask = current_umask();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	lowercase = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
  	eas = 2;
  	chk = 1;
  	errs = 1;
  	chkdsk = 1;
  	timeshift = 0;
0fe105aa2   Mikulas Patocka   HPFS: Remove CR/L...
506
  	if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  	    &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...
525
526
527
  	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
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  		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
549
  	s->s_d_op = &hpfs_dentry_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550

0b69760be   Mikulas Patocka   HPFS: Fix endiani...
551
552
553
554
555
556
  	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
557
558
559
560
561
562
  	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
563
564
565
566
567
568
569
570
571
572
573
  	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;
  	
  	/* Load bitmap directory */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
574
  	if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  		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);
  	}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
592
  	if (le32_to_cpu(spareblock->hotfixes_used) || le32_to_cpu(spareblock->n_spares_used)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  		if (errs >= 2) {
  			printk("HPFS: Hotfixes not supported here, try chkdsk
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
596
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
  			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...
605
  	if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
  		if (errs >= 2) {
  			printk("HPFS: Spare dnodes used, try chkdsk
  ");
dab4c82a6   Mikulas Patocka   HPFS: Fix a bug t...
609
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
614
615
616
617
  			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...
618
619
  		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
620
  			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...
621
  				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
622
623
624
625
  			goto bail4;
  		}
  		a = sbi->sb_dirband_size;
  		sbi->sb_dirband_size = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
626
627
628
  		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...
629
  			mark_dirty(s, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
636
  			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...
637
638
  	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
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  			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);
  	s->s_root = d_alloc_root(root);
  	if (!s->s_root) {
  		iput(root);
  		goto bail0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
664
665
666
667
  
  	/*
  	 * 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...
668
  		root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  		root->i_atime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
670
  		root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  		root->i_mtime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
672
  		root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  		root->i_ctime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
674
  		hpfs_i(root)->i_ea_size = le16_to_cpu(de->ea_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
678
679
680
681
  		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...
682
  	hpfs_unlock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
  	return 0;
  
  bail4:	brelse(bh2);
  bail3:	brelse(bh1);
  bail2:	brelse(bh0);
  bail1:
  bail0:
7dd29d8d8   Mikulas Patocka   HPFS: Introduce a...
690
  	hpfs_unlock(s);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
691
692
  	kfree(sbi->sb_bmp_dir);
  	kfree(sbi->sb_cp_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
  	s->s_fs_info = NULL;
  	kfree(sbi);
  	return -EINVAL;
  }
152a08366   Al Viro   new helper: mount...
697
698
  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
699
  {
152a08366   Al Viro   new helper: mount...
700
  	return mount_bdev(fs_type, flags, dev_name, data, hpfs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
  }
  
  static struct file_system_type hpfs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "hpfs",
152a08366   Al Viro   new helper: mount...
706
  	.mount		= hpfs_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
  	.kill_sb	= kill_block_super,
  	.fs_flags	= FS_REQUIRES_DEV,
  };
  
  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");