VisionFive2 Linux kernel

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

More than 9999 Commits   32 Branches   54 Tags
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    1) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    2)  * Compressed rom filesystem for Linux.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    3)  *
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    4)  * Copyright (C) 1999 Linus Torvalds.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    5)  *
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    6)  * This file is released under the GPL.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    7)  */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    8) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700    9) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   10)  * These are the VFS interfaces to the compressed rom filesystem.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   11)  * The actual compression is based on zlib, see the other files.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   12)  */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   13) 
4f21e1ea09e1e (Fabian Frederick   2014-08-08 14:22:50 -0700   14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4f21e1ea09e1e (Fabian Frederick   2014-08-08 14:22:50 -0700   15) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   16) #include <linux/module.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   17) #include <linux/fs.h>
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400   18) #include <linux/file.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   19) #include <linux/pagemap.h>
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400   20) #include <linux/pfn_t.h>
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400   21) #include <linux/ramfs.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   22) #include <linux/init.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   23) #include <linux/string.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   24) #include <linux/blkdev.h>
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400   25) #include <linux/mtd/mtd.h>
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400   26) #include <linux/mtd/super.h>
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000   27) #include <linux/fs_context.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   28) #include <linux/slab.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   29) #include <linux/vfs.h>
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800   30) #include <linux/mutex.h>
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   31) #include <uapi/linux/cramfs_fs.h>
1508f3eb69708 (Fabian Frederick   2014-08-08 14:22:55 -0700   32) #include <linux/uaccess.h>
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   33) 
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   34) #include "internal.h"
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   35) 
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   36) /*
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   37)  * cramfs super-block data in memory
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   38)  */
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   39) struct cramfs_sb_info {
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   40) 	unsigned long magic;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   41) 	unsigned long size;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   42) 	unsigned long blocks;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   43) 	unsigned long files;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   44) 	unsigned long flags;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400   45) 	void *linear_virt_addr;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400   46) 	resource_size_t linear_phys_addr;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400   47) 	size_t mtd_point_size;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   48) };
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   49) 
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   50) static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb)
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   51) {
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   52) 	return sb->s_fs_info;
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   53) }
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500   54) 
ee9b6d61a2a43 (Josef 'Jeff' Sipek 2007-02-12 00:55:41 -0800   55) static const struct super_operations cramfs_ops;
754661f143e70 (Arjan van de Ven   2007-02-12 00:55:38 -0800   56) static const struct inode_operations cramfs_dir_inode_operations;
4b6f5d20b04dc (Arjan van de Ven   2006-03-28 01:56:42 -0800   57) static const struct file_operations cramfs_directory_operations;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400   58) static const struct file_operations cramfs_physmem_fops;
f5e54d6e53a20 (Christoph Hellwig  2006-06-28 04:26:44 -0700   59) static const struct address_space_operations cramfs_aops;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   60) 
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800   61) static DEFINE_MUTEX(read_mutex);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   62) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   63) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   64) /* These macros may change in future, to provide better st_ino semantics. */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   65) #define OFFSET(x)	((x)->i_ino)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700   66) 
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400   67) static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset)
a97c9bf33f461 (Dave Johnson       2005-09-06 15:17:40 -0700   68) {
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   69) 	if (!cino->offset)
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   70) 		return offset + 1;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   71) 	if (!cino->size)
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   72) 		return offset + 1;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   73) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   74) 	/*
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   75) 	 * The file mode test fixes buggy mkcramfs implementations where
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   76) 	 * cramfs_inode->offset is set to a non zero value for entries
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   77) 	 * which did not contain data, like devices node and fifos.
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   78) 	 */
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   79) 	switch (cino->mode & S_IFMT) {
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   80) 	case S_IFREG:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   81) 	case S_IFDIR:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   82) 	case S_IFLNK:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   83) 		return cino->offset << 2;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   84) 	default:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   85) 		break;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   86) 	}
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   87) 	return offset + 1;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   88) }
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   89) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   90) static struct inode *get_cramfs_inode(struct super_block *sb,
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400   91) 	const struct cramfs_inode *cramfs_inode, unsigned int offset)
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   92) {
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   93) 	struct inode *inode;
95582b0083883 (Deepa Dinamani     2018-05-08 19:36:02 -0700   94) 	static struct timespec64 zerotime;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   95) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   96) 	inode = iget_locked(sb, cramino(cramfs_inode, offset));
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   97) 	if (!inode)
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   98) 		return ERR_PTR(-ENOMEM);
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800   99) 	if (!(inode->i_state & I_NEW))
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  100) 		return inode;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  101) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  102) 	switch (cramfs_inode->mode & S_IFMT) {
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  103) 	case S_IFREG:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  104) 		inode->i_fop = &generic_ro_fops;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  105) 		inode->i_data.a_ops = &cramfs_aops;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  106) 		if (IS_ENABLED(CONFIG_CRAMFS_MTD) &&
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  107) 		    CRAMFS_SB(sb)->flags & CRAMFS_FLAG_EXT_BLOCK_POINTERS &&
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  108) 		    CRAMFS_SB(sb)->linear_phys_addr)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  109) 			inode->i_fop = &cramfs_physmem_fops;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  110) 		break;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  111) 	case S_IFDIR:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  112) 		inode->i_op = &cramfs_dir_inode_operations;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  113) 		inode->i_fop = &cramfs_directory_operations;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  114) 		break;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  115) 	case S_IFLNK:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  116) 		inode->i_op = &page_symlink_inode_operations;
21fc61c73c390 (Al Viro            2015-11-17 01:07:57 -0500  117) 		inode_nohighmem(inode);
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  118) 		inode->i_data.a_ops = &cramfs_aops;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  119) 		break;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  120) 	default:
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  121) 		init_special_inode(inode, cramfs_inode->mode,
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  122) 				old_decode_dev(cramfs_inode->size));
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  123) 	}
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  124) 
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  125) 	inode->i_mode = cramfs_inode->mode;
a7d9cfe97b450 (Eric W. Biederman  2012-02-10 11:06:08 -0800  126) 	i_uid_write(inode, cramfs_inode->uid);
a7d9cfe97b450 (Eric W. Biederman  2012-02-10 11:06:08 -0800  127) 	i_gid_write(inode, cramfs_inode->gid);
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  128) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  129) 	/* if the lower 2 bits are zero, the inode contains data */
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  130) 	if (!(inode->i_ino & 3)) {
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  131) 		inode->i_size = cramfs_inode->size;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  132) 		inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  133) 	}
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  134) 
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  135) 	/* Struct copy intentional */
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  136) 	inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  137) 	/* inode->i_nlink is left 1 - arguably wrong for directories,
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  138) 	   but it's the best we can do without reading the directory
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  139) 	   contents.  1 yields the right result in GNU find, even
77b8a75f5bb46 (Al Viro            2010-06-04 21:19:01 -0400  140) 	   without -noleaf option. */
a97c9bf33f461 (Dave Johnson       2005-09-06 15:17:40 -0700  141) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  142) 	unlock_new_inode(inode);
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  143) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  144) 	return inode;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  145) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  146) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  147) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  148)  * We have our own block cache: don't fill up the buffer cache
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  149)  * with the rom-image, because the way the filesystem is set
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  150)  * up the accesses should be fairly regular and cached in the
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  151)  * page cache and dentry tree anyway..
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  152)  *
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  153)  * This also acts as a way to guarantee contiguous areas of up to
ea1754a084760 (Kirill A. Shutemov 2016-04-01 15:29:48 +0300  154)  * BLKS_PER_BUF*PAGE_SIZE, so that the caller doesn't need to
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  155)  * worry about end-of-buffer issues even when decompressing a full
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  156)  * page cache.
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  157)  *
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  158)  * Note: This is all optimized away at compile time when
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  159)  *       CONFIG_CRAMFS_BLOCKDEV=n.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  160)  */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  161) #define READ_BUFFERS (2)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  162) /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  163) #define NEXT_BUFFER(_ix) ((_ix) ^ 1)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  164) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  165) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  166)  * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  167)  * data that takes up more space than the original and with unlucky
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  168)  * alignment.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  169)  */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  170) #define BLKS_PER_BUF_SHIFT	(2)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  171) #define BLKS_PER_BUF		(1 << BLKS_PER_BUF_SHIFT)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  172) #define BUFFER_SIZE		(BLKS_PER_BUF*PAGE_SIZE)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  173) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  174) static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  175) static unsigned buffer_blocknr[READ_BUFFERS];
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  176) static struct super_block *buffer_dev[READ_BUFFERS];
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  177) static int next_buffer;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  178) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  179) /*
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  180)  * Populate our block cache and return a pointer to it.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  181)  */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  182) static void *cramfs_blkdev_read(struct super_block *sb, unsigned int offset,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  183) 				unsigned int len)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  184) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  185) 	struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  186) 	struct page *pages[BLKS_PER_BUF];
6bbfb0776615b (Andi Drebes        2007-10-18 03:06:54 -0700  187) 	unsigned i, blocknr, buffer;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  188) 	unsigned long devsize;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  189) 	char *data;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  190) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  191) 	if (!len)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  192) 		return NULL;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  193) 	blocknr = offset >> PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  194) 	offset &= PAGE_SIZE - 1;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  195) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  196) 	/* Check if an existing buffer already has the data.. */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  197) 	for (i = 0; i < READ_BUFFERS; i++) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  198) 		unsigned int blk_offset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  199) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  200) 		if (buffer_dev[i] != sb)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  201) 			continue;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  202) 		if (blocknr < buffer_blocknr[i])
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  203) 			continue;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  204) 		blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  205) 		blk_offset += offset;
672ca9dd13f1a (Nicolas Pitre      2018-10-30 13:26:15 -0400  206) 		if (blk_offset > BUFFER_SIZE ||
672ca9dd13f1a (Nicolas Pitre      2018-10-30 13:26:15 -0400  207) 		    blk_offset + len > BUFFER_SIZE)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  208) 			continue;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  209) 		return read_buffers[i] + blk_offset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  210) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  211) 
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  212) 	devsize = mapping->host->i_size >> PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  213) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  214) 	/* Ok, read in BLKS_PER_BUF pages completely first. */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  215) 	for (i = 0; i < BLKS_PER_BUF; i++) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  216) 		struct page *page = NULL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  217) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  218) 		if (blocknr + i < devsize) {
67f9fd91f93c5 (Sasha Levin        2014-04-03 14:48:18 -0700  219) 			page = read_mapping_page(mapping, blocknr + i, NULL);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  220) 			/* synchronous error? */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  221) 			if (IS_ERR(page))
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  222) 				page = NULL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  223) 		}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  224) 		pages[i] = page;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  225) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  226) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  227) 	for (i = 0; i < BLKS_PER_BUF; i++) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  228) 		struct page *page = pages[i];
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  229) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  230) 		if (page) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  231) 			wait_on_page_locked(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  232) 			if (!PageUptodate(page)) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  233) 				/* asynchronous error */
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  234) 				put_page(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  235) 				pages[i] = NULL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  236) 			}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  237) 		}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  238) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  239) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  240) 	buffer = next_buffer;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  241) 	next_buffer = NEXT_BUFFER(buffer);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  242) 	buffer_blocknr[buffer] = blocknr;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  243) 	buffer_dev[buffer] = sb;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  244) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  245) 	data = read_buffers[buffer];
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  246) 	for (i = 0; i < BLKS_PER_BUF; i++) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  247) 		struct page *page = pages[i];
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  248) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  249) 		if (page) {
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  250) 			memcpy(data, kmap(page), PAGE_SIZE);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  251) 			kunmap(page);
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  252) 			put_page(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  253) 		} else
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  254) 			memset(data, 0, PAGE_SIZE);
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  255) 		data += PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  256) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  257) 	return read_buffers[buffer] + offset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  258) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  259) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  260) /*
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  261)  * Return a pointer to the linearly addressed cramfs image in memory.
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  262)  */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  263) static void *cramfs_direct_read(struct super_block *sb, unsigned int offset,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  264) 				unsigned int len)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  265) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  266) 	struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  267) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  268) 	if (!len)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  269) 		return NULL;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  270) 	if (len > sbi->size || offset > sbi->size - len)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  271) 		return page_address(ZERO_PAGE(0));
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  272) 	return sbi->linear_virt_addr + offset;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  273) }
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  274) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  275) /*
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  276)  * Returns a pointer to a buffer containing at least LEN bytes of
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  277)  * filesystem starting at byte offset OFFSET into the filesystem.
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  278)  */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  279) static void *cramfs_read(struct super_block *sb, unsigned int offset,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  280) 			 unsigned int len)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  281) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  282) 	struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  283) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  284) 	if (IS_ENABLED(CONFIG_CRAMFS_MTD) && sbi->linear_virt_addr)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  285) 		return cramfs_direct_read(sb, offset, len);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  286) 	else if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV))
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  287) 		return cramfs_blkdev_read(sb, offset, len);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  288) 	else
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  289) 		return NULL;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  290) }
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  291) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  292) /*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  293)  * For a mapping to be possible, we need a range of uncompressed and
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  294)  * contiguous blocks. Return the offset for the first block and number of
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  295)  * valid blocks for which that is true, or zero otherwise.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  296)  */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  297) static u32 cramfs_get_block_range(struct inode *inode, u32 pgoff, u32 *pages)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  298) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  299) 	struct cramfs_sb_info *sbi = CRAMFS_SB(inode->i_sb);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  300) 	int i;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  301) 	u32 *blockptrs, first_block_addr;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  302) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  303) 	/*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  304) 	 * We can dereference memory directly here as this code may be
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  305) 	 * reached only when there is a direct filesystem image mapping
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  306) 	 * available in memory.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  307) 	 */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  308) 	blockptrs = (u32 *)(sbi->linear_virt_addr + OFFSET(inode) + pgoff * 4);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  309) 	first_block_addr = blockptrs[0] & ~CRAMFS_BLK_FLAGS;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  310) 	i = 0;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  311) 	do {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  312) 		u32 block_off = i * (PAGE_SIZE >> CRAMFS_BLK_DIRECT_PTR_SHIFT);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  313) 		u32 expect = (first_block_addr + block_off) |
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  314) 			     CRAMFS_BLK_FLAG_DIRECT_PTR |
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  315) 			     CRAMFS_BLK_FLAG_UNCOMPRESSED;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  316) 		if (blockptrs[i] != expect) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  317) 			pr_debug("range: block %d/%d got %#x expects %#x\n",
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  318) 				 pgoff+i, pgoff + *pages - 1,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  319) 				 blockptrs[i], expect);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  320) 			if (i == 0)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  321) 				return 0;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  322) 			break;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  323) 		}
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  324) 	} while (++i < *pages);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  325) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  326) 	*pages = i;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  327) 	return first_block_addr << CRAMFS_BLK_DIRECT_PTR_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  328) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  329) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  330) #ifdef CONFIG_MMU
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  331) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  332) /*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  333)  * Return true if the last page of a file in the filesystem image contains
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  334)  * some other data that doesn't belong to that file. It is assumed that the
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  335)  * last block is CRAMFS_BLK_FLAG_DIRECT_PTR | CRAMFS_BLK_FLAG_UNCOMPRESSED
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  336)  * (verified by cramfs_get_block_range() and directly accessible in memory.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  337)  */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  338) static bool cramfs_last_page_is_shared(struct inode *inode)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  339) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  340) 	struct cramfs_sb_info *sbi = CRAMFS_SB(inode->i_sb);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  341) 	u32 partial, last_page, blockaddr, *blockptrs;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  342) 	char *tail_data;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  343) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  344) 	partial = offset_in_page(inode->i_size);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  345) 	if (!partial)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  346) 		return false;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  347) 	last_page = inode->i_size >> PAGE_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  348) 	blockptrs = (u32 *)(sbi->linear_virt_addr + OFFSET(inode));
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  349) 	blockaddr = blockptrs[last_page] & ~CRAMFS_BLK_FLAGS;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  350) 	blockaddr <<= CRAMFS_BLK_DIRECT_PTR_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  351) 	tail_data = sbi->linear_virt_addr + blockaddr + partial;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  352) 	return memchr_inv(tail_data, 0, PAGE_SIZE - partial) ? true : false;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  353) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  354) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  355) static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  356) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  357) 	struct inode *inode = file_inode(file);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  358) 	struct cramfs_sb_info *sbi = CRAMFS_SB(inode->i_sb);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  359) 	unsigned int pages, max_pages, offset;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  360) 	unsigned long address, pgoff = vma->vm_pgoff;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  361) 	char *bailout_reason;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  362) 	int ret;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  363) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  364) 	ret = generic_file_readonly_mmap(file, vma);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  365) 	if (ret)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  366) 		return ret;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  367) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  368) 	/*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  369) 	 * Now try to pre-populate ptes for this vma with a direct
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  370) 	 * mapping avoiding memory allocation when possible.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  371) 	 */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  372) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  373) 	/* Could COW work here? */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  374) 	bailout_reason = "vma is writable";
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  375) 	if (vma->vm_flags & VM_WRITE)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  376) 		goto bailout;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  377) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  378) 	max_pages = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  379) 	bailout_reason = "beyond file limit";
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  380) 	if (pgoff >= max_pages)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  381) 		goto bailout;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  382) 	pages = min(vma_pages(vma), max_pages - pgoff);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  383) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  384) 	offset = cramfs_get_block_range(inode, pgoff, &pages);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  385) 	bailout_reason = "unsuitable block layout";
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  386) 	if (!offset)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  387) 		goto bailout;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  388) 	address = sbi->linear_phys_addr + offset;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  389) 	bailout_reason = "data is not page aligned";
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  390) 	if (!PAGE_ALIGNED(address))
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  391) 		goto bailout;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  392) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  393) 	/* Don't map the last page if it contains some other data */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  394) 	if (pgoff + pages == max_pages && cramfs_last_page_is_shared(inode)) {
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  395) 		pr_debug("mmap: %pD: last page is shared\n", file);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  396) 		pages--;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  397) 	}
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  398) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  399) 	if (!pages) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  400) 		bailout_reason = "no suitable block remaining";
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  401) 		goto bailout;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  402) 	}
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  403) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  404) 	if (pages == vma_pages(vma)) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  405) 		/*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  406) 		 * The entire vma is mappable. remap_pfn_range() will
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  407) 		 * make it distinguishable from a non-direct mapping
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  408) 		 * in /proc/<pid>/maps by substituting the file offset
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  409) 		 * with the actual physical address.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  410) 		 */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  411) 		ret = remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  412) 				      pages * PAGE_SIZE, vma->vm_page_prot);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  413) 	} else {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  414) 		/*
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  415) 		 * Let's create a mixed map if we can't map it all.
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  416) 		 * The normal paging machinery will take care of the
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  417) 		 * unpopulated ptes via cramfs_readpage().
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  418) 		 */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  419) 		int i;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  420) 		vma->vm_flags |= VM_MIXEDMAP;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  421) 		for (i = 0; i < pages && !ret; i++) {
7f2764cfbd85a (Nicolas Pitre      2018-10-26 15:04:06 -0700  422) 			vm_fault_t vmf;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  423) 			unsigned long off = i * PAGE_SIZE;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  424) 			pfn_t pfn = phys_to_pfn_t(address + off, PFN_DEV);
7f2764cfbd85a (Nicolas Pitre      2018-10-26 15:04:06 -0700  425) 			vmf = vmf_insert_mixed(vma, vma->vm_start + off, pfn);
7f2764cfbd85a (Nicolas Pitre      2018-10-26 15:04:06 -0700  426) 			if (vmf & VM_FAULT_ERROR)
7f2764cfbd85a (Nicolas Pitre      2018-10-26 15:04:06 -0700  427) 				ret = vm_fault_to_errno(vmf, 0);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  428) 		}
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  429) 	}
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  430) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  431) 	if (!ret)
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  432) 		pr_debug("mapped %pD[%lu] at 0x%08lx (%u/%lu pages) "
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  433) 			 "to vma 0x%08lx, page_prot 0x%llx\n", file,
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  434) 			 pgoff, address, pages, vma_pages(vma), vma->vm_start,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  435) 			 (unsigned long long)pgprot_val(vma->vm_page_prot));
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  436) 	return ret;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  437) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  438) bailout:
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  439) 	pr_debug("%pD[%lu]: direct mmap impossible: %s\n",
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  440) 		 file, pgoff, bailout_reason);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  441) 	/* Didn't manage any direct map, but normal paging is still possible */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  442) 	return 0;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  443) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  444) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  445) #else /* CONFIG_MMU */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  446) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  447) static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  448) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  449) 	return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -ENOSYS;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  450) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  451) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  452) static unsigned long cramfs_physmem_get_unmapped_area(struct file *file,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  453) 			unsigned long addr, unsigned long len,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  454) 			unsigned long pgoff, unsigned long flags)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  455) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  456) 	struct inode *inode = file_inode(file);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  457) 	struct super_block *sb = inode->i_sb;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  458) 	struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  459) 	unsigned int pages, block_pages, max_pages, offset;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  460) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  461) 	pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  462) 	max_pages = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  463) 	if (pgoff >= max_pages || pages > max_pages - pgoff)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  464) 		return -EINVAL;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  465) 	block_pages = pages;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  466) 	offset = cramfs_get_block_range(inode, pgoff, &block_pages);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  467) 	if (!offset || block_pages != pages)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  468) 		return -ENOSYS;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  469) 	addr = sbi->linear_phys_addr + offset;
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  470) 	pr_debug("get_unmapped for %pD ofs %#lx siz %lu at 0x%08lx\n",
aa7d5c7e307a0 (Al Viro            2021-01-05 22:57:20 -0500  471) 		 file, pgoff*PAGE_SIZE, len, addr);
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  472) 	return addr;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  473) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  474) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  475) static unsigned int cramfs_physmem_mmap_capabilities(struct file *file)
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  476) {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  477) 	return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT |
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  478) 	       NOMMU_MAP_READ | NOMMU_MAP_EXEC;
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  479) }
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  480) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  481) #endif /* CONFIG_MMU */
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  482) 
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  483) static const struct file_operations cramfs_physmem_fops = {
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  484) 	.llseek			= generic_file_llseek,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  485) 	.read_iter		= generic_file_read_iter,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  486) 	.splice_read		= generic_file_splice_read,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  487) 	.mmap			= cramfs_physmem_mmap,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  488) #ifndef CONFIG_MMU
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  489) 	.get_unmapped_area	= cramfs_physmem_get_unmapped_area,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  490) 	.mmap_capabilities	= cramfs_physmem_mmap_capabilities,
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  491) #endif
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  492) };
eddcd97659e31 (Nicolas Pitre      2017-10-12 02:16:12 -0400  493) 
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  494) static void cramfs_kill_sb(struct super_block *sb)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  495) {
f7f4f4dd6948e (Al Viro            2013-12-10 16:54:28 -0500  496) 	struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  497) 
08a8f30868803 (Joe Perches        2018-05-13 15:05:47 -0700  498) 	if (IS_ENABLED(CONFIG_CRAMFS_MTD) && sb->s_mtd) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  499) 		if (sbi && sbi->mtd_point_size)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  500) 			mtd_unpoint(sb->s_mtd, 0, sbi->mtd_point_size);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  501) 		kill_mtd_super(sb);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  502) 	} else if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV) && sb->s_bdev) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  503) 		kill_block_super(sb);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  504) 	}
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  505) 	kfree(sbi);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  506) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  507) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  508) static int cramfs_reconfigure(struct fs_context *fc)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  509) {
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  510) 	sync_filesystem(fc->root->d_sb);
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  511) 	fc->sb_flags |= SB_RDONLY;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  512) 	return 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  513) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  514) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  515) static int cramfs_read_super(struct super_block *sb, struct fs_context *fc,
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  516) 			     struct cramfs_super *super)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  517) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  518) 	struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  519) 	unsigned long root_offset;
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  520) 	bool silent = fc->sb_flags & SB_SILENT;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  521) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  522) 	/* We don't know the real size yet */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  523) 	sbi->size = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  524) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  525) 	/* Read the first block and get the superblock from it */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  526) 	mutex_lock(&read_mutex);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  527) 	memcpy(super, cramfs_read(sb, 0, sizeof(*super)), sizeof(*super));
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  528) 	mutex_unlock(&read_mutex);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  529) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  530) 	/* Do sanity checks on the superblock */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  531) 	if (super->magic != CRAMFS_MAGIC) {
0cc785ecbf6c0 (Masanari Iida      2012-02-11 21:35:12 +0900  532) 		/* check for wrong endianness */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  533) 		if (super->magic == CRAMFS_MAGIC_WEND) {
ac8d35c565837 (Andi Drebes        2007-10-16 23:27:12 -0700  534) 			if (!silent)
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  535) 				errorfc(fc, "wrong endianness");
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  536) 			return -EINVAL;
ac8d35c565837 (Andi Drebes        2007-10-16 23:27:12 -0700  537) 		}
ac8d35c565837 (Andi Drebes        2007-10-16 23:27:12 -0700  538) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  539) 		/* check at 512 byte offset */
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  540) 		mutex_lock(&read_mutex);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  541) 		memcpy(super,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  542) 		       cramfs_read(sb, 512, sizeof(*super)),
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  543) 		       sizeof(*super));
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  544) 		mutex_unlock(&read_mutex);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  545) 		if (super->magic != CRAMFS_MAGIC) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  546) 			if (super->magic == CRAMFS_MAGIC_WEND && !silent)
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  547) 				errorfc(fc, "wrong endianness");
ac8d35c565837 (Andi Drebes        2007-10-16 23:27:12 -0700  548) 			else if (!silent)
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  549) 				errorfc(fc, "wrong magic");
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  550) 			return -EINVAL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  551) 		}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  552) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  553) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  554) 	/* get feature flags first */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  555) 	if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) {
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  556) 		errorfc(fc, "unsupported filesystem features");
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  557) 		return -EINVAL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  558) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  559) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  560) 	/* Check that the root inode is in a sane state */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  561) 	if (!S_ISDIR(super->root.mode)) {
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  562) 		errorfc(fc, "root is not a directory");
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  563) 		return -EINVAL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  564) 	}
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  565) 	/* correct strange, hard-coded permissions of mkcramfs */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  566) 	super->root.mode |= 0555;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  567) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  568) 	root_offset = super->root.offset << 2;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  569) 	if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  570) 		sbi->size = super->size;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  571) 		sbi->blocks = super->fsid.blocks;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  572) 		sbi->files = super->fsid.files;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  573) 	} else {
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  574) 		sbi->size = 1<<28;
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  575) 		sbi->blocks = 0;
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  576) 		sbi->files = 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  577) 	}
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  578) 	sbi->magic = super->magic;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  579) 	sbi->flags = super->flags;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  580) 	if (root_offset == 0)
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  581) 		infofc(fc, "empty filesystem");
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  582) 	else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  583) 		 ((root_offset != sizeof(struct cramfs_super)) &&
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  584) 		  (root_offset != 512 + sizeof(struct cramfs_super))))
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  585) 	{
e1ee7d8511f1b (Al Viro            2019-12-21 21:33:45 -0500  586) 		errorfc(fc, "bad root offset %lu", root_offset);
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  587) 		return -EINVAL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  588) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  589) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  590) 	return 0;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  591) }
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  592) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  593) static int cramfs_finalize_super(struct super_block *sb,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  594) 				 struct cramfs_inode *cramfs_root)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  595) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  596) 	struct inode *root;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  597) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  598) 	/* Set it all up.. */
1751e8a6cb935 (Linus Torvalds     2017-11-27 13:05:09 -0800  599) 	sb->s_flags |= SB_RDONLY;
22b139691f9eb (Deepa Dinamani     2019-07-30 08:22:29 -0700  600) 	sb->s_time_min = 0;
22b139691f9eb (Deepa Dinamani     2019-07-30 08:22:29 -0700  601) 	sb->s_time_max = 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  602) 	sb->s_op = &cramfs_ops;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  603) 	root = get_cramfs_inode(sb, cramfs_root, 0);
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  604) 	if (IS_ERR(root))
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  605) 		return PTR_ERR(root);
48fde701aff66 (Al Viro            2012-01-08 22:15:13 -0500  606) 	sb->s_root = d_make_root(root);
48fde701aff66 (Al Viro            2012-01-08 22:15:13 -0500  607) 	if (!sb->s_root)
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  608) 		return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  609) 	return 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  610) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  611) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  612) static int cramfs_blkdev_fill_super(struct super_block *sb, struct fs_context *fc)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  613) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  614) 	struct cramfs_sb_info *sbi;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  615) 	struct cramfs_super super;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  616) 	int i, err;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  617) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  618) 	sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  619) 	if (!sbi)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  620) 		return -ENOMEM;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  621) 	sb->s_fs_info = sbi;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  622) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  623) 	/* Invalidate the read buffers on mount: think disk change.. */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  624) 	for (i = 0; i < READ_BUFFERS; i++)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  625) 		buffer_blocknr[i] = -1;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  626) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  627) 	err = cramfs_read_super(sb, fc, &super);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  628) 	if (err)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  629) 		return err;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  630) 	return cramfs_finalize_super(sb, &super.root);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  631) }
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  632) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  633) static int cramfs_mtd_fill_super(struct super_block *sb, struct fs_context *fc)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  634) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  635) 	struct cramfs_sb_info *sbi;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  636) 	struct cramfs_super super;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  637) 	int err;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  638) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  639) 	sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  640) 	if (!sbi)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  641) 		return -ENOMEM;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  642) 	sb->s_fs_info = sbi;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  643) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  644) 	/* Map only one page for now.  Will remap it when fs size is known. */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  645) 	err = mtd_point(sb->s_mtd, 0, PAGE_SIZE, &sbi->mtd_point_size,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  646) 			&sbi->linear_virt_addr, &sbi->linear_phys_addr);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  647) 	if (err || sbi->mtd_point_size != PAGE_SIZE) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  648) 		pr_err("unable to get direct memory access to mtd:%s\n",
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  649) 		       sb->s_mtd->name);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  650) 		return err ? : -ENODATA;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  651) 	}
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  652) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  653) 	pr_info("checking physical address %pap for linear cramfs image\n",
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  654) 		&sbi->linear_phys_addr);
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  655) 	err = cramfs_read_super(sb, fc, &super);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  656) 	if (err)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  657) 		return err;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  658) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  659) 	/* Remap the whole filesystem now */
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  660) 	pr_info("linear cramfs image on mtd:%s appears to be %lu KB in size\n",
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  661) 		sb->s_mtd->name, sbi->size/1024);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  662) 	mtd_unpoint(sb->s_mtd, 0, PAGE_SIZE);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  663) 	err = mtd_point(sb->s_mtd, 0, sbi->size, &sbi->mtd_point_size,
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  664) 			&sbi->linear_virt_addr, &sbi->linear_phys_addr);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  665) 	if (err || sbi->mtd_point_size != sbi->size) {
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  666) 		pr_err("unable to get direct memory access to mtd:%s\n",
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  667) 		       sb->s_mtd->name);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  668) 		return err ? : -ENODATA;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  669) 	}
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  670) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  671) 	return cramfs_finalize_super(sb, &super.root);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  672) }
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  673) 
726c334223180 (David Howells      2006-06-23 02:02:58 -0700  674) static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  675) {
726c334223180 (David Howells      2006-06-23 02:02:58 -0700  676) 	struct super_block *sb = dentry->d_sb;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  677) 	u64 id = 0;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  678) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  679) 	if (sb->s_bdev)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  680) 		id = huge_encode_dev(sb->s_bdev->bd_dev);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  681) 	else if (sb->s_dev)
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  682) 		id = huge_encode_dev(sb->s_dev);
726c334223180 (David Howells      2006-06-23 02:02:58 -0700  683) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  684) 	buf->f_type = CRAMFS_MAGIC;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  685) 	buf->f_bsize = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  686) 	buf->f_blocks = CRAMFS_SB(sb)->blocks;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  687) 	buf->f_bfree = 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  688) 	buf->f_bavail = 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  689) 	buf->f_files = CRAMFS_SB(sb)->files;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  690) 	buf->f_ffree = 0;
6d1349c769ea2 (Al Viro            2020-09-18 16:45:50 -0400  691) 	buf->f_fsid = u64_to_fsid(id);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  692) 	buf->f_namelen = CRAMFS_MAXPATHLEN;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  693) 	return 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  694) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  695) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  696) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  697)  * Read a cramfs directory entry.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  698)  */
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  699) static int cramfs_readdir(struct file *file, struct dir_context *ctx)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  700) {
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  701) 	struct inode *inode = file_inode(file);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  702) 	struct super_block *sb = inode->i_sb;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  703) 	char *buf;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  704) 	unsigned int offset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  705) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  706) 	/* Offset within the thing. */
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  707) 	if (ctx->pos >= inode->i_size)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  708) 		return 0;
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  709) 	offset = ctx->pos;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  710) 	/* Directory entries are always 4-byte aligned */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  711) 	if (offset & 3)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  712) 		return -EINVAL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  713) 
4176ed593866b (Andi Drebes        2007-10-18 03:06:55 -0700  714) 	buf = kmalloc(CRAMFS_MAXPATHLEN, GFP_KERNEL);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  715) 	if (!buf)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  716) 		return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  717) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  718) 	while (offset < inode->i_size) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  719) 		struct cramfs_inode *de;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  720) 		unsigned long nextoffset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  721) 		char *name;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  722) 		ino_t ino;
175a4eb7ea531 (Al Viro            2011-07-26 03:30:54 -0400  723) 		umode_t mode;
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  724) 		int namelen;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  725) 
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  726) 		mutex_lock(&read_mutex);
4176ed593866b (Andi Drebes        2007-10-18 03:06:55 -0700  727) 		de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  728) 		name = (char *)(de+1);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  729) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  730) 		/*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  731) 		 * Namelengths on disk are shifted by two
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  732) 		 * and the name padded out to 4-byte boundaries
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  733) 		 * with zeroes.
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  734) 		 */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  735) 		namelen = de->namelen << 2;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  736) 		memcpy(buf, name, namelen);
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  737) 		ino = cramino(de, OFFSET(inode) + offset);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  738) 		mode = de->mode;
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  739) 		mutex_unlock(&read_mutex);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  740) 		nextoffset = offset + sizeof(*de) + namelen;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  741) 		for (;;) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  742) 			if (!namelen) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  743) 				kfree(buf);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  744) 				return -EIO;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  745) 			}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  746) 			if (buf[namelen-1])
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  747) 				break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  748) 			namelen--;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  749) 		}
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  750) 		if (!dir_emit(ctx, buf, namelen, ino, mode >> 12))
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  751) 			break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  752) 
6f7f231e7b4f8 (Al Viro            2013-05-17 18:02:17 -0400  753) 		ctx->pos = offset = nextoffset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  754) 	}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  755) 	kfree(buf);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  756) 	return 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  757) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  758) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  759) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  760)  * Lookup and fill in the inode data..
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  761)  */
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  762) static struct dentry *cramfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  763) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  764) 	unsigned int offset = 0;
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  765) 	struct inode *inode = NULL;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  766) 	int sorted;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  767) 
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  768) 	mutex_lock(&read_mutex);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  769) 	sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  770) 	while (offset < dir->i_size) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  771) 		struct cramfs_inode *de;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  772) 		char *name;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  773) 		int namelen, retval;
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  774) 		int dir_off = OFFSET(dir) + offset;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  775) 
6f772fe65c7aa (Stefani Seibold    2011-01-12 17:01:10 -0800  776) 		de = cramfs_read(dir->i_sb, dir_off, sizeof(*de)+CRAMFS_MAXPATHLEN);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  777) 		name = (char *)(de+1);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  778) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  779) 		/* Try to take advantage of sorted directories */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  780) 		if (sorted && (dentry->d_name.name[0] < name[0]))
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  781) 			break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  782) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  783) 		namelen = de->namelen << 2;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  784) 		offset += sizeof(*de) + namelen;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  785) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  786) 		/* Quick check that the name is roughly the right length */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  787) 		if (((dentry->d_name.len + 3) & ~3) != namelen)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  788) 			continue;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  789) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  790) 		for (;;) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  791) 			if (!namelen) {
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  792) 				inode = ERR_PTR(-EIO);
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  793) 				goto out;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  794) 			}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  795) 			if (name[namelen-1])
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  796) 				break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  797) 			namelen--;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  798) 		}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  799) 		if (namelen != dentry->d_name.len)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  800) 			continue;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  801) 		retval = memcmp(dentry->d_name.name, name, namelen);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  802) 		if (retval > 0)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  803) 			continue;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  804) 		if (!retval) {
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  805) 			inode = get_cramfs_inode(dir->i_sb, de, dir_off);
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  806) 			break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  807) 		}
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  808) 		/* else (retval < 0) */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  809) 		if (sorted)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  810) 			break;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  811) 	}
0577d1ba411f9 (Al Viro            2011-07-17 19:04:14 -0400  812) out:
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  813) 	mutex_unlock(&read_mutex);
d023b3a19fd5e (Al Viro            2018-04-30 19:18:26 -0400  814) 	return d_splice_alias(inode, dentry);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  815) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  816) 
31d92e55198d4 (Fabian Frederick   2014-08-08 14:22:52 -0700  817) static int cramfs_readpage(struct file *file, struct page *page)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  818) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  819) 	struct inode *inode = page->mapping->host;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  820) 	u32 maxblock;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  821) 	int bytes_filled;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  822) 	void *pgdata;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  823) 
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  824) 	maxblock = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  825) 	bytes_filled = 0;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  826) 	pgdata = kmap(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  827) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  828) 	if (page->index < maxblock) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  829) 		struct super_block *sb = inode->i_sb;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  830) 		u32 blkptr_offset = OFFSET(inode) + page->index * 4;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  831) 		u32 block_ptr, block_start, block_len;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  832) 		bool uncompressed, direct;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  833) 
353ab6e97b8f2 (Ingo Molnar        2006-03-26 01:37:12 -0800  834) 		mutex_lock(&read_mutex);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  835) 		block_ptr = *(u32 *) cramfs_read(sb, blkptr_offset, 4);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  836) 		uncompressed = (block_ptr & CRAMFS_BLK_FLAG_UNCOMPRESSED);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  837) 		direct = (block_ptr & CRAMFS_BLK_FLAG_DIRECT_PTR);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  838) 		block_ptr &= ~CRAMFS_BLK_FLAGS;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  839) 
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  840) 		if (direct) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  841) 			/*
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  842) 			 * The block pointer is an absolute start pointer,
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  843) 			 * shifted by 2 bits. The size is included in the
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  844) 			 * first 2 bytes of the data block when compressed,
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  845) 			 * or PAGE_SIZE otherwise.
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  846) 			 */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  847) 			block_start = block_ptr << CRAMFS_BLK_DIRECT_PTR_SHIFT;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  848) 			if (uncompressed) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  849) 				block_len = PAGE_SIZE;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  850) 				/* if last block: cap to file length */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  851) 				if (page->index == maxblock - 1)
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  852) 					block_len =
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  853) 						offset_in_page(inode->i_size);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  854) 			} else {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  855) 				block_len = *(u16 *)
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  856) 					cramfs_read(sb, block_start, 2);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  857) 				block_start += 2;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  858) 			}
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  859) 		} else {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  860) 			/*
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  861) 			 * The block pointer indicates one past the end of
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  862) 			 * the current block (start of next block). If this
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  863) 			 * is the first block then it starts where the block
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  864) 			 * pointer table ends, otherwise its start comes
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  865) 			 * from the previous block's pointer.
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  866) 			 */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  867) 			block_start = OFFSET(inode) + maxblock * 4;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  868) 			if (page->index)
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  869) 				block_start = *(u32 *)
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  870) 					cramfs_read(sb, blkptr_offset - 4, 4);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  871) 			/* Beware... previous ptr might be a direct ptr */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  872) 			if (unlikely(block_start & CRAMFS_BLK_FLAG_DIRECT_PTR)) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  873) 				/* See comments on earlier code. */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  874) 				u32 prev_start = block_start;
56ce68bceeefa (Nicolas Pitre      2018-10-30 14:22:58 -0400  875) 				block_start = prev_start & ~CRAMFS_BLK_FLAGS;
56ce68bceeefa (Nicolas Pitre      2018-10-30 14:22:58 -0400  876) 				block_start <<= CRAMFS_BLK_DIRECT_PTR_SHIFT;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  877) 				if (prev_start & CRAMFS_BLK_FLAG_UNCOMPRESSED) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  878) 					block_start += PAGE_SIZE;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  879) 				} else {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  880) 					block_len = *(u16 *)
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  881) 						cramfs_read(sb, block_start, 2);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  882) 					block_start += 2 + block_len;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  883) 				}
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  884) 			}
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  885) 			block_start &= ~CRAMFS_BLK_FLAGS;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  886) 			block_len = block_ptr - block_start;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  887) 		}
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  888) 
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  889) 		if (block_len == 0)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  890) 			; /* hole */
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  891) 		else if (unlikely(block_len > 2*PAGE_SIZE ||
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  892) 				  (uncompressed && block_len > PAGE_SIZE))) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  893) 			mutex_unlock(&read_mutex);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  894) 			pr_err("bad data blocksize %u\n", block_len);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  895) 			goto err;
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  896) 		} else if (uncompressed) {
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  897) 			memcpy(pgdata,
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  898) 			       cramfs_read(sb, block_start, block_len),
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  899) 			       block_len);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  900) 			bytes_filled = block_len;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  901) 		} else {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  902) 			bytes_filled = cramfs_uncompress_block(pgdata,
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  903) 				 PAGE_SIZE,
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  904) 				 cramfs_read(sb, block_start, block_len),
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  905) 				 block_len);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  906) 		}
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  907) 		mutex_unlock(&read_mutex);
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  908) 		if (unlikely(bytes_filled < 0))
fd4f6f2a78aea (Nicolas Pitre      2017-10-12 02:16:11 -0400  909) 			goto err;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  910) 	}
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  911) 
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300  912) 	memset(pgdata + bytes_filled, 0, PAGE_SIZE - bytes_filled);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  913) 	flush_dcache_page(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  914) 	kunmap(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  915) 	SetPageUptodate(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  916) 	unlock_page(page);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  917) 	return 0;
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  918) 
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  919) err:
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  920) 	kunmap(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  921) 	ClearPageUptodate(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  922) 	SetPageError(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  923) 	unlock_page(page);
98310e581e098 (David VomLehn      2009-04-02 16:59:15 -0700  924) 	return 0;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  925) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  926) 
f5e54d6e53a20 (Christoph Hellwig  2006-06-28 04:26:44 -0700  927) static const struct address_space_operations cramfs_aops = {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  928) 	.readpage = cramfs_readpage
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  929) };
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  930) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  931) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  932)  * Our operations:
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  933)  */
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  934) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  935) /*
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  936)  * A directory can only readdir
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  937)  */
4b6f5d20b04dc (Arjan van de Ven   2006-03-28 01:56:42 -0800  938) static const struct file_operations cramfs_directory_operations = {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  939) 	.llseek		= generic_file_llseek,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  940) 	.read		= generic_read_dir,
c51da20c48b76 (Al Viro            2016-04-30 22:37:34 -0400  941) 	.iterate_shared	= cramfs_readdir,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  942) };
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  943) 
754661f143e70 (Arjan van de Ven   2007-02-12 00:55:38 -0800  944) static const struct inode_operations cramfs_dir_inode_operations = {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  945) 	.lookup		= cramfs_lookup,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  946) };
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  947) 
ee9b6d61a2a43 (Josef 'Jeff' Sipek 2007-02-12 00:55:41 -0800  948) static const struct super_operations cramfs_ops = {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  949) 	.statfs		= cramfs_statfs,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  950) };
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  951) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  952) static int cramfs_get_tree(struct fs_context *fc)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  953) {
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  954) 	int ret = -ENOPROTOOPT;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  955) 
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  956) 	if (IS_ENABLED(CONFIG_CRAMFS_MTD)) {
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  957) 		ret = get_tree_mtd(fc, cramfs_mtd_fill_super);
3e5aeec0e267d (Maxime Bizon       2019-10-19 15:24:11 -0400  958) 		if (!ret)
3e5aeec0e267d (Maxime Bizon       2019-10-19 15:24:11 -0400  959) 			return 0;
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  960) 	}
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  961) 	if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV))
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  962) 		ret = get_tree_bdev(fc, cramfs_blkdev_fill_super);
99c18ce580c6c (Nicolas Pitre      2017-10-13 16:09:23 -0400  963) 	return ret;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  964) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  965) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  966) static const struct fs_context_operations cramfs_context_ops = {
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  967) 	.get_tree	= cramfs_get_tree,
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  968) 	.reconfigure	= cramfs_reconfigure,
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  969) };
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  970) 
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  971) /*
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  972)  * Set up the filesystem mount context.
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  973)  */
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  974) static int cramfs_init_fs_context(struct fs_context *fc)
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  975) {
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  976) 	fc->ops = &cramfs_context_ops;
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  977) 	return 0;
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  978) }
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  979) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  980) static struct file_system_type cramfs_fs_type = {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  981) 	.owner		= THIS_MODULE,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  982) 	.name		= "cramfs",
74f78fc5ef43d (David Howells      2019-03-25 16:38:32 +0000  983) 	.init_fs_context = cramfs_init_fs_context,
2309fb8ef40e8 (Al Viro            2013-12-10 16:35:14 -0500  984) 	.kill_sb	= cramfs_kill_sb,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  985) 	.fs_flags	= FS_REQUIRES_DEV,
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  986) };
7f78e03513940 (Eric W. Biederman  2013-03-02 19:39:14 -0800  987) MODULE_ALIAS_FS("cramfs");
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  988) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  989) static int __init init_cramfs_fs(void)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700  990) {
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  991) 	int rv;
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  992) 
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  993) 	rv = cramfs_uncompress_init();
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  994) 	if (rv < 0)
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  995) 		return rv;
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  996) 	rv = register_filesystem(&cramfs_fs_type);
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  997) 	if (rv < 0)
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  998) 		cramfs_uncompress_exit();
50d44ed009a62 (Alexey Dobriyan    2006-09-29 02:01:04 -0700  999) 	return rv;
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1000) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1001) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1002) static void __exit exit_cramfs_fs(void)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1003) {
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1004) 	cramfs_uncompress_exit();
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1005) 	unregister_filesystem(&cramfs_fs_type);
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1006) }
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1007) 
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1008) module_init(init_cramfs_fs)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1009) module_exit(exit_cramfs_fs)
^1da177e4c3f4 (Linus Torvalds     2005-04-16 15:20:36 -0700 1010) MODULE_LICENSE("GPL");