Blame view

fs/logfs/super.c 16.3 KB
5db53f3e8   Joern Engel   [LogFS] add new f...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * fs/logfs/super.c
   *
   * As should be obvious for Linux kernel code, license is GPLv2
   *
   * Copyright (c) 2005-2008 Joern Engel <joern@logfs.org>
   *
   * Generally contains mount/umount code and also serves as a dump area for
   * any functions that don't fit elsewhere and neither justify a file of their
   * own.
   */
  #include "logfs.h"
  #include <linux/bio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
b8639077a   Joern Engel   [LogFS] Set s_bdi
15
  #include <linux/blkdev.h>
143cb494c   Paul Gortmaker   fs: add module.h ...
16
  #include <linux/module.h>
5db53f3e8   Joern Engel   [LogFS] add new f...
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  #include <linux/mtd/mtd.h>
  #include <linux/statfs.h>
  #include <linux/buffer_head.h>
  
  static DEFINE_MUTEX(emergency_mutex);
  static struct page *emergency_page;
  
  struct page *emergency_read_begin(struct address_space *mapping, pgoff_t index)
  {
  	filler_t *filler = (filler_t *)mapping->a_ops->readpage;
  	struct page *page;
  	int err;
  
  	page = read_cache_page(mapping, index, filler, NULL);
  	if (page)
  		return page;
  
  	/* No more pages available, switch to emergency page */
  	printk(KERN_INFO"Logfs: Using emergency page
  ");
  	mutex_lock(&emergency_mutex);
  	err = filler(NULL, emergency_page);
  	if (err) {
  		mutex_unlock(&emergency_mutex);
  		printk(KERN_EMERG"Logfs: Error reading emergency page
  ");
  		return ERR_PTR(err);
  	}
  	return emergency_page;
  }
  
  void emergency_read_end(struct page *page)
  {
  	if (page == emergency_page)
  		mutex_unlock(&emergency_mutex);
  	else
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
53
  		put_page(page);
5db53f3e8   Joern Engel   [LogFS] add new f...
54
55
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
87
88
89
90
91
92
93
94
95
96
97
  }
  
  static void dump_segfile(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct logfs_segment_entry se;
  	u32 segno;
  
  	for (segno = 0; segno < super->s_no_segs; segno++) {
  		logfs_get_segment_entry(sb, segno, &se);
  		printk("%3x: %6x %8x", segno, be32_to_cpu(se.ec_level),
  				be32_to_cpu(se.valid));
  		if (++segno < super->s_no_segs) {
  			logfs_get_segment_entry(sb, segno, &se);
  			printk(" %6x %8x", be32_to_cpu(se.ec_level),
  					be32_to_cpu(se.valid));
  		}
  		if (++segno < super->s_no_segs) {
  			logfs_get_segment_entry(sb, segno, &se);
  			printk(" %6x %8x", be32_to_cpu(se.ec_level),
  					be32_to_cpu(se.valid));
  		}
  		if (++segno < super->s_no_segs) {
  			logfs_get_segment_entry(sb, segno, &se);
  			printk(" %6x %8x", be32_to_cpu(se.ec_level),
  					be32_to_cpu(se.valid));
  		}
  		printk("
  ");
  	}
  }
  
  /*
   * logfs_crash_dump - dump debug information to device
   *
   * The LogFS superblock only occupies part of a segment.  This function will
   * write as much debug information as it can gather into the spare space.
   */
  void logfs_crash_dump(struct super_block *sb)
  {
  	dump_segfile(sb);
  }
  
  /*
5db53f3e8   Joern Engel   [LogFS] add new f...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
   * FIXME: There should be a reserve for root, similar to ext2.
   */
  int logfs_statfs(struct dentry *dentry, struct kstatfs *stats)
  {
  	struct super_block *sb = dentry->d_sb;
  	struct logfs_super *super = logfs_super(sb);
  
  	stats->f_type		= LOGFS_MAGIC_U32;
  	stats->f_bsize		= sb->s_blocksize;
  	stats->f_blocks		= super->s_size >> LOGFS_BLOCK_BITS >> 3;
  	stats->f_bfree		= super->s_free_bytes >> sb->s_blocksize_bits;
  	stats->f_bavail		= super->s_free_bytes >> sb->s_blocksize_bits;
  	stats->f_files		= 0;
  	stats->f_ffree		= 0;
  	stats->f_namelen	= LOGFS_MAX_NAMELEN;
  	return 0;
  }
  
  static int logfs_sb_set(struct super_block *sb, void *_super)
  {
  	struct logfs_super *super = _super;
  
  	sb->s_fs_info = super;
  	sb->s_mtd = super->s_mtd;
  	sb->s_bdev = super->s_bdev;
bba0b5c2c   Joern Engel   logfs: fix compil...
123
  #ifdef CONFIG_BLOCK
b8639077a   Joern Engel   [LogFS] Set s_bdi
124
125
  	if (sb->s_bdev)
  		sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
bba0b5c2c   Joern Engel   logfs: fix compil...
126
127
  #endif
  #ifdef CONFIG_MTD
b8639077a   Joern Engel   [LogFS] Set s_bdi
128
129
  	if (sb->s_mtd)
  		sb->s_bdi = sb->s_mtd->backing_dev_info;
bba0b5c2c   Joern Engel   logfs: fix compil...
130
  #endif
5db53f3e8   Joern Engel   [LogFS] add new f...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  	return 0;
  }
  
  static int logfs_sb_test(struct super_block *sb, void *_super)
  {
  	struct logfs_super *super = _super;
  	struct mtd_info *mtd = super->s_mtd;
  
  	if (mtd && sb->s_mtd == mtd)
  		return 1;
  	if (super->s_bdev && sb->s_bdev == super->s_bdev)
  		return 1;
  	return 0;
  }
  
  static void set_segment_header(struct logfs_segment_header *sh, u8 type,
  		u8 level, u32 segno, u32 ec)
  {
  	sh->pad = 0;
  	sh->type = type;
  	sh->level = level;
  	sh->segno = cpu_to_be32(segno);
  	sh->ec = cpu_to_be32(ec);
  	sh->gec = cpu_to_be64(segno);
  	sh->crc = logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4);
  }
  
  static void logfs_write_ds(struct super_block *sb, struct logfs_disk_super *ds,
  		u32 segno, u32 ec)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct logfs_segment_header *sh = &ds->ds_sh;
  	int i;
  
  	memset(ds, 0, sizeof(*ds));
  	set_segment_header(sh, SEG_SUPER, 0, segno, ec);
  
  	ds->ds_ifile_levels	= super->s_ifile_levels;
  	ds->ds_iblock_levels	= super->s_iblock_levels;
  	ds->ds_data_levels	= super->s_data_levels; /* XXX: Remove */
  	ds->ds_segment_shift	= super->s_segshift;
  	ds->ds_block_shift	= sb->s_blocksize_bits;
  	ds->ds_write_shift	= super->s_writeshift;
  	ds->ds_filesystem_size	= cpu_to_be64(super->s_size);
  	ds->ds_segment_size	= cpu_to_be32(super->s_segsize);
  	ds->ds_bad_seg_reserve	= cpu_to_be32(super->s_bad_seg_reserve);
  	ds->ds_feature_incompat	= cpu_to_be64(super->s_feature_incompat);
  	ds->ds_feature_ro_compat= cpu_to_be64(super->s_feature_ro_compat);
  	ds->ds_feature_compat	= cpu_to_be64(super->s_feature_compat);
  	ds->ds_feature_flags	= cpu_to_be64(super->s_feature_flags);
  	ds->ds_root_reserve	= cpu_to_be64(super->s_root_reserve);
  	ds->ds_speed_reserve	= cpu_to_be64(super->s_speed_reserve);
  	journal_for_each(i)
  		ds->ds_journal_seg[i] = cpu_to_be32(super->s_journal_seg[i]);
  	ds->ds_magic		= cpu_to_be64(LOGFS_MAGIC);
  	ds->ds_crc = logfs_crc32(ds, sizeof(*ds),
  			LOGFS_SEGMENT_HEADERSIZE + 12);
  }
  
  static int write_one_sb(struct super_block *sb,
  		struct page *(*find_sb)(struct super_block *sb, u64 *ofs))
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct logfs_disk_super *ds;
  	struct logfs_segment_entry se;
  	struct page *page;
  	u64 ofs;
  	u32 ec, segno;
  	int err;
  
  	page = find_sb(sb, &ofs);
  	if (!page)
  		return -EIO;
  	ds = page_address(page);
  	segno = seg_no(sb, ofs);
  	logfs_get_segment_entry(sb, segno, &se);
  	ec = be32_to_cpu(se.ec_level) >> 4;
  	ec++;
  	logfs_set_segment_erased(sb, segno, ec, 0);
  	logfs_write_ds(sb, ds, segno, ec);
  	err = super->s_devops->write_sb(sb, page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
212
  	put_page(page);
5db53f3e8   Joern Engel   [LogFS] add new f...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  	return err;
  }
  
  int logfs_write_sb(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  	int err;
  
  	/* First superblock */
  	err = write_one_sb(sb, super->s_devops->find_first_sb);
  	if (err)
  		return err;
  
  	/* Last superblock */
  	err = write_one_sb(sb, super->s_devops->find_last_sb);
  	if (err)
  		return err;
  	return 0;
  }
  
  static int ds_cmp(const void *ds0, const void *ds1)
  {
  	size_t len = sizeof(struct logfs_disk_super);
  
  	/* We know the segment headers differ, so ignore them */
  	len -= LOGFS_SEGMENT_HEADERSIZE;
  	ds0 += LOGFS_SEGMENT_HEADERSIZE;
  	ds1 += LOGFS_SEGMENT_HEADERSIZE;
  	return memcmp(ds0, ds1, len);
  }
  
  static int logfs_recover_sb(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct logfs_disk_super _ds0, *ds0 = &_ds0;
  	struct logfs_disk_super _ds1, *ds1 = &_ds1;
  	int err, valid0, valid1;
  
  	/* read first superblock */
  	err = wbuf_read(sb, super->s_sb_ofs[0], sizeof(*ds0), ds0);
  	if (err)
  		return err;
  	/* read last superblock */
  	err = wbuf_read(sb, super->s_sb_ofs[1], sizeof(*ds1), ds1);
  	if (err)
  		return err;
  	valid0 = logfs_check_ds(ds0) == 0;
  	valid1 = logfs_check_ds(ds1) == 0;
  
  	if (!valid0 && valid1) {
  		printk(KERN_INFO"First superblock is invalid - fixing.
  ");
  		return write_one_sb(sb, super->s_devops->find_first_sb);
  	}
  	if (valid0 && !valid1) {
  		printk(KERN_INFO"Last superblock is invalid - fixing.
  ");
  		return write_one_sb(sb, super->s_devops->find_last_sb);
  	}
  	if (valid0 && valid1 && ds_cmp(ds0, ds1)) {
  		printk(KERN_INFO"Superblocks don't match - fixing.
  ");
faaa27ab9   Joern Engel   Write out both su...
275
  		return logfs_write_sb(sb);
5db53f3e8   Joern Engel   [LogFS] add new f...
276
277
278
279
280
281
282
283
284
285
  	}
  	/* If neither is valid now, something's wrong.  Didn't we properly
  	 * check them before?!? */
  	BUG_ON(!valid0 && !valid1);
  	return 0;
  }
  
  static int logfs_make_writeable(struct super_block *sb)
  {
  	int err;
49137f2ef   Joern Engel   Open segment file...
286
287
288
  	err = logfs_open_segfile(sb);
  	if (err)
  		return err;
5db53f3e8   Joern Engel   [LogFS] add new f...
289
290
291
292
293
294
295
296
297
  	/* Repair any broken superblock copies */
  	err = logfs_recover_sb(sb);
  	if (err)
  		return err;
  
  	/* Check areas for trailing unaccounted data */
  	err = logfs_check_areas(sb);
  	if (err)
  		return err;
5db53f3e8   Joern Engel   [LogFS] add new f...
298
299
300
301
302
303
304
305
306
307
308
  	/* Do one GC pass before any data gets dirtied */
  	logfs_gc_pass(sb);
  
  	/* after all initializations are done, replay the journal
  	 * for rw-mounts, if necessary */
  	err = logfs_replay_journal(sb);
  	if (err)
  		return err;
  
  	return 0;
  }
a1da9e8ab   Al Viro   switch logfs to -...
309
  static int logfs_get_sb_final(struct super_block *sb)
5db53f3e8   Joern Engel   [LogFS] add new f...
310
  {
9421502b4   Joern Engel   [LogFS] Fix bdev ...
311
  	struct logfs_super *super = logfs_super(sb);
5db53f3e8   Joern Engel   [LogFS] add new f...
312
313
314
315
316
317
318
  	struct inode *rootdir;
  	int err;
  
  	/* root dir */
  	rootdir = logfs_iget(sb, LOGFS_INO_ROOT);
  	if (IS_ERR(rootdir))
  		goto fail;
48fde701a   Al Viro   switch open-coded...
319
320
  	sb->s_root = d_make_root(rootdir);
  	if (!sb->s_root)
265624495   Al Viro   Fix double-free i...
321
  		goto fail;
5db53f3e8   Joern Engel   [LogFS] add new f...
322

8e22c1a4e   Al Viro   logfs: get rid of...
323
  	/* at that point we know that ->put_super() will be called */
9421502b4   Joern Engel   [LogFS] Fix bdev ...
324
325
  	super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
  	if (!super->s_erase_page)
8e22c1a4e   Al Viro   logfs: get rid of...
326
  		return -ENOMEM;
9421502b4   Joern Engel   [LogFS] Fix bdev ...
327
  	memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE);
5db53f3e8   Joern Engel   [LogFS] add new f...
328
329
  	/* FIXME: check for read-only mounts */
  	err = logfs_make_writeable(sb);
8e22c1a4e   Al Viro   logfs: get rid of...
330
331
332
333
  	if (err) {
  		__free_page(super->s_erase_page);
  		return err;
  	}
5db53f3e8   Joern Engel   [LogFS] add new f...
334
335
336
  
  	log_super("LogFS: Finished mounting
  ");
5db53f3e8   Joern Engel   [LogFS] add new f...
337
  	return 0;
5db53f3e8   Joern Engel   [LogFS] add new f...
338
  fail:
8e22c1a4e   Al Viro   logfs: get rid of...
339
340
341
  	iput(super->s_master_inode);
  	iput(super->s_segfile_inode);
  	iput(super->s_mapping_inode);
5db53f3e8   Joern Engel   [LogFS] add new f...
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
  	return -EIO;
  }
  
  int logfs_check_ds(struct logfs_disk_super *ds)
  {
  	struct logfs_segment_header *sh = &ds->ds_sh;
  
  	if (ds->ds_magic != cpu_to_be64(LOGFS_MAGIC))
  		return -EINVAL;
  	if (sh->crc != logfs_crc32(sh, LOGFS_SEGMENT_HEADERSIZE, 4))
  		return -EINVAL;
  	if (ds->ds_crc != logfs_crc32(ds, sizeof(*ds),
  				LOGFS_SEGMENT_HEADERSIZE + 12))
  		return -EINVAL;
  	return 0;
  }
  
  static struct page *find_super_block(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct page *first, *last;
  
  	first = super->s_devops->find_first_sb(sb, &super->s_sb_ofs[0]);
  	if (!first || IS_ERR(first))
  		return NULL;
  	last = super->s_devops->find_last_sb(sb, &super->s_sb_ofs[1]);
3272c8a57   Dan Carpenter   logfs: testing th...
368
  	if (!last || IS_ERR(last)) {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
369
  		put_page(first);
5db53f3e8   Joern Engel   [LogFS] add new f...
370
371
372
373
  		return NULL;
  	}
  
  	if (!logfs_check_ds(page_address(first))) {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
374
  		put_page(last);
5db53f3e8   Joern Engel   [LogFS] add new f...
375
376
377
378
379
  		return first;
  	}
  
  	/* First one didn't work, try the second superblock */
  	if (!logfs_check_ds(page_address(last))) {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
380
  		put_page(first);
5db53f3e8   Joern Engel   [LogFS] add new f...
381
382
383
384
  		return last;
  	}
  
  	/* Neither worked, sorry folks */
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
385
386
  	put_page(first);
  	put_page(last);
5db53f3e8   Joern Engel   [LogFS] add new f...
387
388
389
390
391
392
393
394
395
396
397
398
  	return NULL;
  }
  
  static int __logfs_read_sb(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  	struct page *page;
  	struct logfs_disk_super *ds;
  	int i;
  
  	page = find_super_block(sb);
  	if (!page)
ad342631f   Joern Engel   logfs: Return -EI...
399
  		return -EINVAL;
5db53f3e8   Joern Engel   [LogFS] add new f...
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
  
  	ds = page_address(page);
  	super->s_size = be64_to_cpu(ds->ds_filesystem_size);
  	super->s_root_reserve = be64_to_cpu(ds->ds_root_reserve);
  	super->s_speed_reserve = be64_to_cpu(ds->ds_speed_reserve);
  	super->s_bad_seg_reserve = be32_to_cpu(ds->ds_bad_seg_reserve);
  	super->s_segsize = 1 << ds->ds_segment_shift;
  	super->s_segmask = (1 << ds->ds_segment_shift) - 1;
  	super->s_segshift = ds->ds_segment_shift;
  	sb->s_blocksize = 1 << ds->ds_block_shift;
  	sb->s_blocksize_bits = ds->ds_block_shift;
  	super->s_writesize = 1 << ds->ds_write_shift;
  	super->s_writeshift = ds->ds_write_shift;
  	super->s_no_segs = super->s_size >> super->s_segshift;
  	super->s_no_blocks = super->s_segsize >> sb->s_blocksize_bits;
  	super->s_feature_incompat = be64_to_cpu(ds->ds_feature_incompat);
  	super->s_feature_ro_compat = be64_to_cpu(ds->ds_feature_ro_compat);
  	super->s_feature_compat = be64_to_cpu(ds->ds_feature_compat);
  	super->s_feature_flags = be64_to_cpu(ds->ds_feature_flags);
  
  	journal_for_each(i)
  		super->s_journal_seg[i] = be32_to_cpu(ds->ds_journal_seg[i]);
  
  	super->s_ifile_levels = ds->ds_ifile_levels;
  	super->s_iblock_levels = ds->ds_iblock_levels;
  	super->s_data_levels = ds->ds_data_levels;
  	super->s_total_levels = super->s_ifile_levels + super->s_iblock_levels
  		+ super->s_data_levels;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
428
  	put_page(page);
5db53f3e8   Joern Engel   [LogFS] add new f...
429
430
  	return 0;
  }
6a08ab846   Joern Engel   [LogFS] Check fea...
431
  static int logfs_read_sb(struct super_block *sb, int read_only)
5db53f3e8   Joern Engel   [LogFS] add new f...
432
433
434
435
436
437
438
439
440
441
  {
  	struct logfs_super *super = logfs_super(sb);
  	int ret;
  
  	super->s_btree_pool = mempool_create(32, btree_alloc, btree_free, NULL);
  	if (!super->s_btree_pool)
  		return -ENOMEM;
  
  	btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool);
  	btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool);
032d8f726   Joern Engel   [LogFS] Prevent m...
442
443
  	btree_init_mempool32(&super->s_shadow_tree.segment_map,
  			super->s_btree_pool);
5db53f3e8   Joern Engel   [LogFS] add new f...
444
445
446
447
448
449
450
451
  
  	ret = logfs_init_mapping(sb);
  	if (ret)
  		return ret;
  
  	ret = __logfs_read_sb(sb);
  	if (ret)
  		return ret;
6a08ab846   Joern Engel   [LogFS] Check fea...
452
453
454
455
456
  	if (super->s_feature_incompat & ~LOGFS_FEATURES_INCOMPAT)
  		return -EIO;
  	if ((super->s_feature_ro_compat & ~LOGFS_FEATURES_RO_COMPAT) &&
  			!read_only)
  		return -EIO;
5db53f3e8   Joern Engel   [LogFS] add new f...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  	ret = logfs_init_rw(sb);
  	if (ret)
  		return ret;
  
  	ret = logfs_init_areas(sb);
  	if (ret)
  		return ret;
  
  	ret = logfs_init_gc(sb);
  	if (ret)
  		return ret;
  
  	ret = logfs_init_journal(sb);
  	if (ret)
  		return ret;
  
  	return 0;
  }
  
  static void logfs_kill_sb(struct super_block *sb)
  {
  	struct logfs_super *super = logfs_super(sb);
  
  	log_super("LogFS: Start unmounting
  ");
  	/* Alias entries slow down mount, so evict as many as possible */
  	sync_filesystem(sb);
c6d383014   Joern Engel   [LogFS] Only writ...
484
  	logfs_write_anchor(sb);
1bcceaff8   Joern Engel   logfs: Free areas...
485
  	free_areas(sb);
5db53f3e8   Joern Engel   [LogFS] add new f...
486
487
488
489
490
  
  	/*
  	 * From this point on alias entries are simply dropped - and any
  	 * writes to the object store are considered bugs.
  	 */
5db53f3e8   Joern Engel   [LogFS] add new f...
491
492
493
  	log_super("LogFS: Now in shutdown
  ");
  	generic_shutdown_super(sb);
ecfd89099   Prasad Joshi   logfs: set superb...
494
  	super->s_flags |= LOGFS_SB_FLAG_SHUTDOWN;
5db53f3e8   Joern Engel   [LogFS] add new f...
495
496
497
498
499
500
501
  
  	BUG_ON(super->s_dirty_used_bytes || super->s_dirty_free_bytes);
  
  	logfs_cleanup_gc(sb);
  	logfs_cleanup_journal(sb);
  	logfs_cleanup_areas(sb);
  	logfs_cleanup_rw(sb);
9421502b4   Joern Engel   [LogFS] Fix bdev ...
502
503
  	if (super->s_erase_page)
  		__free_page(super->s_erase_page);
e5a0726a9   Al Viro   logfs: fix a leak...
504
  	super->s_devops->put_device(super);
1f1b0008e   Joern Engel   [LogFS] Prevent m...
505
506
  	logfs_mempool_destroy(super->s_btree_pool);
  	logfs_mempool_destroy(super->s_alias_pool);
5db53f3e8   Joern Engel   [LogFS] add new f...
507
508
509
510
  	kfree(super);
  	log_super("LogFS: Finished unmounting
  ");
  }
a1da9e8ab   Al Viro   switch logfs to -...
511
512
  static struct dentry *logfs_get_sb_device(struct logfs_super *super,
  		struct file_system_type *type, int flags)
5db53f3e8   Joern Engel   [LogFS] add new f...
513
  {
5db53f3e8   Joern Engel   [LogFS] add new f...
514
515
516
517
518
519
  	struct super_block *sb;
  	int err = -ENOMEM;
  	static int mount_count;
  
  	log_super("LogFS: Start mount %x
  ", mount_count++);
5db53f3e8   Joern Engel   [LogFS] add new f...
520

5db53f3e8   Joern Engel   [LogFS] add new f...
521
  	err = -EINVAL;
9249e17fe   David Howells   VFS: Pass mount f...
522
  	sb = sget(type, logfs_sb_test, logfs_sb_set, flags | MS_NOATIME, super);
a1da9e8ab   Al Viro   switch logfs to -...
523
524
525
526
527
  	if (IS_ERR(sb)) {
  		super->s_devops->put_device(super);
  		kfree(super);
  		return ERR_CAST(sb);
  	}
5db53f3e8   Joern Engel   [LogFS] add new f...
528
529
530
  
  	if (sb->s_root) {
  		/* Device is already in use */
a1da9e8ab   Al Viro   switch logfs to -...
531
532
533
  		super->s_devops->put_device(super);
  		kfree(super);
  		return dget(sb->s_root);
5db53f3e8   Joern Engel   [LogFS] add new f...
534
  	}
5db53f3e8   Joern Engel   [LogFS] add new f...
535
536
537
538
539
540
541
  	/*
  	 * sb->s_maxbytes is limited to 8TB.  On 32bit systems, the page cache
  	 * only covers 16TB and the upper 8TB are used for indirect blocks.
  	 * On 64bit system we could bump up the limit, but that would make
  	 * the filesystem incompatible with 32bit systems.
  	 */
  	sb->s_maxbytes	= (1ull << 43) - 1;
8de527787   Al Viro   vfs: check i_nlin...
542
  	sb->s_max_links = LOGFS_LINK_MAX;
5db53f3e8   Joern Engel   [LogFS] add new f...
543
  	sb->s_op	= &logfs_super_operations;
5db53f3e8   Joern Engel   [LogFS] add new f...
544

6a08ab846   Joern Engel   [LogFS] Check fea...
545
  	err = logfs_read_sb(sb, sb->s_flags & MS_RDONLY);
5db53f3e8   Joern Engel   [LogFS] add new f...
546
547
548
549
  	if (err)
  		goto err1;
  
  	sb->s_flags |= MS_ACTIVE;
a1da9e8ab   Al Viro   switch logfs to -...
550
551
  	err = logfs_get_sb_final(sb);
  	if (err) {
8e22c1a4e   Al Viro   logfs: get rid of...
552
  		deactivate_locked_super(sb);
a1da9e8ab   Al Viro   switch logfs to -...
553
554
555
  		return ERR_PTR(err);
  	}
  	return dget(sb->s_root);
5db53f3e8   Joern Engel   [LogFS] add new f...
556
557
  
  err1:
8e22c1a4e   Al Viro   logfs: get rid of...
558
559
560
561
  	/* no ->s_root, no ->put_super() */
  	iput(super->s_master_inode);
  	iput(super->s_segfile_inode);
  	iput(super->s_mapping_inode);
6f2e9e6a9   Joern Engel   Use deactivate_lo...
562
  	deactivate_locked_super(sb);
a1da9e8ab   Al Viro   switch logfs to -...
563
  	return ERR_PTR(err);
5db53f3e8   Joern Engel   [LogFS] add new f...
564
  }
a1da9e8ab   Al Viro   switch logfs to -...
565
566
  static struct dentry *logfs_mount(struct file_system_type *type, int flags,
  		const char *devname, void *data)
5db53f3e8   Joern Engel   [LogFS] add new f...
567
568
  {
  	ulong mtdnr;
71a1c0125   Al Viro   logfs get_sb mass...
569
  	struct logfs_super *super;
7d945a3aa   Al Viro   logfs get_sb, part 3
570
  	int err;
71a1c0125   Al Viro   logfs get_sb mass...
571
572
573
  
  	super = kzalloc(sizeof(*super), GFP_KERNEL);
  	if (!super)
a1da9e8ab   Al Viro   switch logfs to -...
574
  		return ERR_PTR(-ENOMEM);
5db53f3e8   Joern Engel   [LogFS] add new f...
575

cce2c56e7   Linus Torvalds   logfs: initialize...
576
577
578
  	mutex_init(&super->s_dirop_mutex);
  	mutex_init(&super->s_object_alias_mutex);
  	INIT_LIST_HEAD(&super->s_freeing_list);
5db53f3e8   Joern Engel   [LogFS] add new f...
579
  	if (!devname)
7d945a3aa   Al Viro   logfs get_sb, part 3
580
581
582
583
  		err = logfs_get_sb_bdev(super, type, devname);
  	else if (strncmp(devname, "mtd", 3))
  		err = logfs_get_sb_bdev(super, type, devname);
  	else {
5db53f3e8   Joern Engel   [LogFS] add new f...
584
585
  		char *garbage;
  		mtdnr = simple_strtoul(devname+3, &garbage, 0);
7d945a3aa   Al Viro   logfs get_sb, part 3
586
587
588
589
590
591
592
593
  		if (*garbage)
  			err = -EINVAL;
  		else
  			err = logfs_get_sb_mtd(super, mtdnr);
  	}
  
  	if (err) {
  		kfree(super);
a1da9e8ab   Al Viro   switch logfs to -...
594
  		return ERR_PTR(err);
5db53f3e8   Joern Engel   [LogFS] add new f...
595
  	}
a1da9e8ab   Al Viro   switch logfs to -...
596
  	return logfs_get_sb_device(super, type, flags);
5db53f3e8   Joern Engel   [LogFS] add new f...
597
598
599
600
601
  }
  
  static struct file_system_type logfs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "logfs",
a1da9e8ab   Al Viro   switch logfs to -...
602
  	.mount		= logfs_mount,
5db53f3e8   Joern Engel   [LogFS] add new f...
603
604
605
606
  	.kill_sb	= logfs_kill_sb,
  	.fs_flags	= FS_REQUIRES_DEV,
  
  };
7f78e0351   Eric W. Biederman   fs: Limit sys_mou...
607
  MODULE_ALIAS_FS("logfs");
5db53f3e8   Joern Engel   [LogFS] add new f...
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  
  static int __init logfs_init(void)
  {
  	int ret;
  
  	emergency_page = alloc_pages(GFP_KERNEL, 0);
  	if (!emergency_page)
  		return -ENOMEM;
  
  	ret = logfs_compr_init();
  	if (ret)
  		goto out1;
  
  	ret = logfs_init_inode_cache();
  	if (ret)
  		goto out2;
03e897a1e   Al Viro   logfs: missing cl...
624
625
626
627
  	ret = register_filesystem(&logfs_fs_type);
  	if (!ret)
  		return 0;
  	logfs_destroy_inode_cache();
5db53f3e8   Joern Engel   [LogFS] add new f...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  out2:
  	logfs_compr_exit();
  out1:
  	__free_pages(emergency_page, 0);
  	return ret;
  }
  
  static void __exit logfs_exit(void)
  {
  	unregister_filesystem(&logfs_fs_type);
  	logfs_destroy_inode_cache();
  	logfs_compr_exit();
  	__free_pages(emergency_page, 0);
  }
  
  module_init(logfs_init);
  module_exit(logfs_exit);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Joern Engel <joern@logfs.org>");
  MODULE_DESCRIPTION("scalable flash filesystem");