^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");