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 */