VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   35 Branches   59 Tags
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   1) /* Block- or MTD-based romfs
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   2)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   3)  * Copyright © 2007 Red Hat, Inc. All Rights Reserved.
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   4)  * Written by David Howells (dhowells@redhat.com)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   5)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   6)  * Derived from: ROMFS file system, Linux implementation
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   7)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   8)  * Copyright © 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000   9)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  10)  * Using parts of the minix filesystem
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  11)  * Copyright © 1991, 1992  Linus Torvalds
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  12)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  13)  * and parts of the affs filesystem additionally
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  14)  * Copyright © 1993  Ray Burr
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  15)  * Copyright © 1996  Hans-Joachim Widmaier
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  16)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  17)  * Changes
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  18)  *					Changed for 2.1.19 modules
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  19)  *	Jan 1997			Initial release
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  20)  *	Jun 1997			2.1.43+ changes
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  21)  *					Proper page locking in readpage
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  22)  *					Changed to work with 2.1.45+ fs
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  23)  *	Jul 1997			Fixed follow_link
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  24)  *			2.1.47
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  25)  *					lookup shouldn't return -ENOENT
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  26)  *					from Horst von Brand:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  27)  *					  fail on wrong checksum
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  28)  *					  double unlock_super was possible
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  29)  *					  correct namelen for statfs
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  30)  *					spotted by Bill Hawes:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  31)  *					  readlink shouldn't iput()
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  32)  *	Jun 1998	2.1.106		from Avery Pennarun: glibc scandir()
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  33)  *					  exposed a problem in readdir
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  34)  *			2.1.107		code-freeze spellchecker run
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  35)  *	Aug 1998			2.1.118+ VFS changes
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  36)  *	Sep 1998	2.1.122		another VFS change (follow_link)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  37)  *	Apr 1999	2.2.7		no more EBADF checking in
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  38)  *					  lookup/readdir, use ERR_PTR
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  39)  *	Jun 1999	2.3.6		d_alloc_root use changed
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  40)  *			2.3.9		clean up usage of ENOENT/negative
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  41)  *					  dentries in lookup
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  42)  *					clean up page flags setting
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  43)  *					  (error, uptodate, locking) in
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  44)  *					  in readpage
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  45)  *					use init_special_inode for
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  46)  *					  fifos/sockets (and streamline) in
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  47)  *					  read_inode, fix _ops table order
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  48)  *	Aug 1999	2.3.16		__initfunc() => __init change
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  49)  *	Oct 1999	2.3.24		page->owner hack obsoleted
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  50)  *	Nov 1999	2.3.27		2.3.25+ page->offset => index change
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  51)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  52)  *
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  53)  * This program is free software; you can redistribute it and/or
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  54)  * modify it under the terms of the GNU General Public Licence
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  55)  * as published by the Free Software Foundation; either version
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  56)  * 2 of the Licence, or (at your option) any later version.
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  57)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  58) 
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700  59) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700  60) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  61) #include <linux/module.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  62) #include <linux/string.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  63) #include <linux/fs.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  64) #include <linux/time.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  65) #include <linux/slab.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  66) #include <linux/init.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  67) #include <linux/blkdev.h>
b941759985841 (David Howells      2019-03-25 16:38:31 +0000  68) #include <linux/fs_context.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  69) #include <linux/mount.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  70) #include <linux/namei.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  71) #include <linux/statfs.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  72) #include <linux/mtd/super.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  73) #include <linux/ctype.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  74) #include <linux/highmem.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  75) #include <linux/pagemap.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  76) #include <linux/uaccess.h>
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800  77) #include <linux/major.h>
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  78) #include "internal.h"
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  79) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  80) static struct kmem_cache *romfs_inode_cachep;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  81) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  82) static const umode_t romfs_modemap[8] = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  83) 	0,			/* hard link */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  84) 	S_IFDIR  | 0644,	/* directory */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  85) 	S_IFREG  | 0644,	/* regular file */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  86) 	S_IFLNK  | 0777,	/* symlink */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  87) 	S_IFBLK  | 0600,	/* blockdev */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  88) 	S_IFCHR  | 0600,	/* chardev */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  89) 	S_IFSOCK | 0644,	/* socket */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  90) 	S_IFIFO  | 0644		/* FIFO */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  91) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  92) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  93) static const unsigned char romfs_dtype_table[] = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  94) 	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_SOCK, DT_FIFO
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  95) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  96) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  97) static struct inode *romfs_iget(struct super_block *sb, unsigned long pos);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  98) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000  99) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 100)  * read a page worth of data from the image
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 101)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 102) static int romfs_readpage(struct file *file, struct page *page)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 103) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 104) 	struct inode *inode = page->mapping->host;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 105) 	loff_t offset, size;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 106) 	unsigned long fillsize, pos;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 107) 	void *buf;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 108) 	int ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 109) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 110) 	buf = kmap(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 111) 	if (!buf)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 112) 		return -ENOMEM;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 113) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 114) 	/* 32 bit warning -- but not for us :) */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 115) 	offset = page_offset(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 116) 	size = i_size_read(inode);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 117) 	fillsize = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 118) 	ret = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 119) 	if (offset < size) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 120) 		size -= offset;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 121) 		fillsize = size > PAGE_SIZE ? PAGE_SIZE : size;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 122) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 123) 		pos = ROMFS_I(inode)->i_dataoffset + offset;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 124) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 125) 		ret = romfs_dev_read(inode->i_sb, pos, buf, fillsize);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 126) 		if (ret < 0) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 127) 			SetPageError(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 128) 			fillsize = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 129) 			ret = -EIO;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 130) 		}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 131) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 132) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 133) 	if (fillsize < PAGE_SIZE)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 134) 		memset(buf + fillsize, 0, PAGE_SIZE - fillsize);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 135) 	if (ret == 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 136) 		SetPageUptodate(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 137) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 138) 	flush_dcache_page(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 139) 	kunmap(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 140) 	unlock_page(page);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 141) 	return ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 142) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 143) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 144) static const struct address_space_operations romfs_aops = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 145) 	.readpage	= romfs_readpage
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 146) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 147) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 148) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 149)  * read the entries from a directory
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 150)  */
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 151) static int romfs_readdir(struct file *file, struct dir_context *ctx)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 152) {
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 153) 	struct inode *i = file_inode(file);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 154) 	struct romfs_inode ri;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 155) 	unsigned long offset, maxoff;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 156) 	int j, ino, nextfh;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 157) 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 158) 	int ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 159) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 160) 	maxoff = romfs_maxsize(i->i_sb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 161) 
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 162) 	offset = ctx->pos;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 163) 	if (!offset) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 164) 		offset = i->i_ino & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 165) 		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 166) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 167) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 168) 		offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 169) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 170) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 171) 	/* Not really failsafe, but we are read-only... */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 172) 	for (;;) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 173) 		if (!offset || offset >= maxoff) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 174) 			offset = maxoff;
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 175) 			ctx->pos = offset;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 176) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 177) 		}
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 178) 		ctx->pos = offset;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 179) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 180) 		/* Fetch inode info */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 181) 		ret = romfs_dev_read(i->i_sb, offset, &ri, ROMFH_SIZE);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 182) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 183) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 184) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 185) 		j = romfs_dev_strnlen(i->i_sb, offset + ROMFH_SIZE,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 186) 				      sizeof(fsname) - 1);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 187) 		if (j < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 188) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 189) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 190) 		ret = romfs_dev_read(i->i_sb, offset + ROMFH_SIZE, fsname, j);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 191) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 192) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 193) 		fsname[j] = '\0';
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 194) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 195) 		ino = offset;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 196) 		nextfh = be32_to_cpu(ri.next);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 197) 		if ((nextfh & ROMFH_TYPE) == ROMFH_HRD)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 198) 			ino = be32_to_cpu(ri.spec);
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 199) 		if (!dir_emit(ctx, fsname, j, ino,
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 200) 			    romfs_dtype_table[nextfh & ROMFH_TYPE]))
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 201) 			goto out;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 202) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 203) 		offset = nextfh & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 204) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 205) out:
3903b38ce77a9 (Al Viro            2013-05-16 01:22:00 -0400 206) 	return 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 207) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 208) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 209) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 210)  * look up an entry in a directory
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 211)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 212) static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3bf95f (Al Viro            2012-06-10 17:13:09 -0400 213) 				   unsigned int flags)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 214) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 215) 	unsigned long offset, maxoff;
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 216) 	struct inode *inode = NULL;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 217) 	struct romfs_inode ri;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 218) 	const char *name;		/* got from dentry */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 219) 	int len, ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 220) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 221) 	offset = dir->i_ino & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 222) 	ret = romfs_dev_read(dir->i_sb, offset, &ri, ROMFH_SIZE);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 223) 	if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 224) 		goto error;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 225) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 226) 	/* search all the file entries in the list starting from the one
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 227) 	 * pointed to by the directory's special data */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 228) 	maxoff = romfs_maxsize(dir->i_sb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 229) 	offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 230) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 231) 	name = dentry->d_name.name;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 232) 	len = dentry->d_name.len;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 233) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 234) 	for (;;) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 235) 		if (!offset || offset >= maxoff)
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 236) 			break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 237) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 238) 		ret = romfs_dev_read(dir->i_sb, offset, &ri, sizeof(ri));
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 239) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 240) 			goto error;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 241) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 242) 		/* try to match the first 16 bytes of name */
84baf74bf23bb (David Howells      2009-04-23 16:41:13 +0100 243) 		ret = romfs_dev_strcmp(dir->i_sb, offset + ROMFH_SIZE, name,
84baf74bf23bb (David Howells      2009-04-23 16:41:13 +0100 244) 				       len);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 245) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 246) 			goto error;
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 247) 		if (ret == 1) {
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 248) 			/* Hard link handling */
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 249) 			if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 250) 				offset = be32_to_cpu(ri.spec) & ROMFH_MASK;
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 251) 			inode = romfs_iget(dir->i_sb, offset);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 252) 			break;
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 253) 		}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 254) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 255) 		/* next entry */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 256) 		offset = be32_to_cpu(ri.next) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 257) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 258) 
8130c15176ae0 (Al Viro            2018-04-30 20:08:17 -0400 259) 	return d_splice_alias(inode, dentry);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 260) error:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 261) 	return ERR_PTR(ret);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 262) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 263) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 264) static const struct file_operations romfs_dir_operations = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 265) 	.read		= generic_read_dir,
d375570fa8376 (Al Viro            2016-04-30 23:08:45 -0400 266) 	.iterate_shared	= romfs_readdir,
d375570fa8376 (Al Viro            2016-04-30 23:08:45 -0400 267) 	.llseek		= generic_file_llseek,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 268) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 269) 
6e1d5dcc2bbbe (Alexey Dobriyan    2009-09-21 17:01:11 -0700 270) static const struct inode_operations romfs_dir_inode_operations = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 271) 	.lookup		= romfs_lookup,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 272) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 273) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 274) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 275)  * get a romfs inode based on its position in the image (which doubles as the
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 276)  * inode number)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 277)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 278) static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 279) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 280) 	struct romfs_inode_info *inode;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 281) 	struct romfs_inode ri;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 282) 	struct inode *i;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 283) 	unsigned long nlen;
774e33e70b2bf (Roel Kluin         2009-04-26 14:51:17 +0200 284) 	unsigned nextfh;
774e33e70b2bf (Roel Kluin         2009-04-26 14:51:17 +0200 285) 	int ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 286) 	umode_t mode;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 287) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 288) 	/* we might have to traverse a chain of "hard link" file entries to get
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 289) 	 * to the actual file */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 290) 	for (;;) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 291) 		ret = romfs_dev_read(sb, pos, &ri, sizeof(ri));
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 292) 		if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 293) 			goto error;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 294) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 295) 		/* XXX: do romfs_checksum here too (with name) */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 296) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 297) 		nextfh = be32_to_cpu(ri.next);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 298) 		if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 299) 			break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 300) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 301) 		pos = be32_to_cpu(ri.spec) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 302) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 303) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 304) 	/* determine the length of the filename */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 305) 	nlen = romfs_dev_strnlen(sb, pos + ROMFH_SIZE, ROMFS_MAXFN);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 306) 	if (IS_ERR_VALUE(nlen))
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 307) 		goto eio;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 308) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 309) 	/* get an inode for this image position */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 310) 	i = iget_locked(sb, pos);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 311) 	if (!i)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 312) 		return ERR_PTR(-ENOMEM);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 313) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 314) 	if (!(i->i_state & I_NEW))
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 315) 		return i;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 316) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 317) 	/* precalculate the data offset */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 318) 	inode = ROMFS_I(i);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 319) 	inode->i_metasize = (ROMFH_SIZE + nlen + 1 + ROMFH_PAD) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 320) 	inode->i_dataoffset = pos + inode->i_metasize;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 321) 
bfe8684869601 (Miklos Szeredi     2011-10-28 14:13:29 +0200 322) 	set_nlink(i, 1);		/* Hard to decide.. */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 323) 	i->i_size = be32_to_cpu(ri.size);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 324) 	i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 325) 	i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 326) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 327) 	/* set up mode and ops */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 328) 	mode = romfs_modemap[nextfh & ROMFH_TYPE];
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 329) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 330) 	switch (nextfh & ROMFH_TYPE) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 331) 	case ROMFH_DIR:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 332) 		i->i_size = ROMFS_I(i)->i_metasize;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 333) 		i->i_op = &romfs_dir_inode_operations;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 334) 		i->i_fop = &romfs_dir_operations;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 335) 		if (nextfh & ROMFH_EXEC)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 336) 			mode |= S_IXUGO;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 337) 		break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 338) 	case ROMFH_REG:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 339) 		i->i_fop = &romfs_ro_fops;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 340) 		i->i_data.a_ops = &romfs_aops;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 341) 		if (nextfh & ROMFH_EXEC)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 342) 			mode |= S_IXUGO;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 343) 		break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 344) 	case ROMFH_SYM:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 345) 		i->i_op = &page_symlink_inode_operations;
21fc61c73c390 (Al Viro            2015-11-17 01:07:57 -0500 346) 		inode_nohighmem(i);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 347) 		i->i_data.a_ops = &romfs_aops;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 348) 		mode |= S_IRWXUGO;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 349) 		break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 350) 	default:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 351) 		/* depending on MBZ for sock/fifos */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 352) 		nextfh = be32_to_cpu(ri.spec);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 353) 		init_special_inode(i, mode, MKDEV(nextfh >> 16,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 354) 						  nextfh & 0xffff));
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 355) 		break;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 356) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 357) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 358) 	i->i_mode = mode;
d9bc85de46cad (Libing Zhou        2020-10-15 20:13:42 -0700 359) 	i->i_blocks = (i->i_size + 511) >> 9;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 360) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 361) 	unlock_new_inode(i);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 362) 	return i;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 363) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 364) eio:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 365) 	ret = -EIO;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 366) error:
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 367) 	pr_err("read error for inode 0x%lx\n", pos);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 368) 	return ERR_PTR(ret);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 369) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 370) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 371) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 372)  * allocate a new inode
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 373)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 374) static struct inode *romfs_alloc_inode(struct super_block *sb)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 375) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 376) 	struct romfs_inode_info *inode;
b6d53b1b11349 (Fabian Frederick   2014-08-08 14:23:01 -0700 377) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 378) 	inode = kmem_cache_alloc(romfs_inode_cachep, GFP_KERNEL);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 379) 	return inode ? &inode->vfs_inode : NULL;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 380) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 381) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 382) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 383)  * return a spent inode to the slab cache
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 384)  */
bcb8d71bda471 (Al Viro            2019-04-15 22:21:45 -0400 385) static void romfs_free_inode(struct inode *inode)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 386) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 387) 	kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 388) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 389) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 390) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 391)  * get filesystem statistics
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 392)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 393) static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 394) {
8a59f5d252659 (Coly Li            2009-04-06 19:01:12 -0700 395) 	struct super_block *sb = dentry->d_sb;
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 396) 	u64 id = 0;
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 397) 
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 398) 	/* When calling huge_encode_dev(),
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 399) 	 * use sb->s_bdev->bd_dev when,
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 400) 	 *   - CONFIG_ROMFS_ON_BLOCK defined
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 401) 	 * use sb->s_dev when,
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 402) 	 *   - CONFIG_ROMFS_ON_BLOCK undefined and
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 403) 	 *   - CONFIG_ROMFS_ON_MTD defined
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 404) 	 * leave id as 0 when,
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 405) 	 *   - CONFIG_ROMFS_ON_BLOCK undefined and
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 406) 	 *   - CONFIG_ROMFS_ON_MTD undefined
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 407) 	 */
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 408) 	if (sb->s_bdev)
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 409) 		id = huge_encode_dev(sb->s_bdev->bd_dev);
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 410) 	else if (sb->s_dev)
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 411) 		id = huge_encode_dev(sb->s_dev);
8a59f5d252659 (Coly Li            2009-04-06 19:01:12 -0700 412) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 413) 	buf->f_type = ROMFS_MAGIC;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 414) 	buf->f_namelen = ROMFS_MAXFN;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 415) 	buf->f_bsize = ROMBSIZE;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 416) 	buf->f_bfree = buf->f_bavail = buf->f_ffree;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 417) 	buf->f_blocks =
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 418) 		(romfs_maxsize(dentry->d_sb) + ROMBSIZE - 1) >> ROMBSBITS;
6d1349c769ea2 (Al Viro            2020-09-18 16:45:50 -0400 419) 	buf->f_fsid = u64_to_fsid(id);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 420) 	return 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 421) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 422) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 423) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 424)  * remounting must involve read-only
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 425)  */
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 426) static int romfs_reconfigure(struct fs_context *fc)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 427) {
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 428) 	sync_filesystem(fc->root->d_sb);
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 429) 	fc->sb_flags |= SB_RDONLY;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 430) 	return 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 431) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 432) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 433) static const struct super_operations romfs_super_ops = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 434) 	.alloc_inode	= romfs_alloc_inode,
bcb8d71bda471 (Al Viro            2019-04-15 22:21:45 -0400 435) 	.free_inode	= romfs_free_inode,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 436) 	.statfs		= romfs_statfs,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 437) };
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 438) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 439) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 440)  * checksum check on part of a romfs filesystem
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 441)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 442) static __u32 romfs_checksum(const void *data, int size)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 443) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 444) 	const __be32 *ptr = data;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 445) 	__u32 sum;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 446) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 447) 	sum = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 448) 	size >>= 2;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 449) 	while (size > 0) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 450) 		sum += be32_to_cpu(*ptr++);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 451) 		size--;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 452) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 453) 	return sum;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 454) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 455) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 456) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 457)  * fill in the superblock
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 458)  */
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 459) static int romfs_fill_super(struct super_block *sb, struct fs_context *fc)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 460) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 461) 	struct romfs_super_block *rsb;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 462) 	struct inode *root;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 463) 	unsigned long pos, img_size;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 464) 	const char *storage;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 465) 	size_t len;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 466) 	int ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 467) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 468) #ifdef CONFIG_BLOCK
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 469) 	if (!sb->s_mtd) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 470) 		sb_set_blocksize(sb, ROMBSIZE);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 471) 	} else {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 472) 		sb->s_blocksize = ROMBSIZE;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 473) 		sb->s_blocksize_bits = blksize_bits(ROMBSIZE);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 474) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 475) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 476) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 477) 	sb->s_maxbytes = 0xFFFFFFFF;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 478) 	sb->s_magic = ROMFS_MAGIC;
1751e8a6cb935 (Linus Torvalds     2017-11-27 13:05:09 -0800 479) 	sb->s_flags |= SB_RDONLY | SB_NOATIME;
22b139691f9eb (Deepa Dinamani     2019-07-30 08:22:29 -0700 480) 	sb->s_time_min = 0;
22b139691f9eb (Deepa Dinamani     2019-07-30 08:22:29 -0700 481) 	sb->s_time_max = 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 482) 	sb->s_op = &romfs_super_ops;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 483) 
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 484) #ifdef CONFIG_ROMFS_ON_MTD
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 485) 	/* Use same dev ID from the underlying mtdblock device */
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 486) 	if (sb->s_mtd)
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 487) 		sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
f598f82e204ec (Coly Li            2017-01-24 15:18:46 -0800 488) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 489) 	/* read the image superblock and check it */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 490) 	rsb = kmalloc(512, GFP_KERNEL);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 491) 	if (!rsb)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 492) 		return -ENOMEM;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 493) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 494) 	sb->s_fs_info = (void *) 512;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 495) 	ret = romfs_dev_read(sb, 0, rsb, 512);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 496) 	if (ret < 0)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 497) 		goto error_rsb;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 498) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 499) 	img_size = be32_to_cpu(rsb->size);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 500) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 501) 	if (sb->s_mtd && img_size > sb->s_mtd->size)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 502) 		goto error_rsb_inval;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 503) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 504) 	sb->s_fs_info = (void *) img_size;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 505) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 506) 	if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 ||
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 507) 	    img_size < ROMFH_SIZE) {
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 508) 		if (!(fc->sb_flags & SB_SILENT))
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 509) 			errorf(fc, "VFS: Can't find a romfs filesystem on dev %s.\n",
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 510) 			       sb->s_id);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 511) 		goto error_rsb_inval;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 512) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 513) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 514) 	if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) {
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 515) 		pr_err("bad initial checksum on dev %s.\n", sb->s_id);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 516) 		goto error_rsb_inval;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 517) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 518) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 519) 	storage = sb->s_mtd ? "MTD" : "the block layer";
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 520) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 521) 	len = strnlen(rsb->name, ROMFS_MAXFN);
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 522) 	if (!(fc->sb_flags & SB_SILENT))
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 523) 		pr_notice("Mounting image '%*.*s' through %s\n",
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 524) 			  (unsigned) len, (unsigned) len, rsb->name, storage);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 525) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 526) 	kfree(rsb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 527) 	rsb = NULL;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 528) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 529) 	/* find the root directory */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 530) 	pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 531) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 532) 	root = romfs_iget(sb, pos);
a21f3c2a04d8a (Julia Lawall       2009-09-23 15:57:35 -0700 533) 	if (IS_ERR(root))
40e2c71d57565 (Rui Xiang          2014-01-23 15:56:19 -0800 534) 		return PTR_ERR(root);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 535) 
48fde701aff66 (Al Viro            2012-01-08 22:15:13 -0500 536) 	sb->s_root = d_make_root(root);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 537) 	if (!sb->s_root)
40e2c71d57565 (Rui Xiang          2014-01-23 15:56:19 -0800 538) 		return -ENOMEM;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 539) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 540) 	return 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 541) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 542) error_rsb_inval:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 543) 	ret = -EINVAL;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 544) error_rsb:
7e32b7bb73404 (Al Viro            2010-01-25 06:05:54 -0500 545) 	kfree(rsb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 546) 	return ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 547) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 548) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 549) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 550)  * get a superblock for mounting
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 551)  */
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 552) static int romfs_get_tree(struct fs_context *fc)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 553) {
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 554) 	int ret = -EINVAL;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 555) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 556) #ifdef CONFIG_ROMFS_ON_MTD
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 557) 	ret = get_tree_mtd(fc, romfs_fill_super);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 558) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 559) #ifdef CONFIG_ROMFS_ON_BLOCK
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 560) 	if (ret == -EINVAL)
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 561) 		ret = get_tree_bdev(fc, romfs_fill_super);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 562) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 563) 	return ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 564) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 565) 
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 566) static const struct fs_context_operations romfs_context_ops = {
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 567) 	.get_tree	= romfs_get_tree,
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 568) 	.reconfigure	= romfs_reconfigure,
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 569) };
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 570) 
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 571) /*
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 572)  * Set up the filesystem mount context.
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 573)  */
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 574) static int romfs_init_fs_context(struct fs_context *fc)
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 575) {
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 576) 	fc->ops = &romfs_context_ops;
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 577) 	return 0;
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 578) }
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 579) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 580) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 581)  * destroy a romfs superblock in the appropriate manner
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 582)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 583) static void romfs_kill_sb(struct super_block *sb)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 584) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 585) #ifdef CONFIG_ROMFS_ON_MTD
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 586) 	if (sb->s_mtd) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 587) 		kill_mtd_super(sb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 588) 		return;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 589) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 590) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 591) #ifdef CONFIG_ROMFS_ON_BLOCK
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 592) 	if (sb->s_bdev) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 593) 		kill_block_super(sb);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 594) 		return;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 595) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 596) #endif
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 597) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 598) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 599) static struct file_system_type romfs_fs_type = {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 600) 	.owner		= THIS_MODULE,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 601) 	.name		= "romfs",
b941759985841 (David Howells      2019-03-25 16:38:31 +0000 602) 	.init_fs_context = romfs_init_fs_context,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 603) 	.kill_sb	= romfs_kill_sb,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 604) 	.fs_flags	= FS_REQUIRES_DEV,
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 605) };
7f78e03513940 (Eric W. Biederman  2013-03-02 19:39:14 -0800 606) MODULE_ALIAS_FS("romfs");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 607) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 608) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 609)  * inode storage initialiser
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 610)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 611) static void romfs_i_init_once(void *_inode)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 612) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 613) 	struct romfs_inode_info *inode = _inode;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 614) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 615) 	inode_init_once(&inode->vfs_inode);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 616) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 617) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 618) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 619)  * romfs module initialisation
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 620)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 621) static int __init init_romfs_fs(void)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 622) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 623) 	int ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 624) 
3d79d3145f9c0 (Fabian Frederick   2014-08-08 14:22:57 -0700 625) 	pr_info("ROMFS MTD (C) 2007 Red Hat, Inc.\n");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 626) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 627) 	romfs_inode_cachep =
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 628) 		kmem_cache_create("romfs_i",
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 629) 				  sizeof(struct romfs_inode_info), 0,
5d097056c9a01 (Vladimir Davydov   2016-01-14 15:18:21 -0800 630) 				  SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
5d097056c9a01 (Vladimir Davydov   2016-01-14 15:18:21 -0800 631) 				  SLAB_ACCOUNT, romfs_i_init_once);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 632) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 633) 	if (!romfs_inode_cachep) {
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 634) 		pr_err("Failed to initialise inode cache\n");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 635) 		return -ENOMEM;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 636) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 637) 	ret = register_filesystem(&romfs_fs_type);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 638) 	if (ret) {
ca9e5368a7d99 (Fabian Frederick   2014-08-08 14:22:59 -0700 639) 		pr_err("Failed to register filesystem\n");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 640) 		goto error_register;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 641) 	}
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 642) 	return 0;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 643) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 644) error_register:
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 645) 	kmem_cache_destroy(romfs_inode_cachep);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 646) 	return ret;
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 647) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 648) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 649) /*
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 650)  * romfs module removal
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 651)  */
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 652) static void __exit exit_romfs_fs(void)
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 653) {
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 654) 	unregister_filesystem(&romfs_fs_type);
8c0a85377048b (Kirill A. Shutemov 2012-09-26 11:33:07 +1000 655) 	/*
8c0a85377048b (Kirill A. Shutemov 2012-09-26 11:33:07 +1000 656) 	 * Make sure all delayed rcu free inodes are flushed before we
8c0a85377048b (Kirill A. Shutemov 2012-09-26 11:33:07 +1000 657) 	 * destroy cache.
8c0a85377048b (Kirill A. Shutemov 2012-09-26 11:33:07 +1000 658) 	 */
8c0a85377048b (Kirill A. Shutemov 2012-09-26 11:33:07 +1000 659) 	rcu_barrier();
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 660) 	kmem_cache_destroy(romfs_inode_cachep);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 661) }
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 662) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 663) module_init(init_romfs_fs);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 664) module_exit(exit_romfs_fs);
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 665) 
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 666) MODULE_DESCRIPTION("Direct-MTD Capable RomFS");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 667) MODULE_AUTHOR("Red Hat, Inc.");
da4458bda237a (David Howells      2009-02-12 10:40:10 +0000 668) MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */