From patchwork Fri Aug 11 19:22:48 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 109926 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp1341262qge; Fri, 11 Aug 2017 12:32:27 -0700 (PDT) X-Received: by 10.99.45.194 with SMTP id t185mr16193210pgt.295.1502479947773; Fri, 11 Aug 2017 12:32:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502479947; cv=none; d=google.com; s=arc-20160816; b=mgIYWNawF8iwfP3os7HXYDzQGyTYPr0iCAGH3fVB+SR9gqxcauy/RddhamK7avaQtf yiOde0ySFJg3F7RMVJQ80fsiLPRqeHuiiglEJ4MKGKf5MQcfLY6QEENnSzV6WHokLwBE iXx4lXZDglgCL3+Xgb1MAkTIyPHlH7E65LtPIFDX7wBiWPfhUNiBXWVG9UyCMzxO0HYw fi+R1s3cEkjMGHwjLY9AeA3aK4RouDz97f0sd/9q9uS5tdreyjPtrMKVvnmgfSvEOsB1 VPuOgP6FvFioY3pqvAgcwtS6mPt8ZAvVaQ+PK7jY7ZjECSgek833H35ovQ1sMyJiC0uK bAyg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=+ytsbJyNMBmPANMdL20HzbIBx8+/ah2AO81w1mBzsSo=; b=wNVsuU331fyAXRr0OrSDwDRXTnTMm+J62x+jnav/tJApphA5ILtpYM1dsuROJx3UZi Tw8UJ6TLN5rlaASSsQjb0meq1JkvHPSgsX2wA+XBsSx8szd+QM4jcxgu1qfzergSxYFj 6UcIDqrLzQeQeKp3yDjXuPOeWRWMdr19mSKns3+bbRCvYG71/DBYoQTNiD8EIj5+1w8F JoqdYntHfm+LKCSK4FrreRgYXi0ovUdPYhHIP6o6Tj0SkOV9GcdgcQ6oGkDCTqYinVM3 TvJbt9oVYRY/xxB9ZdF1Zdm8oC+4CXD4EYYDE//hRdz8Y22H8Gq91udnfp91lExkDTox u4Sg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=qbnAPOMj; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m29si890936pgn.176.2017.08.11.12.32.27; Fri, 11 Aug 2017 12:32:27 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=qbnAPOMj; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753890AbdHKTcZ (ORCPT + 25 others); Fri, 11 Aug 2017 15:32:25 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:57961 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753363AbdHKTa5 (ORCPT ); Fri, 11 Aug 2017 15:30:57 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id CCF22A4270; Fri, 11 Aug 2017 15:23:02 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=pKGg yhpSmJy9PL5etislAuH4APY=; b=qbnAPOMj+nHMFuMN6xf3c46h2GG8pTI1IGzx fZBJVuduz1HJefzasC276DekPPHBhUrjMdXymixO90xDxvFNouB4V58xNoqGX9yz Wx5nBOzMx2CfUbGSb+ZNqy4q/DHqB8SCJzG0bwdgFHQfuFaWcv76i7i2jtP2j5M2 HQxtZik= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id B6A14A4265; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) Received: from yoda.home (unknown [96.23.157.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 29795A425A; Fri, 11 Aug 2017 15:23:00 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 599062DA0674; Fri, 11 Aug 2017 15:22:59 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH 1/5] cramfs: direct memory access support Date: Fri, 11 Aug 2017 15:22:48 -0400 Message-Id: <20170811192252.19062-2-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170811192252.19062-1-nicolas.pitre@linaro.org> References: <20170811192252.19062-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 7CE4F2B0-7ECA-11E7-A625-9D2B0D78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Small embedded systems typically execute the kernel code in place (XIP) directly from flash to save on precious RAM usage. This adds the ability to consume filesystem data directly from flash to the cramfs filesystem as well. Cramfs is particularly well suited to this feature as it is very simple and its RAM usage is already very low, and with this feature it is possible to use it with no block device support and even lower RAM usage. This patch was inspired by a similar patch from Shane Nay dated 17 years ago that used to be very popular in embedded circles but never made it into mainline. This is a cleaned-up implementation that uses far fewer memory address at run time when both methods are configured in. In the context of small IoT deployments, this functionality has become relevant and useful again. To distinguish between both access types, the cramfs_physmem filesystem type must be specified when using a memory accessible cramfs image, and the physaddr argument must provide the actual filesystem image's physical memory location. Signed-off-by: Nicolas Pitre --- fs/cramfs/Kconfig | 30 ++++++- fs/cramfs/inode.c | 264 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 242 insertions(+), 52 deletions(-) -- 2.9.4 diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index 11b29d491b..5eed4ad2d5 100644 --- a/fs/cramfs/Kconfig +++ b/fs/cramfs/Kconfig @@ -1,6 +1,5 @@ config CRAMFS tristate "Compressed ROM file system support (cramfs) (OBSOLETE)" - depends on BLOCK select ZLIB_INFLATE help Saying Y here includes support for CramFs (Compressed ROM File @@ -20,3 +19,32 @@ config CRAMFS in terms of performance and features. If unsure, say N. + +config CRAMFS_BLOCKDEV + bool "Support CramFs image over a regular block device" if EXPERT + depends on CRAMFS && BLOCK + default y + help + This option allows the CramFs driver to load data from a regular + block device such a disk partition or a ramdisk. + +config CRAMFS_PHYSMEM + bool "Support CramFs image directly mapped in physical memory" + depends on CRAMFS + default y if !CRAMFS_BLOCKDEV + help + This option allows the CramFs driver to load data directly from + a linear adressed memory range (usually non volatile memory + like flash) instead of going through the block device layer. + This saves some memory since no intermediate buffering is + necessary. + + The filesystem type for this feature is "cramfs_physmem". + The location of the CramFs image in memory is board + dependent. Therefore, if you say Y, you must know the proper + physical address where to store the CramFs image and specify + it using the physaddr=0x******** mount option (for example: + "mount -t cramfs_physmem -o physaddr=0x100000 none /mnt"). + + If unsure, say N. + diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 7919967488..393eb27ef4 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "internal.h" @@ -36,6 +37,8 @@ struct cramfs_sb_info { unsigned long blocks; unsigned long files; unsigned long flags; + void *linear_virt_addr; + phys_addr_t linear_phys_addr; }; static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) @@ -140,6 +143,9 @@ static struct inode *get_cramfs_inode(struct super_block *sb, * BLKS_PER_BUF*PAGE_SIZE, so that the caller doesn't need to * worry about end-of-buffer issues even when decompressing a full * page cache. + * + * Note: This is all optimized away at compile time when + * CONFIG_CRAMFS_BLOCKDEV=n. */ #define READ_BUFFERS (2) /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */ @@ -160,10 +166,10 @@ static struct super_block *buffer_dev[READ_BUFFERS]; static int next_buffer; /* - * Returns a pointer to a buffer containing at least LEN bytes of - * filesystem starting at byte offset OFFSET into the filesystem. + * Populate our block cache and return a pointer from it. */ -static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) +static void *cramfs_blkdev_read(struct super_block *sb, unsigned int offset, + unsigned int len) { struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; struct page *pages[BLKS_PER_BUF]; @@ -239,7 +245,39 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i return read_buffers[buffer] + offset; } -static void cramfs_kill_sb(struct super_block *sb) +/* + * Return a pointer to the linearly addressed cramfs image in memory. + */ +static void *cramfs_direct_read(struct super_block *sb, unsigned int offset, + unsigned int len) +{ + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + + if (!len) + return NULL; + if (len > sbi->size || offset > sbi->size - len) + return page_address(ZERO_PAGE(0)); + return sbi->linear_virt_addr + offset; +} + +/* + * Returns a pointer to a buffer containing at least LEN bytes of + * filesystem starting at byte offset OFFSET into the filesystem. + */ +static void *cramfs_read(struct super_block *sb, unsigned int offset, + unsigned int len) +{ + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + + if (IS_ENABLED(CONFIG_CRAMFS_PHYSMEM) && sbi->linear_virt_addr) + return cramfs_direct_read(sb, offset, len); + else if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) + return cramfs_blkdev_read(sb, offset, len); + else + return NULL; +} + +static void cramfs_blkdev_kill_sb(struct super_block *sb) { struct cramfs_sb_info *sbi = CRAMFS_SB(sb); @@ -247,6 +285,16 @@ static void cramfs_kill_sb(struct super_block *sb) kfree(sbi); } +static void cramfs_physmem_kill_sb(struct super_block *sb) +{ + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + + if (sbi->linear_virt_addr) + memunmap(sbi->linear_virt_addr); + kill_anon_super(sb); + kfree(sbi); +} + static int cramfs_remount(struct super_block *sb, int *flags, char *data) { sync_filesystem(sb); @@ -254,34 +302,24 @@ static int cramfs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static int cramfs_fill_super(struct super_block *sb, void *data, int silent) +static int cramfs_read_super(struct super_block *sb, + struct cramfs_super *super, int silent) { - int i; - struct cramfs_super super; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); unsigned long root_offset; - struct cramfs_sb_info *sbi; - struct inode *root; - - sb->s_flags |= MS_RDONLY; - - sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); - if (!sbi) - return -ENOMEM; - sb->s_fs_info = sbi; - /* Invalidate the read buffers on mount: think disk change.. */ - mutex_lock(&read_mutex); - for (i = 0; i < READ_BUFFERS; i++) - buffer_blocknr[i] = -1; + /* We don't know the real size yet */ + sbi->size = PAGE_SIZE; /* Read the first block and get the superblock from it */ - memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super)); + mutex_lock(&read_mutex); + memcpy(super, cramfs_read(sb, 0, sizeof(*super)), sizeof(*super)); mutex_unlock(&read_mutex); /* Do sanity checks on the superblock */ - if (super.magic != CRAMFS_MAGIC) { + if (super->magic != CRAMFS_MAGIC) { /* check for wrong endianness */ - if (super.magic == CRAMFS_MAGIC_WEND) { + if (super->magic == CRAMFS_MAGIC_WEND) { if (!silent) pr_err("wrong endianness\n"); return -EINVAL; @@ -289,10 +327,10 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) /* check at 512 byte offset */ mutex_lock(&read_mutex); - memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super)); + memcpy(super, cramfs_read(sb, 512, sizeof(*super)), sizeof(*super)); mutex_unlock(&read_mutex); - if (super.magic != CRAMFS_MAGIC) { - if (super.magic == CRAMFS_MAGIC_WEND && !silent) + if (super->magic != CRAMFS_MAGIC) { + if (super->magic == CRAMFS_MAGIC_WEND && !silent) pr_err("wrong endianness\n"); else if (!silent) pr_err("wrong magic\n"); @@ -301,34 +339,34 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) } /* get feature flags first */ - if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { + if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) { pr_err("unsupported filesystem features\n"); return -EINVAL; } /* Check that the root inode is in a sane state */ - if (!S_ISDIR(super.root.mode)) { + if (!S_ISDIR(super->root.mode)) { pr_err("root is not a directory\n"); return -EINVAL; } /* correct strange, hard-coded permissions of mkcramfs */ - super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + super->root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - root_offset = super.root.offset << 2; - if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { - sbi->size = super.size; - sbi->blocks = super.fsid.blocks; - sbi->files = super.fsid.files; + root_offset = super->root.offset << 2; + if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { + sbi->size = super->size; + sbi->blocks = super->fsid.blocks; + sbi->files = super->fsid.files; } else { sbi->size = 1<<28; sbi->blocks = 0; sbi->files = 0; } - sbi->magic = super.magic; - sbi->flags = super.flags; + sbi->magic = super->magic; + sbi->flags = super->flags; if (root_offset == 0) pr_info("empty filesystem"); - else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && + else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && ((root_offset != sizeof(struct cramfs_super)) && (root_offset != 512 + sizeof(struct cramfs_super)))) { @@ -336,9 +374,18 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) return -EINVAL; } + return 0; +} + +static int cramfs_finalize_super(struct super_block *sb, + struct cramfs_inode *cramfs_root) +{ + struct inode *root; + /* Set it all up.. */ + sb->s_flags |= MS_RDONLY; sb->s_op = &cramfs_ops; - root = get_cramfs_inode(sb, &super.root, 0); + root = get_cramfs_inode(sb, cramfs_root, 0); if (IS_ERR(root)) return PTR_ERR(root); sb->s_root = d_make_root(root); @@ -347,6 +394,92 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } +static int cramfs_blkdev_fill_super(struct super_block *sb, void *data, int silent) +{ + struct cramfs_sb_info *sbi; + struct cramfs_super super; + int i, err; + + sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + sb->s_fs_info = sbi; + + /* Invalidate the read buffers on mount: think disk change.. */ + for (i = 0; i < READ_BUFFERS; i++) + buffer_blocknr[i] = -1; + + err = cramfs_read_super(sb, &super, silent); + if (err) + return err; + return cramfs_finalize_super(sb, &super.root); +} + +static int cramfs_physmem_fill_super(struct super_block *sb, void *data, int silent) +{ + struct cramfs_sb_info *sbi; + struct cramfs_super super; + char *p; + int err; + + sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + sb->s_fs_info = sbi; + + /* + * The physical location of the cramfs image is specified as + * a mount parameter. This parameter is mandatory for obvious + * reasons. Some validation is made on the phys address but this + * is not exhaustive and we count on the fact that someone using + * this feature is supposed to know what he/she's doing. + */ + if (!data || !(p = strstr((char *)data, "physaddr="))) { + pr_err("unknown physical address for linear cramfs image\n"); + return -EINVAL; + } + sbi->linear_phys_addr = memparse(p + 9, NULL); + if (!sbi->linear_phys_addr) { + pr_err("bad value for cramfs image physical address\n"); + return -EINVAL; + } + if (sbi->linear_phys_addr & (PAGE_SIZE-1)) { + pr_err("physical address %pap for linear cramfs isn't aligned to a page boundary\n", + &sbi->linear_phys_addr); + return -EINVAL; + } + + /* + * Map only one page for now. Will remap it when fs size is known. + * Although we'll only read from it, we want the CPU cache to + * kick in for the higher throughput it provides, hence MEMREMAP_WB. + */ + pr_info("checking physical address %pap for linear cramfs image\n", &sbi->linear_phys_addr); + sbi->linear_virt_addr = memremap(sbi->linear_phys_addr, PAGE_SIZE, + MEMREMAP_WB); + if (!sbi->linear_virt_addr) { + pr_err("ioremap of the linear cramfs image failed\n"); + return -ENOMEM; + } + + err = cramfs_read_super(sb, &super, silent); + if (err) + return err; + + /* Remap the whole filesystem now */ + pr_info("linear cramfs image appears to be %lu KB in size\n", + sbi->size/1024); + memunmap(sbi->linear_virt_addr); + sbi->linear_virt_addr = memremap(sbi->linear_phys_addr, sbi->size, + MEMREMAP_WB); + if (!sbi->linear_virt_addr) { + pr_err("ioremap of the linear cramfs image failed\n"); + return -ENOMEM; + } + + return cramfs_finalize_super(sb, &super.root); +} + static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -573,38 +706,67 @@ static const struct super_operations cramfs_ops = { .statfs = cramfs_statfs, }; -static struct dentry *cramfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static struct dentry *cramfs_blkdev_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_bdev(fs_type, flags, dev_name, data, cramfs_blkdev_fill_super); +} + +static struct dentry *cramfs_physmem_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return mount_bdev(fs_type, flags, dev_name, data, cramfs_fill_super); + return mount_nodev(fs_type, flags, data, cramfs_physmem_fill_super); } static struct file_system_type cramfs_fs_type = { .owner = THIS_MODULE, .name = "cramfs", - .mount = cramfs_mount, - .kill_sb = cramfs_kill_sb, + .mount = cramfs_blkdev_mount, + .kill_sb = cramfs_blkdev_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; + +static struct file_system_type cramfs_physmem_fs_type = { + .owner = THIS_MODULE, + .name = "cramfs_physmem", + .mount = cramfs_physmem_mount, + .kill_sb = cramfs_physmem_kill_sb, +}; + +#ifdef CONFIG_CRAMFS_BLOCKDEV MODULE_ALIAS_FS("cramfs"); +#endif +#ifdef CONFIG_CRAMFS_PHYSMEM +MODULE_ALIAS_FS("cramfs_physmem"); +#endif static int __init init_cramfs_fs(void) { int rv; - rv = cramfs_uncompress_init(); - if (rv < 0) - return rv; - rv = register_filesystem(&cramfs_fs_type); - if (rv < 0) - cramfs_uncompress_exit(); - return rv; + if ((rv = cramfs_uncompress_init()) < 0) + goto err0; + if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV) && + (rv = register_filesystem(&cramfs_fs_type)) < 0) + goto err1; + if (IS_ENABLED(CONFIG_CRAMFS_PHYSMEM) && + (rv = register_filesystem(&cramfs_physmem_fs_type)) < 0) + goto err2; + return 0; + +err2: if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) + unregister_filesystem(&cramfs_fs_type); +err1: cramfs_uncompress_exit(); +err0: return rv; } static void __exit exit_cramfs_fs(void) { cramfs_uncompress_exit(); - unregister_filesystem(&cramfs_fs_type); + if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) + unregister_filesystem(&cramfs_fs_type); + if (IS_ENABLED(CONFIG_CRAMFS_PHYSMEM)) + unregister_filesystem(&cramfs_physmem_fs_type); } module_init(init_cramfs_fs) From patchwork Fri Aug 11 19:22:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 109922 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp1340128qge; Fri, 11 Aug 2017 12:31:19 -0700 (PDT) X-Received: by 10.84.229.6 with SMTP id b6mr19095415plk.274.1502479879720; Fri, 11 Aug 2017 12:31:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502479879; cv=none; d=google.com; s=arc-20160816; b=bsyrsNcfEcYP5JwYM4fU0LzavWA25HLmqXlfirAZ6Dg5r6HuuhzF3gv/DGpxVgcmj6 7yEYfGBdXVYwTwRQEEhm2BPZiuD045WypRm+czn0ay+3w3B8hJufBAhsmP8+AzKk1eAh czisIZqOdtLyIW8dI9r16CjDMKHSn+t4FnTtpr2IAGm1+Mgv62kXbPeWBtuB7XrHquKG CIhLTKVVN9rmXqGNNxbhjCSnAtErDj01fyrzzgWIKDCEwwinebgX1VdoSchNz3SIRvUx 1hYMjR0MwdGEs0lmz48MPWkLbKcirWT9joJ6dhhrufwoo8x3Sn47AxFVl0s+3zVChrPV wqTQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=ca+QiXC0vF9FkCx9VLYqGM6WdqUbVTv57rFd2zh45MM=; b=P4Fv/TQxQRL8G5aDTwtLgzrC6GXQH0vZf5eJEbR8RLsP3bh9Ur1Y5KUripUganfSxP ytiarzFjXsBycmPcqGs9JPSvjNhQ3sEeY/yGu0hvaV6WpoDoG/AxGQ1I930nicd8nKG7 WVT/uPpUDvXpXnQF2A6FeTeglHaIaPK2erIHLe0lAEbjEgr8kSgsF5CtW0rdmvDH4vEF T1rFtk2cIWWrkHnNgswNTUG8d1uvs2LCIRGkc4qkJDFJzKG5aIR7SvqOBnbfvraf2ZX9 LfhOXgqaFXjt5V32/Ti3C8xU+GJI1GHbS3gGqjeJ7dK7GPYgDQE7VOWZr9tsV+tbYnOL NgkA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=Y1ii0t1G; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r15si879293pfd.505.2017.08.11.12.31.19; Fri, 11 Aug 2017 12:31:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=Y1ii0t1G; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753766AbdHKTbB (ORCPT + 25 others); Fri, 11 Aug 2017 15:31:01 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:58929 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753401AbdHKTa5 (ORCPT ); Fri, 11 Aug 2017 15:30:57 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id CD4E2A4267; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=Kzk1 NoZ34grNpdHOoyv80jv8ttk=; b=Y1ii0t1GS1rEDUp+4tBwBzWdT4CMTJ1WgyWC JMZHMXAiFIeWtggheoWmmYefeJtIYKYFJbP0MctlTrawxZMt2snZzqmkbFb+6A4o FEXGtBVYL3oy7Pu8KDM48Qaxwpu2ItmmtfEQ9SN/BwZ2Kw68ekTHfXXVfaeEZDcw 9GB4VH8= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 5EBC5A4261; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) Received: from yoda.home (unknown [96.23.157.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 203A4A4258; Fri, 11 Aug 2017 15:23:00 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 7A6082DA0679; Fri, 11 Aug 2017 15:22:59 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH 2/5] cramfs: make cramfs_physmem usable as root fs Date: Fri, 11 Aug 2017 15:22:49 -0400 Message-Id: <20170811192252.19062-3-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170811192252.19062-1-nicolas.pitre@linaro.org> References: <20170811192252.19062-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 7CDD8764-7ECA-11E7-BCC6-9D2B0D78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Signed-off-by: Nicolas Pitre --- init/do_mounts.c | 8 ++++++++ 1 file changed, 8 insertions(+) -- 2.9.4 diff --git a/init/do_mounts.c b/init/do_mounts.c index c2de5104aa..43b5817f60 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -556,6 +556,14 @@ void __init prepare_namespace(void) ssleep(root_delay); } + if (IS_ENABLED(CONFIG_CRAMFS_PHYSMEM) && root_fs_names && + !strcmp(root_fs_names, "cramfs_physmem")) { + int err = do_mount_root("cramfs", "cramfs_physmem", + root_mountflags, root_mount_data); + if (!err) + goto out; + } + /* * wait for the known devices to complete their probing * From patchwork Fri Aug 11 19:22:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 109921 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp1339968qge; Fri, 11 Aug 2017 12:31:10 -0700 (PDT) X-Received: by 10.99.147.71 with SMTP id w7mr16093050pgm.24.1502479870015; Fri, 11 Aug 2017 12:31:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502479870; cv=none; d=google.com; s=arc-20160816; b=D2U2jx0LsgApeSYnOJyLPU+q5TxjI/pavnB7onL97hWV3LeJz++MkVpIJNBRWILECF /tnZUDhVxdxWznA2Z+27XOgjJ/+W1GgO7O8N4VQs1pyPp4S/Gdgjr9tjSYfpZNWLgFMf L09Jl7Fjct0hYCV+DWza2H9P0kyOtj+xd9UhB+PSLy1HyCQEEAznqrQJp6djUVpKF0uI Ec94sOzCib2xio4IYFXd7oqIi0lMLFc2BJVQnXrTo9nH+1e0d73HJ3jpA2Ve/PmgMQjx MdfPPyqse7lit+Ta6d9+DNqs0KOeYJQGkdNKFJf8r/vsNUftUR89JyZnPjcsyIXaKVPf 5YNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=gpkIlciVfYD57TRIqwkTxUKts/zAYIrjrQnnMx8Un+I=; b=mCx0Xhq/fTOTBgg0OwlBcbRik4oyqq+tVp6lOGrZAO3+D3meD84Un/dBp/0UOrfAkc UYa0iqJUi9cJri2Z0wHYqwrGUGxNBC4K37Fls3aaFn4w0M/EzvTXp5TYR0f5t+aE4cuk TwEDvlBi2p26jnhd/J2Xd5xgXsoVaomxXmPsjZQa6DXtsmsvr+bkdXsYpFHwJzzVpXNw UKXqac+4pBbt8DZskoY3UNlkP6n/6IGRw7FOdqnPtW3qznaZV/THiAGyMNZ2cehzg8Sb huL6+w1WTJRWTrllikYmMSF+z3KNSinfsU12AoHyTzaE3tXMMUtIKbcGJ45PXKAxKDC2 LS5w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=HqoeLbJC; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l14si950042plk.333.2017.08.11.12.31.09; Fri, 11 Aug 2017 12:31:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=HqoeLbJC; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753785AbdHKTbD (ORCPT + 25 others); Fri, 11 Aug 2017 15:31:03 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:57953 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753357AbdHKTa5 (ORCPT ); Fri, 11 Aug 2017 15:30:57 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id CD64BA4269; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=7N5i 8V6sh5kGfF6QlWJpJm35Oac=; b=HqoeLbJCOgBGK3VKpNCmLnRSJdVNMU3ic0aJ QFjZJVciPzjBe7+JcBDS1OVqFNrEBviZZoTLcOPVfWk4v+4fLRnUBuVshGXTKt55 H8md1WHXIJhnlwoRPp7sulpja+HzlJT/mfUxhMaN9H1a3O4rgYQfmwGUgfKK768k RJQ9q/g= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 59953A425E; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) Received: from yoda.home (unknown [96.23.157.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 2E91EA425B; Fri, 11 Aug 2017 15:23:00 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 934E32DA067D; Fri, 11 Aug 2017 15:22:59 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH 3/5] cramfs: implement uncompressed and arbitrary data block positioning Date: Fri, 11 Aug 2017 15:22:50 -0400 Message-Id: <20170811192252.19062-4-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170811192252.19062-1-nicolas.pitre@linaro.org> References: <20170811192252.19062-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 7CE6AFEC-7ECA-11E7-9F63-9D2B0D78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Two new capabilities are introduced here: - The ability to store some blocks uncompressed. - The ability to locate blocks anywhere. Those capabilities can be used independently, but the combination opens the possibility for execute-in-place (XIP) of program text segments that must remain uncompressed, and in the MMU case, must have a specific alignment. It is even possible to still have the writable data segments from the same file compressed as they have to be copied into RAM anyway. This is achieved by giving special meanings to some unused block pointer bits while remaining compatible with legacy cramfs images. Signed-off-by: Nicolas Pitre --- fs/cramfs/README | 31 ++++++++++++++- fs/cramfs/inode.c | 87 +++++++++++++++++++++++++++++++++--------- include/uapi/linux/cramfs_fs.h | 20 +++++++++- 3 files changed, 118 insertions(+), 20 deletions(-) -- 2.9.4 diff --git a/fs/cramfs/README b/fs/cramfs/README index 9d4e7ea311..d71b27e0ff 100644 --- a/fs/cramfs/README +++ b/fs/cramfs/README @@ -49,17 +49,46 @@ same as the start of the (i+1)'th if there is one). The first immediately follows the last for the file. s are each 32 bits long. +When the CRAMFS_FLAG_EXT_BLOCK_POINTERS capability bit is set, each +'s top bits may contain special flags as follows: + +CRAMFS_BLK_FLAG_UNCOMPRESSED (bit 31): + The block data is not compressed and should be copied verbatim. + +CRAMFS_BLK_FLAG_DIRECT_PTR (bit 30): + The stores the actual block start offset and not + its end, shifted right by 2 bits. The block must therefore be + aligned to a 4-byte boundary. The block size is either blksize + if CRAMFS_BLK_FLAG_UNCOMPRESSED is also specified, otherwise + the compressed data length is included in the first 2 bytes of + the block data. This is used to allow discontiguous data layout + and specific data block alignments e.g. for XIP applications. + + The order of 's is a depth-first descent of the directory tree, i.e. the same order as `find -size +0 \( -type f -o -type l \) -print'. : The i'th is the output of zlib's compress function -applied to the i'th blksize-sized chunk of the input data. +applied to the i'th blksize-sized chunk of the input data if the +corresponding CRAMFS_BLK_FLAG_UNCOMPRESSED bit is not set, +otherwise it is the input data directly. (For the last of the file, the input may of course be smaller.) Each may be a different size. (See above.) + s are merely byte-aligned, not generally u32-aligned. +When CRAMFS_BLK_FLAG_DIRECT_PTR is specified then the corresponding + may be located anywhere and not necessarily contiguous with +the previous/next blocks. In that case it is minimally u32-aligned. +If CRAMFS_BLK_FLAG_UNCOMPRESSED is also specified then the size is always +blksize except for the last block which is limited by the file length. +If CRAMFS_BLK_FLAG_DIRECT_PTR is set and CRAMFS_BLK_FLAG_UNCOMPRESSED +is not set then the first 2 bytes of the block contains the size of the +remaining block data as this cannot be determined from the placement of +logically adjacent blocks. + Holes ----- diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 393eb27ef4..b825ae162c 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -636,33 +636,84 @@ static int cramfs_readpage(struct file *file, struct page *page) if (page->index < maxblock) { struct super_block *sb = inode->i_sb; u32 blkptr_offset = OFFSET(inode) + page->index*4; - u32 start_offset, compr_len; + u32 block_ptr, block_start, block_len; + bool uncompressed, direct; - start_offset = OFFSET(inode) + maxblock*4; mutex_lock(&read_mutex); - if (page->index) - start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, - 4); - compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - - start_offset); - mutex_unlock(&read_mutex); + block_ptr = *(u32 *) cramfs_read(sb, blkptr_offset, 4); + uncompressed = (block_ptr & CRAMFS_BLK_FLAG_UNCOMPRESSED); + direct = (block_ptr & CRAMFS_BLK_FLAG_DIRECT_PTR); + block_ptr &= ~CRAMFS_BLK_FLAGS; + + if (direct) { + /* + * The block pointer is an absolute start pointer, + * shifted by 2 bits. The size is included in the + * first 2 bytes of the data block when compressed, + * or PAGE_SIZE otherwise. + */ + block_start = block_ptr << 2; + if (uncompressed) { + block_len = PAGE_SIZE; + /* if last block: cap to file length */ + if (page->index == maxblock - 1) + block_len = offset_in_page(inode->i_size); + } else { + block_len = *(u16 *) + cramfs_read(sb, block_start, 2); + block_start += 2; + } + } else { + /* + * The block pointer indicates one past the end of + * the current block (start of next block). If this + * is the first block then it starts where the block + * pointer table ends, otherwise its start comes + * from the previous block's pointer. + */ + block_start = OFFSET(inode) + maxblock*4; + if (page->index) + block_start = *(u32 *) + cramfs_read(sb, blkptr_offset-4, 4); + /* Beware... previous ptr might be a direct ptr */ + if (unlikely(block_start & CRAMFS_BLK_FLAG_DIRECT_PTR)) { + /* See comments on earlier code. */ + u32 prev_start = block_start; + block_start = prev_start & ~CRAMFS_BLK_FLAGS; + block_start <<= 2; + if (prev_start & CRAMFS_BLK_FLAG_UNCOMPRESSED) { + block_start += PAGE_SIZE; + } else { + block_len = *(u16 *) + cramfs_read(sb, block_start, 2); + block_start += 2 + block_len; + } + } + block_start &= ~CRAMFS_BLK_FLAGS; + block_len = block_ptr - block_start; + } - if (compr_len == 0) + if (block_len == 0) ; /* hole */ - else if (unlikely(compr_len > (PAGE_SIZE << 1))) { - pr_err("bad compressed blocksize %u\n", - compr_len); + else if (unlikely(block_len > 2*PAGE_SIZE || + (uncompressed && block_len > PAGE_SIZE))) { + mutex_unlock(&read_mutex); + pr_err("bad data blocksize %u\n", block_len); goto err; + } else if (uncompressed) { + memcpy(pgdata, + cramfs_read(sb, block_start, block_len), + block_len); + bytes_filled = block_len; } else { - mutex_lock(&read_mutex); bytes_filled = cramfs_uncompress_block(pgdata, PAGE_SIZE, - cramfs_read(sb, start_offset, compr_len), - compr_len); - mutex_unlock(&read_mutex); - if (unlikely(bytes_filled < 0)) - goto err; + cramfs_read(sb, block_start, block_len), + block_len); } + mutex_unlock(&read_mutex); + if (unlikely(bytes_filled < 0)) + goto err; } memset(pgdata + bytes_filled, 0, PAGE_SIZE - bytes_filled); diff --git a/include/uapi/linux/cramfs_fs.h b/include/uapi/linux/cramfs_fs.h index e4611a9b92..ed250aa372 100644 --- a/include/uapi/linux/cramfs_fs.h +++ b/include/uapi/linux/cramfs_fs.h @@ -73,6 +73,7 @@ struct cramfs_super { #define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ #define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ #define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ +#define CRAMFS_FLAG_EXT_BLOCK_POINTERS 0x00000800 /* block pointer extensions */ /* * Valid values in super.flags. Currently we refuse to mount @@ -82,7 +83,24 @@ struct cramfs_super { #define CRAMFS_SUPPORTED_FLAGS ( 0x000000ff \ | CRAMFS_FLAG_HOLES \ | CRAMFS_FLAG_WRONG_SIGNATURE \ - | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) + | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET \ + | CRAMFS_FLAG_EXT_BLOCK_POINTERS ) +/* + * Block pointer flags + * + * The maximum block offset that needs to be represented is roughly: + * + * (1 << CRAMFS_OFFSET_WIDTH) * 4 + + * (1 << CRAMFS_SIZE_WIDTH) / PAGE_SIZE * (4 + PAGE_SIZE) + * = 0x11004000 + * + * That leaves room for 3 flag bits in the block pointer table. + */ +#define CRAMFS_BLK_FLAG_UNCOMPRESSED (1 << 31) +#define CRAMFS_BLK_FLAG_DIRECT_PTR (1 << 30) + +#define CRAMFS_BLK_FLAGS ( CRAMFS_BLK_FLAG_UNCOMPRESSED \ + | CRAMFS_BLK_FLAG_DIRECT_PTR ) #endif /* _UAPI__CRAMFS_H */ From patchwork Fri Aug 11 19:22:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 109924 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp1340556qge; Fri, 11 Aug 2017 12:31:45 -0700 (PDT) X-Received: by 10.98.48.69 with SMTP id w66mr17496111pfw.214.1502479905191; Fri, 11 Aug 2017 12:31:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502479905; cv=none; d=google.com; s=arc-20160816; b=b1doEdz1s86UJpypppTyoG70zBQRLht7kJifx/REFhk17Ef6lM0WUpbskVhtDp0kY1 43lsIXtmeUlrzzMgVyzlCD5f5upFeM+uc7+n80YKmGO6w90+uCt9c2ups8miXgPmYlBW 3NDN5QEApEHukCr2E2QyNY6FtiRsfhxIOdWmK3zCXF2haQMd2Mcz8Fyeqv1EFr6VNy9T FY75uV9cpvw0Rf6SoHQd40aNRNr1nTr5JK5zZYu1XkmDJiRc3Qt8QIP17YmUZJXwqeCx h0ECkAzrCPLyYSQQyxklsyCUxsC0V6z/0YYVMa691gRXXPDagnuy0YGjSn7BqZXpj15A 3/7w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=BHJYgBGqALWA0+DY28YqyG9dWTiROFsaTF1LLpCmCjw=; b=RHHGsjaukZ9qvGRLyHwKDTLmJ3EALgZxw9dPxS1kaM2PfvN4bc5eEllvg4uxhp2vMR /hCmBdxkIIcGjKTyow0E/GIt3lfmqMftiu9j8vMNI8enHs84x9gfoIIOD9h2hjnUnE5u YoQvq2RekYM1zf5M+pG4rW/ODDCDP83YxlH23Ikt3H8kH83dajp9Sjs9Rwll73APcUcc CJCzT9utq9v2gDCoyAt4gtvdJ9iF1UXYuoSqAnCNmlJiM0j8LlkFhm4hmd1UUQsUfj8c bBGF5gqeWU74xwV8sUVTduRr8uHwO57YKHT50rhMg4m99ANOkrQJ59oHNweHBtjo+rmF c4XQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=WlSeqeW3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l62si907543pfa.56.2017.08.11.12.31.44; Fri, 11 Aug 2017 12:31:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=WlSeqeW3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753842AbdHKTbm (ORCPT + 25 others); Fri, 11 Aug 2017 15:31:42 -0400 Received: from pb-smtp1.pobox.com ([64.147.108.70]:60235 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753821AbdHKTbj (ORCPT ); Fri, 11 Aug 2017 15:31:39 -0400 X-Greylist: delayed 516 seconds by postgrey-1.27 at vger.kernel.org; Fri, 11 Aug 2017 15:31:38 EDT Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 9CF2DAE1F3; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=DzuM hcjKpeO64sAi186SeOtt4D8=; b=WlSeqeW3WrmeF+WC6Eil1HU8C7iSaMDUMDmG auTX6oSHRp/HbYpbrCgpwL5ZIJGeEebAAtnyrFydObGsXoYMqE+YSGBQ6zyDeJeW JEbfEk+67IA7ZV3IPUkaTjw++U0AZF9nGztD1AsgcRCoGkGHiKK7FV6wMig0Thjn 6NYPY8g= Received: from pb-smtp1.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 94163AE1F2; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) Received: from yoda.home (unknown [96.23.157.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp1.pobox.com (Postfix) with ESMTPSA id 76EB2AE1ED; Fri, 11 Aug 2017 15:23:00 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id AC7772DA0695; Fri, 11 Aug 2017 15:22:59 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH 4/5] cramfs: add mmap support Date: Fri, 11 Aug 2017 15:22:51 -0400 Message-Id: <20170811192252.19062-5-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170811192252.19062-1-nicolas.pitre@linaro.org> References: <20170811192252.19062-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 7D15BD6E-7ECA-11E7-B26A-FE4B1A68708C-78420484!pb-smtp1.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When cramfs_physmem is used then we have the opportunity to map files directly from ROM, directly into user space, saving on RAM usage. This gives us Execute-In-Place (XIP) support. For a file to be mmap()-able, the map area has to correspond to a range of uncompressed and contiguous blocks, and in the MMU case it also has to be page aligned. A version of mkcramfs with appropriate support is necessary to create such a filesystem image. Signed-off-by: Nicolas Pitre --- fs/cramfs/inode.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) -- 2.9.4 diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index b825ae162c..5aedbd224e 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb) static const struct super_operations cramfs_ops; static const struct inode_operations cramfs_dir_inode_operations; static const struct file_operations cramfs_directory_operations; +static const struct file_operations cramfs_physmem_fops; static const struct address_space_operations cramfs_aops; static DEFINE_MUTEX(read_mutex); @@ -96,6 +98,10 @@ static struct inode *get_cramfs_inode(struct super_block *sb, case S_IFREG: inode->i_fop = &generic_ro_fops; inode->i_data.a_ops = &cramfs_aops; + if (IS_ENABLED(CONFIG_CRAMFS_PHYSMEM) && + CRAMFS_SB(sb)->flags & CRAMFS_FLAG_EXT_BLOCK_POINTERS && + CRAMFS_SB(sb)->linear_phys_addr) + inode->i_fop = &cramfs_physmem_fops; break; case S_IFDIR: inode->i_op = &cramfs_dir_inode_operations; @@ -277,6 +283,149 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, return NULL; } +/* + * For a mapping to be possible, we need a range of uncompressed and + * contiguous blocks. Return the offset for the first block if that + * verifies, or zero otherwise. + */ +static u32 cramfs_get_block_range(struct inode *inode, u32 pgoff, u32 pages) +{ + struct super_block *sb = inode->i_sb; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + int i; + u32 *blockptrs, blockaddr; + + /* + * We can dereference memory directly here as this code may be + * reached only when there is a direct filesystem image mapping + * available in memory. + */ + blockptrs = (u32 *)(sbi->linear_virt_addr + OFFSET(inode) + pgoff*4); + blockaddr = blockptrs[0] & ~CRAMFS_BLK_FLAGS; + i = 0; + do { + u32 expect = blockaddr + i * (PAGE_SIZE >> 2); + expect |= CRAMFS_BLK_FLAG_DIRECT_PTR|CRAMFS_BLK_FLAG_UNCOMPRESSED; + pr_debug("range: block %d/%d got %#x expects %#x\n", + pgoff+i, pgoff+pages-1, blockptrs[i], expect); + if (blockptrs[i] != expect) + return 0; + } while (++i < pages); + + /* stored "direct" block ptrs are shifted down by 2 bits */ + return blockaddr << 2; +} + +static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + unsigned int pages, max_pages, offset; + unsigned long length, address; + char *fail_reason; + int ret; + + if (!IS_ENABLED(CONFIG_MMU)) + return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -ENOSYS; + + if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) + return -EINVAL; + + vma->vm_ops = &generic_file_vm_ops; + if (vma->vm_flags & VM_WRITE) + return 0; + + length = vma->vm_end - vma->vm_start; + pages = (length + PAGE_SIZE - 1) >> PAGE_SHIFT; + max_pages = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (vma->vm_pgoff >= max_pages || pages > max_pages - vma->vm_pgoff) + return -EINVAL; + + offset = cramfs_get_block_range(inode, vma->vm_pgoff, pages); + fail_reason = "unsuitable block layout"; + if (!offset) + goto fail; + address = sbi->linear_phys_addr + offset; + fail_reason = "data is not page aligned"; + if (!PAGE_ALIGNED(address)) + goto fail; + + /* Don't map a partial page if it contains some other data */ + if (unlikely(vma->vm_pgoff + pages == max_pages)) { + unsigned int partial = offset_in_page(inode->i_size); + if (partial) { + char *data = sbi->linear_virt_addr + offset; + data += (pages - 1) * PAGE_SIZE + partial; + fail_reason = "last partial page is shared"; + while ((unsigned long)data & 7) + if (*data++ != 0) + goto fail; + while (offset_in_page(data)) { + if (*(u64 *)data != 0) + goto fail; + data += 8; + } + } + } + + ret = remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT, + length, vma->vm_page_prot); + if (ret) + return ret; + pr_debug("mapped %s at 0x%08lx, length %lu to vma 0x%08lx, " + "page_prot 0x%llx\n", file_dentry(file)->d_name.name, + address, length, vma->vm_start, + (unsigned long long)pgprot_val(vma->vm_page_prot)); + return 0; + +fail: + pr_debug("%s: direct mmap failed: %s\n", + file_dentry(file)->d_name.name, fail_reason); + return 0; +} + +#ifndef CONFIG_MMU + +static unsigned long cramfs_physmem_get_unmapped_area(struct file *file, + unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags) +{ + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct cramfs_sb_info *sbi = CRAMFS_SB(sb); + unsigned int pages, max_pages, offset; + + pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; + max_pages = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (pgoff >= max_pages || pages > max_pages - pgoff) + return -EINVAL; + offset = cramfs_get_block_range(inode, pgoff, pages); + if (!offset) + return -ENOSYS; + addr = sbi->linear_phys_addr + offset; + pr_debug("get_unmapped for %s ofs %#lx siz %lu at 0x%08lx\n", + file_dentry(file)->d_name.name, pgoff*PAGE_SIZE, len, addr); + return addr; +} + +static unsigned cramfs_physmem_mmap_capabilities(struct file *file) +{ + return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_READ | NOMMU_MAP_EXEC; +} +#endif + +static const struct file_operations cramfs_physmem_fops = { + .llseek = generic_file_llseek, + .read_iter = generic_file_read_iter, + .splice_read = generic_file_splice_read, + .mmap = cramfs_physmem_mmap, +#ifndef CONFIG_MMU + .get_unmapped_area = cramfs_physmem_get_unmapped_area, + .mmap_capabilities = cramfs_physmem_mmap_capabilities, +#endif +}; + static void cramfs_blkdev_kill_sb(struct super_block *sb) { struct cramfs_sb_info *sbi = CRAMFS_SB(sb); From patchwork Fri Aug 11 19:22:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 109925 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp1340964qge; Fri, 11 Aug 2017 12:32:09 -0700 (PDT) X-Received: by 10.84.237.2 with SMTP id s2mr18529448plk.70.1502479929880; Fri, 11 Aug 2017 12:32:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502479929; cv=none; d=google.com; s=arc-20160816; b=vgWlmCHvTb2nW5Bk0gSO6z7m8UlNRqTW8Jak7hGZ+9iwoLcGmTa8N51zumyLpXRhRn 9IpcwUuJ2NVJSLbxkzoN3SDGCvf20IDKtyG4hox01uJilmWFjIKMlW7gam4vhzt2fUhd hHHpQ/klqcCg08T8nrsizezBCZmaSMc/xqaYrNEt4zbu83J5hDAVl/BJO0aZHDpAeeaI Zk4VT0szqI5xmLRqyGNX67bUX5C/ZrsDofARbwZ6kWCmMeCJ8+Ee6sKRcMOwNAoKsbcx +YTDeqW3h1ZuAySpUFyGwhdQng97oFyogQjrFYcWUxUA3mFWW7MWl+LvIwwlJ66GNC1m W/Zg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=0PIbmuDYFJ1tbRN1x35uh8SWe7ImlXQXwY26yt0Uwfo=; b=HTO+lbg1PCJgWagp6RL4r3nKXHmEdFXyAebBmTbPC6nUs1g42+HLjmQalnbgeI+JPl 59VODQAFM+5Rqkz9z6ftNLavEonHn9BshLeVAlhp/0Tl2WZzHTcrAVttRAf+q9on97VZ GI9o4aOO+FtfS1iZ4Ht2G3WkpKmf0aPCI8SbanCayEHGqU4aouRm7wW8o2dd1LMV4DJo m00mpNbT+LssatP0Ch4osH+lduz+Fa3+XORdgIMo7GEc0TQuEprE3wFTEF6W7/t62wrx g+XgrDKNUnFYmoChcb66iUCoiSGIR77YzpXliVLqsOqzuU6F6vcxVrTQf7tUXCvbabsW vwoA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=R2NYSel+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l62si907543pfa.56.2017.08.11.12.32.09; Fri, 11 Aug 2017 12:32:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=R2NYSel+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753690AbdHKTa7 (ORCPT + 25 others); Fri, 11 Aug 2017 15:30:59 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:59658 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753181AbdHKTa5 (ORCPT ); Fri, 11 Aug 2017 15:30:57 -0400 X-Greylist: delayed 474 seconds by postgrey-1.27 at vger.kernel.org; Fri, 11 Aug 2017 15:30:56 EDT Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 3AA05A426B; Fri, 11 Aug 2017 15:23:02 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=pobox.com; h=from:to:cc :subject:date:message-id:in-reply-to:references; s=sasl; bh=VHSG cnoZBCAQ5jaB4wDrffQDCv4=; b=R2NYSel+FjXWzpetvz6Ct8LFJCDSsjDHYygy K7YU+k/L5pj04mMXyxdekQdGg/9RT8lyxD5bdkBt/yz6nOTBJT3v+wJlEzdSfoeu Wg+YXZD+bLY88ecg1BeDlyThX9V3yp8H0UUHksD/6piwri5DxnTnz+vW0Ckiihmg YQStVZM= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 2BCB2A426A; Fri, 11 Aug 2017 15:23:02 -0400 (EDT) Received: from yoda.home (unknown [96.23.157.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 5EC21A4262; Fri, 11 Aug 2017 15:23:01 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id BD70C2DA06C6; Fri, 11 Aug 2017 15:22:59 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH 5/5] cramfs: rehabilitate it Date: Fri, 11 Aug 2017 15:22:52 -0400 Message-Id: <20170811192252.19062-6-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170811192252.19062-1-nicolas.pitre@linaro.org> References: <20170811192252.19062-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 7D9D4360-7ECA-11E7-BAA9-9D2B0D78B957-78420484!pb-smtp2.pobox.com Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Update documentation, pointer to latest tools, appoint myself as maintainer. Given it's been unloved for so long, I don't expect anyone will protest. Signed-off-by: Nicolas Pitre --- Documentation/filesystems/cramfs.txt | 35 +++++++++++++++++++++++++++++++++++ MAINTAINERS | 4 ++-- fs/cramfs/Kconfig | 9 ++++++--- 3 files changed, 43 insertions(+), 5 deletions(-) -- 2.9.4 diff --git a/Documentation/filesystems/cramfs.txt b/Documentation/filesystems/cramfs.txt index 4006298f67..5955c23bac 100644 --- a/Documentation/filesystems/cramfs.txt +++ b/Documentation/filesystems/cramfs.txt @@ -45,6 +45,41 @@ you can just change the #define in mkcramfs.c, so long as you don't mind the filesystem becoming unreadable to future kernels. +Memory Mapped cramfs image +-------------------------- + +The CRAMFS_PHYSMEM Kconfig option adds support for loading data directly +from a physical linear memory range (usually non volatile memory like Flash) +to cramfs instead of going through the block device layer. This saves some +memory since no intermediate buffering is necessary to hold the data before +decompressing. + +And when data blocks are kept uncompressed and properly aligned, they will +automatically be mapped directly into user space whenever possible providing +eXecute-In-Place (XIP) from ROM of read-only segments. Data segments mapped +read-write (hence they have to be copied to RAM) may still be compressed in +the cramfs image in the same file along with non compressed read-only +segments. Both MMU and no-MMU systems are supported. This is particularly +handy for tiny embedded systems with very tight memory constraints. + +The filesystem type for this feature is "cramfs_physmem" to distinguish it +from the block device (or MTD) based access. The location of the cramfs +image in memory is system dependent. You must know the proper physical +address where the cramfs image is located and specify it using the +physaddr=0x******** mount option (for example: + +$ mount -t cramfs_physmem -o physaddr=0x80100000 none /mnt + + +Tools +----- + +A version of mkcramfs that can take advantage of the latest capabilities +described above can be found here: + +https://github.com/npitre/cramfs-tools + + For /usr/share/magic -------------------- diff --git a/MAINTAINERS b/MAINTAINERS index 44cb004c76..12f8155cfe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3612,8 +3612,8 @@ F: drivers/cpuidle/* F: include/linux/cpuidle.h CRAMFS FILESYSTEM -W: http://sourceforge.net/projects/cramfs/ -S: Orphan / Obsolete +M: Nicolas Pitre +S: Maintained F: Documentation/filesystems/cramfs.txt F: fs/cramfs/ diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index 5eed4ad2d5..8ed27e41bd 100644 --- a/fs/cramfs/Kconfig +++ b/fs/cramfs/Kconfig @@ -1,5 +1,5 @@ config CRAMFS - tristate "Compressed ROM file system support (cramfs) (OBSOLETE)" + tristate "Compressed ROM file system support (cramfs)" select ZLIB_INFLATE help Saying Y here includes support for CramFs (Compressed ROM File @@ -15,8 +15,11 @@ config CRAMFS cramfs. Note that the root file system (the one containing the directory /) cannot be compiled as a module. - This filesystem is obsoleted by SquashFS, which is much better - in terms of performance and features. + This filesystem is limited in capabilities and performance on + purpose to remain small and low on RAM usage. It is most suitable + for small embedded systems. For a more capable compressed filesystem + you should look at SquashFS which is much better in terms of + performance and features. If unsure, say N.