Blame view

fs/romfs/super.c 14.9 KB
da4458bda   David Howells   NOMMU: Make it po...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
53
54
55
56
57
  /* Block- or MTD-based romfs
   *
   * Copyright © 2007 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * Derived from: ROMFS file system, Linux implementation
   *
   * Copyright © 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
   *
   * Using parts of the minix filesystem
   * Copyright © 1991, 1992  Linus Torvalds
   *
   * and parts of the affs filesystem additionally
   * Copyright © 1993  Ray Burr
   * Copyright © 1996  Hans-Joachim Widmaier
   *
   * Changes
   *					Changed for 2.1.19 modules
   *	Jan 1997			Initial release
   *	Jun 1997			2.1.43+ changes
   *					Proper page locking in readpage
   *					Changed to work with 2.1.45+ fs
   *	Jul 1997			Fixed follow_link
   *			2.1.47
   *					lookup shouldn't return -ENOENT
   *					from Horst von Brand:
   *					  fail on wrong checksum
   *					  double unlock_super was possible
   *					  correct namelen for statfs
   *					spotted by Bill Hawes:
   *					  readlink shouldn't iput()
   *	Jun 1998	2.1.106		from Avery Pennarun: glibc scandir()
   *					  exposed a problem in readdir
   *			2.1.107		code-freeze spellchecker run
   *	Aug 1998			2.1.118+ VFS changes
   *	Sep 1998	2.1.122		another VFS change (follow_link)
   *	Apr 1999	2.2.7		no more EBADF checking in
   *					  lookup/readdir, use ERR_PTR
   *	Jun 1999	2.3.6		d_alloc_root use changed
   *			2.3.9		clean up usage of ENOENT/negative
   *					  dentries in lookup
   *					clean up page flags setting
   *					  (error, uptodate, locking) in
   *					  in readpage
   *					use init_special_inode for
   *					  fifos/sockets (and streamline) in
   *					  read_inode, fix _ops table order
   *	Aug 1999	2.3.16		__initfunc() => __init change
   *	Oct 1999	2.3.24		page->owner hack obsoleted
   *	Nov 1999	2.3.27		2.3.25+ page->offset => index change
   *
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public Licence
   * as published by the Free Software Foundation; either version
   * 2 of the Licence, or (at your option) any later version.
   */
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
58
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
da4458bda   David Howells   NOMMU: Make it po...
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
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  #include <linux/module.h>
  #include <linux/string.h>
  #include <linux/fs.h>
  #include <linux/time.h>
  #include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <linux/parser.h>
  #include <linux/mount.h>
  #include <linux/namei.h>
  #include <linux/statfs.h>
  #include <linux/mtd/super.h>
  #include <linux/ctype.h>
  #include <linux/highmem.h>
  #include <linux/pagemap.h>
  #include <linux/uaccess.h>
  #include "internal.h"
  
  static struct kmem_cache *romfs_inode_cachep;
  
  static const umode_t romfs_modemap[8] = {
  	0,			/* hard link */
  	S_IFDIR  | 0644,	/* directory */
  	S_IFREG  | 0644,	/* regular file */
  	S_IFLNK  | 0777,	/* symlink */
  	S_IFBLK  | 0600,	/* blockdev */
  	S_IFCHR  | 0600,	/* chardev */
  	S_IFSOCK | 0644,	/* socket */
  	S_IFIFO  | 0644		/* FIFO */
  };
  
  static const unsigned char romfs_dtype_table[] = {
  	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
  };
  
  static struct inode *romfs_iget(struct super_block *sb, unsigned long pos);
  
  /*
   * read a page worth of data from the image
   */
  static int romfs_readpage(struct file *file, struct page *page)
  {
  	struct inode *inode = page->mapping->host;
  	loff_t offset, size;
  	unsigned long fillsize, pos;
  	void *buf;
  	int ret;
  
  	buf = kmap(page);
  	if (!buf)
  		return -ENOMEM;
  
  	/* 32 bit warning -- but not for us :) */
  	offset = page_offset(page);
  	size = i_size_read(inode);
  	fillsize = 0;
  	ret = 0;
  	if (offset < size) {
  		size -= offset;
  		fillsize = size > PAGE_SIZE ? PAGE_SIZE : size;
  
  		pos = ROMFS_I(inode)->i_dataoffset + offset;
  
  		ret = romfs_dev_read(inode->i_sb, pos, buf, fillsize);
  		if (ret < 0) {
  			SetPageError(page);
  			fillsize = 0;
  			ret = -EIO;
  		}
  	}
  
  	if (fillsize < PAGE_SIZE)
  		memset(buf + fillsize, 0, PAGE_SIZE - fillsize);
  	if (ret == 0)
  		SetPageUptodate(page);
  
  	flush_dcache_page(page);
  	kunmap(page);
  	unlock_page(page);
  	return ret;
  }
  
  static const struct address_space_operations romfs_aops = {
  	.readpage	= romfs_readpage
  };
  
  /*
   * read the entries from a directory
   */
3903b38ce   Al Viro   [readdir] convert...
148
  static int romfs_readdir(struct file *file, struct dir_context *ctx)
da4458bda   David Howells   NOMMU: Make it po...
149
  {
3903b38ce   Al Viro   [readdir] convert...
150
  	struct inode *i = file_inode(file);
da4458bda   David Howells   NOMMU: Make it po...
151
152
153
  	struct romfs_inode ri;
  	unsigned long offset, maxoff;
  	int j, ino, nextfh;
da4458bda   David Howells   NOMMU: Make it po...
154
155
156
157
  	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
  	int ret;
  
  	maxoff = romfs_maxsize(i->i_sb);
3903b38ce   Al Viro   [readdir] convert...
158
  	offset = ctx->pos;
da4458bda   David Howells   NOMMU: Make it po...
159
160
161
162
163
164
165
166
167
168
169
170
  	if (!offset) {
  		offset = i->i_ino & ROMFH_MASK;
  		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
  		if (ret < 0)
  			goto out;
  		offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
  	}
  
  	/* Not really failsafe, but we are read-only... */
  	for (;;) {
  		if (!offset || offset >= maxoff) {
  			offset = maxoff;
3903b38ce   Al Viro   [readdir] convert...
171
  			ctx->pos = offset;
da4458bda   David Howells   NOMMU: Make it po...
172
173
  			goto out;
  		}
3903b38ce   Al Viro   [readdir] convert...
174
  		ctx->pos = offset;
da4458bda   David Howells   NOMMU: Make it po...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  
  		/* Fetch inode info */
  		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
  		if (ret < 0)
  			goto out;
  
  		j = romfs_dev_strnlen(i->i_sb, offset + ROMFH_SIZE,
  				      sizeof(fsname) - 1);
  		if (j < 0)
  			goto out;
  
  		ret = romfs_dev_read(i->i_sb, offset + ROMFH_SIZE, fsname, j);
  		if (ret < 0)
  			goto out;
  		fsname[j] = '\0';
  
  		ino = offset;
  		nextfh = be32_to_cpu(ri.next);
  		if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
  			ino = be32_to_cpu(ri.spec);
3903b38ce   Al Viro   [readdir] convert...
195
196
  		if (!dir_emit(ctx, fsname, j, ino,
  			    romfs_dtype_table[nextfh & ROMFH_TYPE]))
da4458bda   David Howells   NOMMU: Make it po...
197
  			goto out;
da4458bda   David Howells   NOMMU: Make it po...
198
199
  		offset = nextfh & ROMFH_MASK;
  	}
da4458bda   David Howells   NOMMU: Make it po...
200
  out:
3903b38ce   Al Viro   [readdir] convert...
201
  	return 0;
da4458bda   David Howells   NOMMU: Make it po...
202
203
204
205
206
207
  }
  
  /*
   * look up an entry in a directory
   */
  static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
208
  				   unsigned int flags)
da4458bda   David Howells   NOMMU: Make it po...
209
210
211
212
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
  {
  	unsigned long offset, maxoff;
  	struct inode *inode;
  	struct romfs_inode ri;
  	const char *name;		/* got from dentry */
  	int len, ret;
  
  	offset = dir->i_ino & ROMFH_MASK;
  	ret = romfs_dev_read(dir->i_sb, offset, &ri, ROMFH_SIZE);
  	if (ret < 0)
  		goto error;
  
  	/* search all the file entries in the list starting from the one
  	 * pointed to by the directory's special data */
  	maxoff = romfs_maxsize(dir->i_sb);
  	offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
  
  	name = dentry->d_name.name;
  	len = dentry->d_name.len;
  
  	for (;;) {
  		if (!offset || offset >= maxoff)
  			goto out0;
  
  		ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri));
  		if (ret < 0)
  			goto error;
  
  		/* try to match the first 16 bytes of name */
84baf74bf   David Howells   ROMFS: romfs_look...
238
239
  		ret = romfs_dev_strcmp(dir->i_sb, offset + ROMFH_SIZE, name,
  				       len);
da4458bda   David Howells   NOMMU: Make it po...
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
275
276
277
278
  		if (ret < 0)
  			goto error;
  		if (ret == 1)
  			break;
  
  		/* next entry */
  		offset = be32_to_cpu(ri.next) & ROMFH_MASK;
  	}
  
  	/* Hard link handling */
  	if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
  		offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
  
  	inode = romfs_iget(dir->i_sb, offset);
  	if (IS_ERR(inode)) {
  		ret = PTR_ERR(inode);
  		goto error;
  	}
  	goto outi;
  
  	/*
  	 * it's a bit funky, _lookup needs to return an error code
  	 * (negative) or a NULL, both as a dentry.  ENOENT should not
  	 * be returned, instead we need to create a negative dentry by
  	 * d_add(dentry, NULL); and return 0 as no error.
  	 * (Although as I see, it only matters on writable file
  	 * systems).
  	 */
  out0:
  	inode = NULL;
  outi:
  	d_add(dentry, inode);
  	ret = 0;
  error:
  	return ERR_PTR(ret);
  }
  
  static const struct file_operations romfs_dir_operations = {
  	.read		= generic_read_dir,
3903b38ce   Al Viro   [readdir] convert...
279
  	.iterate	= romfs_readdir,
6038f373a   Arnd Bergmann   llseek: automatic...
280
  	.llseek		= default_llseek,
da4458bda   David Howells   NOMMU: Make it po...
281
  };
6e1d5dcc2   Alexey Dobriyan   const: mark remai...
282
  static const struct inode_operations romfs_dir_inode_operations = {
da4458bda   David Howells   NOMMU: Make it po...
283
284
285
286
287
288
289
290
291
292
293
294
295
  	.lookup		= romfs_lookup,
  };
  
  /*
   * get a romfs inode based on its position in the image (which doubles as the
   * inode number)
   */
  static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
  {
  	struct romfs_inode_info *inode;
  	struct romfs_inode ri;
  	struct inode *i;
  	unsigned long nlen;
774e33e70   Roel Kluin   ROMFS: romfs_dev_...
296
297
  	unsigned nextfh;
  	int ret;
da4458bda   David Howells   NOMMU: Make it po...
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
  	umode_t mode;
  
  	/* we might have to traverse a chain of "hard link" file entries to get
  	 * to the actual file */
  	for (;;) {
  		ret = romfs_dev_read(sb, pos, &ri, sizeof(ri));
  		if (ret < 0)
  			goto error;
  
  		/* XXX: do romfs_checksum here too (with name) */
  
  		nextfh = be32_to_cpu(ri.next);
  		if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
  			break;
  
  		pos = be32_to_cpu(ri.spec) & ROMFH_MASK;
  	}
  
  	/* determine the length of the filename */
  	nlen = romfs_dev_strnlen(sb, pos + ROMFH_SIZE, ROMFS_MAXFN);
  	if (IS_ERR_VALUE(nlen))
  		goto eio;
  
  	/* get an inode for this image position */
  	i = iget_locked(sb, pos);
  	if (!i)
  		return ERR_PTR(-ENOMEM);
  
  	if (!(i->i_state & I_NEW))
  		return i;
  
  	/* precalculate the data offset */
  	inode = ROMFS_I(i);
  	inode->i_metasize = (ROMFH_SIZE + nlen + 1 + ROMFH_PAD) & ROMFH_MASK;
  	inode->i_dataoffset = pos + inode->i_metasize;
bfe868486   Miklos Szeredi   filesystems: add ...
333
  	set_nlink(i, 1);		/* Hard to decide.. */
da4458bda   David Howells   NOMMU: Make it po...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  	i->i_size = be32_to_cpu(ri.size);
  	i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
  	i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
  
  	/* set up mode and ops */
  	mode = romfs_modemap[nextfh & ROMFH_TYPE];
  
  	switch (nextfh & ROMFH_TYPE) {
  	case ROMFH_DIR:
  		i->i_size = ROMFS_I(i)->i_metasize;
  		i->i_op = &romfs_dir_inode_operations;
  		i->i_fop = &romfs_dir_operations;
  		if (nextfh & ROMFH_EXEC)
  			mode |= S_IXUGO;
  		break;
  	case ROMFH_REG:
  		i->i_fop = &romfs_ro_fops;
  		i->i_data.a_ops = &romfs_aops;
da4458bda   David Howells   NOMMU: Make it po...
352
353
354
355
356
  		if (nextfh & ROMFH_EXEC)
  			mode |= S_IXUGO;
  		break;
  	case ROMFH_SYM:
  		i->i_op = &page_symlink_inode_operations;
21fc61c73   Al Viro   don't put symlink...
357
  		inode_nohighmem(i);
da4458bda   David Howells   NOMMU: Make it po...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  		i->i_data.a_ops = &romfs_aops;
  		mode |= S_IRWXUGO;
  		break;
  	default:
  		/* depending on MBZ for sock/fifos */
  		nextfh = be32_to_cpu(ri.spec);
  		init_special_inode(i, mode, MKDEV(nextfh >> 16,
  						  nextfh & 0xffff));
  		break;
  	}
  
  	i->i_mode = mode;
  
  	unlock_new_inode(i);
  	return i;
  
  eio:
  	ret = -EIO;
  error:
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
377
378
  	pr_err("read error for inode 0x%lx
  ", pos);
da4458bda   David Howells   NOMMU: Make it po...
379
380
381
382
383
384
385
386
387
  	return ERR_PTR(ret);
  }
  
  /*
   * allocate a new inode
   */
  static struct inode *romfs_alloc_inode(struct super_block *sb)
  {
  	struct romfs_inode_info *inode;
b6d53b1b1   Fabian Frederick   fs/romfs/super.c:...
388

da4458bda   David Howells   NOMMU: Make it po...
389
390
391
392
393
394
395
  	inode = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL);
  	return inode ? &inode->vfs_inode : NULL;
  }
  
  /*
   * return a spent inode to the slab cache
   */
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
396
  static void romfs_i_callback(struct rcu_head *head)
da4458bda   David Howells   NOMMU: Make it po...
397
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
398
  	struct inode *inode = container_of(head, struct inode, i_rcu);
b6d53b1b1   Fabian Frederick   fs/romfs/super.c:...
399

da4458bda   David Howells   NOMMU: Make it po...
400
401
  	kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
402
403
404
405
  static void romfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, romfs_i_callback);
  }
da4458bda   David Howells   NOMMU: Make it po...
406
407
408
409
410
  /*
   * get filesystem statistics
   */
  static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
  {
8a59f5d25   Coly Li   fs/romfs: return ...
411
412
  	struct super_block *sb = dentry->d_sb;
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
da4458bda   David Howells   NOMMU: Make it po...
413
414
415
416
417
418
  	buf->f_type = ROMFS_MAGIC;
  	buf->f_namelen = ROMFS_MAXFN;
  	buf->f_bsize = ROMBSIZE;
  	buf->f_bfree = buf->f_bavail = buf->f_ffree;
  	buf->f_blocks =
  		(romfs_maxsize(dentry->d_sb) + ROMBSIZE - 1) >> ROMBSBITS;
8a59f5d25   Coly Li   fs/romfs: return ...
419
420
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
da4458bda   David Howells   NOMMU: Make it po...
421
422
423
424
425
426
427
428
  	return 0;
  }
  
  /*
   * remounting must involve read-only
   */
  static int romfs_remount(struct super_block *sb, int *flags, char *data)
  {
02b9984d6   Theodore Ts'o   fs: push sync_fil...
429
  	sync_filesystem(sb);
da4458bda   David Howells   NOMMU: Make it po...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
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
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  	*flags |= MS_RDONLY;
  	return 0;
  }
  
  static const struct super_operations romfs_super_ops = {
  	.alloc_inode	= romfs_alloc_inode,
  	.destroy_inode	= romfs_destroy_inode,
  	.statfs		= romfs_statfs,
  	.remount_fs	= romfs_remount,
  };
  
  /*
   * checksum check on part of a romfs filesystem
   */
  static __u32 romfs_checksum(const void *data, int size)
  {
  	const __be32 *ptr = data;
  	__u32 sum;
  
  	sum = 0;
  	size >>= 2;
  	while (size > 0) {
  		sum += be32_to_cpu(*ptr++);
  		size--;
  	}
  	return sum;
  }
  
  /*
   * fill in the superblock
   */
  static int romfs_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct romfs_super_block *rsb;
  	struct inode *root;
  	unsigned long pos, img_size;
  	const char *storage;
  	size_t len;
  	int ret;
  
  #ifdef CONFIG_BLOCK
  	if (!sb->s_mtd) {
  		sb_set_blocksize(sb, ROMBSIZE);
  	} else {
  		sb->s_blocksize = ROMBSIZE;
  		sb->s_blocksize_bits = blksize_bits(ROMBSIZE);
  	}
  #endif
  
  	sb->s_maxbytes = 0xFFFFFFFF;
  	sb->s_magic = ROMFS_MAGIC;
  	sb->s_flags |= MS_RDONLY | MS_NOATIME;
  	sb->s_op = &romfs_super_ops;
  
  	/* read the image superblock and check it */
  	rsb = kmalloc(512, GFP_KERNEL);
  	if (!rsb)
  		return -ENOMEM;
  
  	sb->s_fs_info = (void *) 512;
  	ret = romfs_dev_read(sb, 0, rsb, 512);
  	if (ret < 0)
  		goto error_rsb;
  
  	img_size = be32_to_cpu(rsb->size);
  
  	if (sb->s_mtd && img_size > sb->s_mtd->size)
  		goto error_rsb_inval;
  
  	sb->s_fs_info = (void *) img_size;
  
  	if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 ||
  	    img_size < ROMFH_SIZE) {
  		if (!silent)
3d79d3145   Fabian Frederick   fs/romfs/super.c:...
504
505
  			pr_warn("VFS: Can't find a romfs filesystem on dev %s.
  ",
da4458bda   David Howells   NOMMU: Make it po...
506
507
508
509
510
  			       sb->s_id);
  		goto error_rsb_inval;
  	}
  
  	if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) {
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
511
512
  		pr_err("bad initial checksum on dev %s.
  ", sb->s_id);
da4458bda   David Howells   NOMMU: Make it po...
513
514
515
516
517
518
519
  		goto error_rsb_inval;
  	}
  
  	storage = sb->s_mtd ? "MTD" : "the block layer";
  
  	len = strnlen(rsb->name, ROMFS_MAXFN);
  	if (!silent)
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
520
521
522
  		pr_notice("Mounting image '%*.*s' through %s
  ",
  			  (unsigned) len, (unsigned) len, rsb->name, storage);
da4458bda   David Howells   NOMMU: Make it po...
523
524
525
526
527
528
529
530
  
  	kfree(rsb);
  	rsb = NULL;
  
  	/* find the root directory */
  	pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK;
  
  	root = romfs_iget(sb, pos);
a21f3c2a0   Julia Lawall   fs/romfs: correct...
531
  	if (IS_ERR(root))
40e2c71d5   Rui Xiang   romfs: fix returm...
532
  		return PTR_ERR(root);
da4458bda   David Howells   NOMMU: Make it po...
533

48fde701a   Al Viro   switch open-coded...
534
  	sb->s_root = d_make_root(root);
da4458bda   David Howells   NOMMU: Make it po...
535
  	if (!sb->s_root)
40e2c71d5   Rui Xiang   romfs: fix returm...
536
  		return -ENOMEM;
da4458bda   David Howells   NOMMU: Make it po...
537
538
  
  	return 0;
da4458bda   David Howells   NOMMU: Make it po...
539
540
541
  error_rsb_inval:
  	ret = -EINVAL;
  error_rsb:
7e32b7bb7   Al Viro   fix leak in romfs...
542
  	kfree(rsb);
da4458bda   David Howells   NOMMU: Make it po...
543
544
545
546
547
548
  	return ret;
  }
  
  /*
   * get a superblock for mounting
   */
848b83a59   Al Viro   convert get_sb_mt...
549
  static struct dentry *romfs_mount(struct file_system_type *fs_type,
da4458bda   David Howells   NOMMU: Make it po...
550
  			int flags, const char *dev_name,
848b83a59   Al Viro   convert get_sb_mt...
551
  			void *data)
da4458bda   David Howells   NOMMU: Make it po...
552
  {
848b83a59   Al Viro   convert get_sb_mt...
553
  	struct dentry *ret = ERR_PTR(-EINVAL);
da4458bda   David Howells   NOMMU: Make it po...
554
555
  
  #ifdef CONFIG_ROMFS_ON_MTD
848b83a59   Al Viro   convert get_sb_mt...
556
  	ret = mount_mtd(fs_type, flags, dev_name, data, romfs_fill_super);
da4458bda   David Howells   NOMMU: Make it po...
557
558
  #endif
  #ifdef CONFIG_ROMFS_ON_BLOCK
848b83a59   Al Viro   convert get_sb_mt...
559
560
561
  	if (ret == ERR_PTR(-EINVAL))
  		ret = mount_bdev(fs_type, flags, dev_name, data,
  				  romfs_fill_super);
da4458bda   David Howells   NOMMU: Make it po...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  #endif
  	return ret;
  }
  
  /*
   * destroy a romfs superblock in the appropriate manner
   */
  static void romfs_kill_sb(struct super_block *sb)
  {
  #ifdef CONFIG_ROMFS_ON_MTD
  	if (sb->s_mtd) {
  		kill_mtd_super(sb);
  		return;
  	}
  #endif
  #ifdef CONFIG_ROMFS_ON_BLOCK
  	if (sb->s_bdev) {
  		kill_block_super(sb);
  		return;
  	}
  #endif
  }
  
  static struct file_system_type romfs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "romfs",
848b83a59   Al Viro   convert get_sb_mt...
588
  	.mount		= romfs_mount,
da4458bda   David Howells   NOMMU: Make it po...
589
590
591
  	.kill_sb	= romfs_kill_sb,
  	.fs_flags	= FS_REQUIRES_DEV,
  };
7f78e0351   Eric W. Biederman   fs: Limit sys_mou...
592
  MODULE_ALIAS_FS("romfs");
da4458bda   David Howells   NOMMU: Make it po...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  
  /*
   * inode storage initialiser
   */
  static void romfs_i_init_once(void *_inode)
  {
  	struct romfs_inode_info *inode = _inode;
  
  	inode_init_once(&inode->vfs_inode);
  }
  
  /*
   * romfs module initialisation
   */
  static int __init init_romfs_fs(void)
  {
  	int ret;
3d79d3145   Fabian Frederick   fs/romfs/super.c:...
610
611
  	pr_info("ROMFS MTD (C) 2007 Red Hat, Inc.
  ");
da4458bda   David Howells   NOMMU: Make it po...
612
613
614
615
  
  	romfs_inode_cachep =
  		kmem_cache_create("romfs_i",
  				  sizeof(struct romfs_inode_info), 0,
5d097056c   Vladimir Davydov   kmemcg: account c...
616
617
  				  SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
  				  SLAB_ACCOUNT, romfs_i_init_once);
da4458bda   David Howells   NOMMU: Make it po...
618
619
  
  	if (!romfs_inode_cachep) {
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
620
621
  		pr_err("Failed to initialise inode cache
  ");
da4458bda   David Howells   NOMMU: Make it po...
622
623
624
625
  		return -ENOMEM;
  	}
  	ret = register_filesystem(&romfs_fs_type);
  	if (ret) {
ca9e5368a   Fabian Frederick   fs/romfs/super.c:...
626
627
  		pr_err("Failed to register filesystem
  ");
da4458bda   David Howells   NOMMU: Make it po...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  		goto error_register;
  	}
  	return 0;
  
  error_register:
  	kmem_cache_destroy(romfs_inode_cachep);
  	return ret;
  }
  
  /*
   * romfs module removal
   */
  static void __exit exit_romfs_fs(void)
  {
  	unregister_filesystem(&romfs_fs_type);
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
643
644
645
646
647
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
da4458bda   David Howells   NOMMU: Make it po...
648
649
650
651
652
653
654
655
656
  	kmem_cache_destroy(romfs_inode_cachep);
  }
  
  module_init(init_romfs_fs);
  module_exit(exit_romfs_fs);
  
  MODULE_DESCRIPTION("Direct-MTD Capable RomFS");
  MODULE_AUTHOR("Red Hat, Inc.");
  MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */