From patchwork Wed Sep 27 23:32:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 114381 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp61151qgf; Wed, 27 Sep 2017 16:33:28 -0700 (PDT) X-Google-Smtp-Source: AOwi7QCKKzym4eV61jWLshOR5dQDN/p1hx3wb2ZevqY4V1vdKm2xnp4TRFp/JPep+x0SYEHvfU4L X-Received: by 10.99.98.131 with SMTP id w125mr2608634pgb.214.1506555208431; Wed, 27 Sep 2017 16:33:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506555208; cv=none; d=google.com; s=arc-20160816; b=BAQQ8WskXKjJbsxmySIV6LbI2NW0hgMRMpcRFclGN7HHgtCEts3+fuqGrgV43wvKNB 5R9896VWYY6pEZzYTAxKMuqciGeGOvXNXUOIdkuxYQ0m2SYGbat4+mt3vpOUya9EUUh7 nd/uSBQfC3K9yzLQ7XB9mouCm3NO4eK0b5l9QfhTcPJeZerl1Lsl3ADXVc5KIeSBDGsX Tqz/cbmeGqbanMAs20L3Y/xL6dRQ7o7XMN9OYsamUdKKcENTyG9pgLAFbl+NxIVuzl1L 5+jGBqRJTXA8iDGkzou7SWWoLdEl0f7/ZzW59dggf7V133bbdKyNAeoOdtDOxek3ahwD ajLg== 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=AHxqAmmeur7ytO16D1Zf60J8lM97u1ahTFBo2su4DZc=; b=DKMBUWS7EvCskvMhVGm+vc8iKAIJwyAl/RamWq/FCtPg2i5YB3cNCWizImx5TqR6YP i8BeT6eVmy7LjwhC3tykf6+mD5iUuJMZVxWvIC+urhQDVj2125YcZpku9mpiKixICRFm 4nIsWAvvTnNMXsrtHgyYw9L2cuUey0/WKDsIyG5IC5u4F6LIuKxGNVDlxFNlhNJxApKf gpxjkfZJwB9K6EXGfYGN6n6ui0jreGPSzc0B7qZUP2nXZcl0XrCuKV8Km5rq7pMpvGQ5 PdF7xJbP6eMXlKrQCfDrgU060Bu+u30VgkPeX5EqRekUdcmpN5oHCxgnbIZdZMMcbHHC elJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=uUOY5dtl; 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 3si105639plp.335.2017.09.27.16.33.28; Wed, 27 Sep 2017 16:33:28 -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=uUOY5dtl; 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 S1752632AbdI0XdZ (ORCPT + 26 others); Wed, 27 Sep 2017 19:33:25 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:55733 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752337AbdI0Xca (ORCPT ); Wed, 27 Sep 2017 19:32:30 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 9D5FCAD2EE; Wed, 27 Sep 2017 19:32:30 -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=lBHG F9kq+O43en3ax/C47X51v4Y=; b=uUOY5dtlxp/IFzJFD86ZhNBqrGedXuQ6OtqE PiK7KJ2g1uS0myX7SOTDkHZ72enVuS4fduPG8V8gyH1J11ILrNrb9RGshr1s9pDr ixnyAcJg6Iha0OC7CG1Kj9wjQl0iKK9XJleZjQCBOROpKMbaIDG9qtp+uJTPzewx DDb8rlk= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 93AF0AD2ED; Wed, 27 Sep 2017 19:32:30 -0400 (EDT) Received: from yoda.home (unknown [137.175.234.45]) (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 F3860AD2EB; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id E18462DA0467; Wed, 27 Sep 2017 19:32:28 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro , linux-mm@kvack.org Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH v4 1/5] cramfs: direct memory access support Date: Wed, 27 Sep 2017 19:32:20 -0400 Message-Id: <20170927233224.31676-2-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170927233224.31676-1-nicolas.pitre@linaro.org> References: <20170927233224.31676-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 2103EA00-A3DC-11E7-A5CF-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 Tested-by: Chris Brandt --- fs/cramfs/Kconfig | 29 +++++- fs/cramfs/inode.c | 264 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 241 insertions(+), 52 deletions(-) -- 2.9.5 diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index 11b29d491b..5b4e0b7e13 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,31 @@ 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..19f464a214 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 Wed Sep 27 23:32:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 114379 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp60522qgf; Wed, 27 Sep 2017 16:32:36 -0700 (PDT) X-Google-Smtp-Source: AOwi7QBD64XtJuQbLbP5r7H92lgnlsWTt+pXCSFVtxtTZwGsf84cwP3Zt7RhPaSBD6ohwe8OBdHR X-Received: by 10.101.91.66 with SMTP id y2mr2636564pgr.235.1506555156404; Wed, 27 Sep 2017 16:32:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506555156; cv=none; d=google.com; s=arc-20160816; b=iPuC+Uxd1goDtDPTDa81qHsjB8w9u3n5gkJ7fq+u7+squRGBGQ1lg5X9Vs1Ps25nRS mq6PVlD3Y0IaTSQmZL3yk0+BiyhS5OdYz4b4IE/+ndgcHL0Ed4AFGYDbhlQAiV+qe1cj apF3uIOZb7xfg32HkgljobR7Sc5jyBdchHuWaUAtY6BUSRoUE3U6xSfgQyoGVBJvGVMX Y9dotKiOl3wQInIdr7mFvJBUrO64k+Kk2ZlCXVlbRODNgP7NlA+BBAQ0fb0LZhGCxFxY KS8LC7At5iZixG3jI0YskCW29qob6Qf/b+e1y54VZ4ABmb85FSrm2cEODkBMkLZNL6Hc iOdA== 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=vQq6HgG2FkLYF9vt5KJBPtbzwngLGnbD/fyWZ6cncgk=; b=dEM39Uip4OT07p0FiJS/1kSJ/JCGBlYuGBQZmHo3FUIyElLTQG5ZjdMuNVdm5+s0GS Ug+lZw2YXVkU0QBRQCCW0PuYNwV5JydgvfxaHxxbZ8WU1JFmMoBmv2p5mwpuCGSk9fKB hWaRNuQWrtCJMABsDQW1RsdsSqgcSJYj70hb4XwDlPIVyX2kppUqN66fiV0MMXV3HnMF /+1qlQioDvp7SwmYZoRCTKJBC3o3bF7kOivjk4EkWOLDO6Zxrr8L0cQqUYmCMcGzTYVG jvx5F0Z9Y2m/6/L/qipH1knHjLoMj/2HG3oa08ML7pe2IaS78+BInuJDGhHuGQXvfR95 5PKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=ZkvLvEk7; 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 h184si87799pge.571.2017.09.27.16.32.36; Wed, 27 Sep 2017 16:32:36 -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=ZkvLvEk7; 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 S1752522AbdI0Xcd (ORCPT + 26 others); Wed, 27 Sep 2017 19:32:33 -0400 Received: from pb-smtp1.pobox.com ([64.147.108.70]:62192 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752288AbdI0Xca (ORCPT ); Wed, 27 Sep 2017 19:32:30 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 3DF3C9954F; Wed, 27 Sep 2017 19:32:30 -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=pul/ bqJBGIDrZnZxuDK2tIvPQU0=; b=ZkvLvEk72hgRn/Rwm0iSq+8BFoJkd6PUx52K gtogYpIq4jNuM/7jnVn9u20XSEsfPOYy4h3zckHqi/jCX1m4jfFAqtNMsrteERCs 0p1eCoDZvBIVRzse+zKu2bppOvGF+B3OWCGggsukxA0gUarfhKVLZP+FiXS12WWK IT/DS3Y= Received: from pb-smtp1.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 34C399954E; Wed, 27 Sep 2017 19:32:30 -0400 (EDT) Received: from yoda.home (unknown [137.175.234.45]) (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 A5F0099548; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id F3FD22DA046A; Wed, 27 Sep 2017 19:32:28 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro , linux-mm@kvack.org Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH v4 2/5] cramfs: make cramfs_physmem usable as root fs Date: Wed, 27 Sep 2017 19:32:21 -0400 Message-Id: <20170927233224.31676-3-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170927233224.31676-1-nicolas.pitre@linaro.org> References: <20170927233224.31676-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 20D40F6A-A3DC-11E7-9EBA-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 Signed-off-by: Nicolas Pitre Tested-by: Chris Brandt --- init/do_mounts.c | 8 ++++++++ 1 file changed, 8 insertions(+) -- 2.9.5 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 Wed Sep 27 23:32:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 114382 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp61283qgf; Wed, 27 Sep 2017 16:33:38 -0700 (PDT) X-Google-Smtp-Source: AOwi7QB+PBGkd0aqExafoE/Xn4EH/UfclC8axb1pYxKAfcVgLEhTMinjsnanf3Ps2sWkqrwXgYQd X-Received: by 10.99.42.79 with SMTP id q76mr2567227pgq.66.1506555218391; Wed, 27 Sep 2017 16:33:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506555218; cv=none; d=google.com; s=arc-20160816; b=OrHQsIQbbyVpQGhDnIqgZCLmQYzBvoQywkXwtc05R6IaiG9tbuv2gtrBwUiIU8e9W/ prPeuZtiwMj3JJVnI3NPilxUfUtcnZU8A9f/qIIGvZnDsyFYcR+08Xr5V38jRsFCKZn7 NGVD/vZxlu2QTTUlar+50Y19Lo0nLC6XywVCHTrpM1cLZXFBPcIP+Lr3MtufadS+doeG PwZws31EfixwfWWurwU7Wj5b7XEx6/FdkSBTRdSnmaPTUkjce91PkTxX7BafOkg0RpOW QxNZ+0p09vwLHKiNRqJVYJSkKJvdFy1R6aTRSqJRDp5eopBWX0FbcNQM5QHPSHkI9JuS MOEA== 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=3cGj8IPWquyxLq6tfRNx9QJpllcigRJVzEZ4RZY3CFc=; b=qrI4oQo5Q0e+mQD+p/u5ew0FTRDnThpTYKwvVnBMhevAi8ypW2+Xo/D0+4rprvltcv 51ipAvUPDhvLWOq+ac+jvtgelT2tJz/CWdbKn4aUiCx0bOaqDGAjUE8vkMOkSCJ9aFoZ /axqcKvMPlyYboBA5dxgv1U5m/CNTmx11S3FxZA9s70SSiYDd9qvO3RYe6eaS9oUrGi9 AgeZSt7NpvEhf0wyjWCyvJnizcLVE2BG93X7PHkIBTBLOOGE4m7pQEmKk7fCZH2rYhPA +CQF63lK3IsfRIZmaNTO/bvP9qXxjxZHUmUSPcARibzOgQHYj9qXMpV6+3OIuVfas67b 4iJg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=A0a12WKi; 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 a18si102672pfk.150.2017.09.27.16.33.38; Wed, 27 Sep 2017 16:33:38 -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=A0a12WKi; 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 S1752619AbdI0XdY (ORCPT + 26 others); Wed, 27 Sep 2017 19:33:24 -0400 Received: from pb-smtp1.pobox.com ([64.147.108.70]:57636 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752341AbdI0Xcb (ORCPT ); Wed, 27 Sep 2017 19:32:31 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 5FA3799552; Wed, 27 Sep 2017 19:32:30 -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=DyZW P+9OI+EA8zRKj1WKI8aEkhY=; b=A0a12WKiyEakKJ2rt6Sc0qZ1dlPRnYUCJmWy 09ujJGLzqQSv8YCLz4YZv/RT75vlTznFoXEqep6YtbXBFCTwD9DOR0rZ+IMeWtrm yMaE0SgwQiChyE1IRa+cDTZZQKux8diWwSpd6nRNlovOJLTd2bbXlfiOmrshdH/M 5Gyh750= Received: from pb-smtp1.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 54A9099551; Wed, 27 Sep 2017 19:32:30 -0400 (EDT) Received: from yoda.home (unknown [137.175.234.45]) (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 BA03099549; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 1EC062DA05DA; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro , linux-mm@kvack.org Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH v4 3/5] cramfs: implement uncompressed and arbitrary data block positioning Date: Wed, 27 Sep 2017 19:32:22 -0400 Message-Id: <20170927233224.31676-4-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170927233224.31676-1-nicolas.pitre@linaro.org> References: <20170927233224.31676-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 20E072F0-A3DC-11E7-A954-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 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 Tested-by: Chris Brandt --- 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.5 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 19f464a214..2fc886092b 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..c7a7883fab 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 Wed Sep 27 23:32:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 114383 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp61457qgf; Wed, 27 Sep 2017 16:33:52 -0700 (PDT) X-Google-Smtp-Source: AOwi7QDCz7RsbCPYjKRwjqyPieL1nBXUAC6lCLbIhQ66fL5NNuSxKcKQjrWeLAvVOjNgEISBmqS6 X-Received: by 10.99.3.216 with SMTP id 207mr2586413pgd.15.1506555232220; Wed, 27 Sep 2017 16:33:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506555232; cv=none; d=google.com; s=arc-20160816; b=c9H6cdajSN0V4jzjwcYoE2GpLIuKBCJn0dlKik6WzUzlcZ4xH/M3/TWnChW40d5+Oj YLeljcoZ0m5Pfynm1qVMtPRhua7T/T6ZSkFuJBbnWmd1GZItSofSAmsTiPzp890bax9T OaxdY2+xpd6uVlDb6NZn+mc9ZJYvqEzy0TwtePi/NNI2AHKWAR1VVv0yVvoY/Jj+3x4t lh40wcVYlY/uapFmoJg8hmUdfPlnjMCM6p6BomGHoq342REOsX7z1QS6I0ZD227wqvNw J6XuupRAuBaXCbqLK5wq74/ES/XJU/Yly2ClaXriFgpHmDTyZPBy39stb4Qava01t7y/ 0T0Q== 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=9CxxbiRE2o1ixBbspkW6d1ORYdnNghmAeO9+IsOoWc4=; b=zSKbNj532WunK5vdfYe4SJjDV9LsLDKOWonzqqLqPJKQyuJexF+FA032bbv6KzHZic 4XPtXZxhp+QQiA4hA8yxyT1IEn8upX45OTOExs5MMLdPBtNQIyxMEz7dD5S3eYKnvnVo zYHucF7ReIohBOZZErnnCl4Yb6s6oGkitkHOOYOyAvze7Y/JBlK+NjA2c6QhgkMiyC6U nMIAW/gBHMSQmlSeT2RdJ+iZ6jhMTvHIO4KpUlSYwOZAaByBMwwK1FKIbgWdeKeiBJ8l a19iN5LMxNbn6o4Wdl1Dz8TceBw/KvOmppeQKswp2NHguR9ve1Gxj+Qu4S16o8uNxub7 O3eg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=Gd+NL0Z8; 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 y187si104444pgb.132.2017.09.27.16.33.51; Wed, 27 Sep 2017 16:33:52 -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=Gd+NL0Z8; 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 S1752603AbdI0XdX (ORCPT + 26 others); Wed, 27 Sep 2017 19:33:23 -0400 Received: from pb-smtp2.pobox.com ([64.147.108.71]:63030 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752357AbdI0Xcb (ORCPT ); Wed, 27 Sep 2017 19:32:31 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 09E07AD2F1; Wed, 27 Sep 2017 19:32:31 -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=dt4a 6Iq/z2MDXTSnyJBy6MMLnoE=; b=Gd+NL0Z8DuxiI4sYvJupRgO/tU4mw41Uz0Yf o5WtxmHXjlqKimrNRZ+NEVOupFXtBKLXgPde85Sa9SPpdwchAsRAVRfWNLNxcLsh 33RtrbiN8ly4Aw4Xp2EV8HYPo4pV1+Z0NUi7zJDTo7/jexobyJ45S40jffbrvEHq Ysh2wM4= Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 00498AD2F0; Wed, 27 Sep 2017 19:32:31 -0400 (EDT) Received: from yoda.home (unknown [137.175.234.45]) (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 44B45AD2EC; Wed, 27 Sep 2017 19:32:30 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 2C4952DA0679; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro , linux-mm@kvack.org Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH v4 4/5] cramfs: add mmap support Date: Wed, 27 Sep 2017 19:32:23 -0400 Message-Id: <20170927233224.31676-5-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170927233224.31676-1-nicolas.pitre@linaro.org> References: <20170927233224.31676-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 212FA3AC-A3DC-11E7-9B7F-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 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. In the MMU case it may happen for a vma structure to extend beyond the actual file size. This is notably the case in binfmt_elf.c:elf_map(). Or the file's last block is shared with other files and cannot be mapped as is. Rather than refusing to mmap it, we do a partial map and set up a special vm_ops fault handler that splits the vma in two: the direct mapping vma and the memory-backed vma populated by the readpage method. In practice the unmapped area is seldom accessed so the split might never occur before this area is discarded. In the non-MMU case it is the get_unmapped_area method that is responsible for providing the address where the actual data can be found. No mapping is necessary of course. Signed-off-by: Nicolas Pitre Tested-by: Chris Brandt --- fs/cramfs/Kconfig | 2 +- fs/cramfs/inode.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+), 1 deletion(-) -- 2.9.5 Signed-off-by: Nicolas Pitre Tested-by: Chris Brandt diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index 5b4e0b7e13..306549be25 100644 --- a/fs/cramfs/Kconfig +++ b/fs/cramfs/Kconfig @@ -30,7 +30,7 @@ config CRAMFS_BLOCKDEV config CRAMFS_PHYSMEM bool "Support CramFs image directly mapped in physical memory" - depends on CRAMFS + depends on CRAMFS = y default y if !CRAMFS_BLOCKDEV help This option allows the CramFs driver to load data directly from diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 2fc886092b..1d7d61354b 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include #include #include @@ -49,6 +51,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 +99,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 +284,294 @@ 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 and number of + * valid blocks for which that is true, 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; + if (blockptrs[i] != expect) { + pr_debug("range: block %d/%d got %#x expects %#x\n", + pgoff+i, pgoff+*pages-1, blockptrs[i], expect); + if (i == 0) + return 0; + break; + } + } while (++i < *pages); + + *pages = i; + + /* stored "direct" block ptrs are shifted down by 2 bits */ + return blockaddr << 2; +} + +/* + * It is possible for cramfs_physmem_mmap() to partially populate the mapping + * causing page faults in the unmapped area. When that happens, we need to + * split the vma so that the unmapped area gets its own vma that can be backed + * with actual memory pages and loaded normally. This is necessary because + * remap_pfn_range() overwrites vma->vm_pgoff with the pfn and filemap_fault() + * no longer works with it. Furthermore this makes /proc/x/maps right. + * Q: is there a way to do split vma at mmap() time? + */ +static const struct vm_operations_struct cramfs_vmasplit_ops; +static int cramfs_vmasplit_fault(struct vm_fault *vmf) +{ + struct mm_struct *mm = vmf->vma->vm_mm; + struct vm_area_struct *vma, *new_vma; + struct file *vma_file = get_file(vmf->vma->vm_file); + unsigned long split_val, split_addr; + unsigned int split_pgoff; + int ret; + + /* We have some vma surgery to do and need the write lock. */ + up_read(&mm->mmap_sem); + if (down_write_killable(&mm->mmap_sem)) { + fput(vma_file); + return VM_FAULT_RETRY; + } + + /* Make sure the vma didn't change between the locks */ + ret = VM_FAULT_SIGSEGV; + vma = find_vma(mm, vmf->address); + if (!vma) + goto out_fput; + + /* + * Someone else might have raced with us and handled the fault, + * changed the vma, etc. If so let it go back to user space and + * fault again if necessary. + */ + ret = VM_FAULT_NOPAGE; + if (vma->vm_ops != &cramfs_vmasplit_ops || vma->vm_file != vma_file) + goto out_fput; + fput(vma_file); + + /* Retrieve the vma split address and validate it */ + split_val = (unsigned long)vma->vm_private_data; + split_pgoff = split_val & 0xfff; + split_addr = (split_val >> 12) << PAGE_SHIFT; + if (split_addr < vma->vm_start) { + /* bottom of vma was unmapped */ + split_pgoff += (vma->vm_start - split_addr) >> PAGE_SHIFT; + split_addr = vma->vm_start; + } + pr_debug("fault: addr=%#lx vma=%#lx-%#lx split=%#lx\n", + vmf->address, vma->vm_start, vma->vm_end, split_addr); + ret = VM_FAULT_SIGSEGV; + if (!split_val || split_addr > vmf->address || vma->vm_end <= vmf->address) + goto out; + + if (unlikely(vma->vm_start == split_addr)) { + /* nothing to split */ + new_vma = vma; + } else { + /* Split away the directly mapped area */ + ret = VM_FAULT_OOM; + if (split_vma(mm, vma, split_addr, 0) != 0) + goto out; + + /* The direct vma should no longer ever fault */ + vma->vm_ops = NULL; + + /* Retrieve the new vma covering the unmapped area */ + new_vma = find_vma(mm, split_addr); + BUG_ON(new_vma == vma); + ret = VM_FAULT_SIGSEGV; + if (!new_vma) + goto out; + } + + /* + * Readjust the new vma with the actual file based pgoff and + * process the fault normally on it. + */ + new_vma->vm_pgoff = split_pgoff; + new_vma->vm_ops = &generic_file_vm_ops; + new_vma->vm_flags &= ~(VM_IO | VM_PFNMAP | VM_DONTEXPAND); + vmf->vma = new_vma; + vmf->pgoff = split_pgoff; + vmf->pgoff += (vmf->address - new_vma->vm_start) >> PAGE_SHIFT; + downgrade_write(&mm->mmap_sem); + return filemap_fault(vmf); + +out_fput: + fput(vma_file); +out: + downgrade_write(&mm->mmap_sem); + return ret; +} + +static const struct vm_operations_struct cramfs_vmasplit_ops = { + .fault = cramfs_vmasplit_fault, +}; + +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, vma_pages, max_pages, offset; + unsigned long 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; + + /* Could COW work here? */ + fail_reason = "vma is writable"; + if (vma->vm_flags & VM_WRITE) + goto fail; + + vma_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE - 1) >> PAGE_SHIFT; + max_pages = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + fail_reason = "beyond file limit"; + if (vma->vm_pgoff >= max_pages) + goto fail; + pages = vma_pages; + if (pages > max_pages - vma->vm_pgoff) + pages = max_pages - vma->vm_pgoff; + + 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 the last 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 += (max_pages - 1) * PAGE_SIZE + partial; + while ((unsigned long)data & 7) + if (*data++ != 0) + goto nonzero; + while (offset_in_page(data)) { + if (*(u64 *)data != 0) { + nonzero: + pr_debug("mmap: %s: last page is shared\n", + file_dentry(file)->d_name.name); + pages--; + break; + } + data += 8; + } + } + } + + if (pages) { + /* + * If we can't map it all, page faults will occur if the + * unmapped area is accessed. Let's handle them to split the + * vma and let the normal paging machinery take care of the + * rest through cramfs_readpage(). Because remap_pfn_range() + * repurposes vma->vm_pgoff, we have to save it somewhere. + * Let's use vma->vm_private_data to hold both the pgoff and + * the actual address split point. Maximum file size is 16MB + * (12 bits pgoff) and max 20 bits pfn where a long is 32 bits + * so we can pack both together. + */ + if (pages != vma_pages) { + unsigned int split_pgoff = vma->vm_pgoff + pages; + unsigned long split_pfn = (vma->vm_start >> PAGE_SHIFT) + pages; + unsigned long split_val = split_pgoff | (split_pfn << 12); + vma->vm_private_data = (void *)split_val; + vma->vm_ops = &cramfs_vmasplit_ops; + /* to keep remap_pfn_range() happy */ + vma->vm_end = vma->vm_start + pages * PAGE_SIZE; + } + + ret = remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT, + pages * PAGE_SIZE, vma->vm_page_prot); + /* restore vm_end in case we cheated it above */ + vma->vm_end = vma->vm_start + vma_pages * PAGE_SIZE; + if (ret) + return ret; + + pr_debug("mapped %s at 0x%08lx (%u/%u pages) to vma 0x%08lx, " + "page_prot 0x%llx\n", file_dentry(file)->d_name.name, + address, pages, vma_pages, vma->vm_start, + (unsigned long long)pgprot_val(vma->vm_page_prot)); + return 0; + } + fail_reason = "no suitable block remaining"; + +fail: + pr_debug("%s: direct mmap failed: %s\n", + file_dentry(file)->d_name.name, fail_reason); + + /* We failed to do a direct map, but normal paging will do it */ + vma->vm_ops = &generic_file_vm_ops; + 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, block_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; + block_pages = pages; + offset = cramfs_get_block_range(inode, pgoff, &block_pages); + if (!offset || block_pages != pages) + 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 Wed Sep 27 23:32:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 114384 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp61620qgf; Wed, 27 Sep 2017 16:34:06 -0700 (PDT) X-Google-Smtp-Source: AOwi7QCjgK33k+Hww8DaPPMt+n8Ualnt2H2NTe8x6b2IfUEzFkt7AVpIRBHauPjfGpeOou1tzpLi X-Received: by 10.159.252.11 with SMTP id n11mr2487799pls.18.1506555245995; Wed, 27 Sep 2017 16:34:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506555245; cv=none; d=google.com; s=arc-20160816; b=MFGw0ri228QTsgRjnb371mmT8rrKnpLnI4/zv+EfBPZAmIzyvYoWpqFI25h6Ut36Gt q8YDYyVMugMgF22uPAAU6tgz3NQwlFVfyyuZWB9ONvmJ37pMQ9D//yJ5WWSxvJPuaCRM f4L72WSES1jHTl9MGG18Kx2ipjmXSjyLvg+GaDt+V9bmLT622XzIdKxe9/lZeZxXPoPt wdU+glFouT0E3jMSCN8s93EeVAYO81KChscbpaJx5CXZNrFy44wfdZSEO9aLXgm+7kbh Z8ybuKrqsFGbZHYwhwEq7NMtUG+upL3Slt6Fvdc3rArFTAw5RsoxP6uRYdPYiKtHaiT5 U45A== 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=XY/5p/pFXe6mEqJTQNcF255ewV2V2SFbENTZi0o14Qk=; b=iB8/+TecKHoNRv7WbLh/0u/mwvz7NiubeNMepzvc3Z8L68Pa3Sv0exK/+D5lXill4a SjDHZXxk38XQff3sexb0wAJ7WUMLqjFefJwcayKWJxEFa7YZ1nUgs6IX50HnznvZgvfe Z8sBfJytuaFFp+pZhfCNW2eGwe1wrp2Svp5XmPxfQp81WuVeexxTR90e7IJluc8eqMHk RjJZm1CO8/TKoPkpzUGuYk5++bAhVVeC4gpI1ms1KWlVo+JkxpzPhKE4JGE+2/8MYsXZ qCNjvXktmtH9DEjGZ+GWtkElRC1C9UfBiAAkhMYtRIqTFSxHniPb1xbRkuVZRP52p9tC hLgA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pobox.com header.s=sasl header.b=C6ApFkkg; 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 y187si104444pgb.132.2017.09.27.16.34.05; Wed, 27 Sep 2017 16:34:05 -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=C6ApFkkg; 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 S1752578AbdI0XdV (ORCPT + 26 others); Wed, 27 Sep 2017 19:33:21 -0400 Received: from pb-smtp1.pobox.com ([64.147.108.70]:51906 "EHLO sasl.smtp.pobox.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752375AbdI0Xcb (ORCPT ); Wed, 27 Sep 2017 19:32:31 -0400 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 124D499558; Wed, 27 Sep 2017 19:32:31 -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=J09e yu5zqSU2SgX8vLT3VCXRDsE=; b=C6ApFkkg/goiDvyhvH/prRSl9z/dokm0xL9F kVrWIkms/njdF6T5S3DsLqjBMK3F2zgBJgAAhcUdHZU0m2aHns4epNnvdVIvQHc8 qLcFXmcK9CeJ6HwkOMFxA3nSqtfMh2Mpkx8T9z6LR8R8zoYS/tiHoEudSW0Cxst/ Ox0QOjc= Received: from pb-smtp1.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp1.pobox.com (Postfix) with ESMTP id 082DA99557; Wed, 27 Sep 2017 19:32:31 -0400 (EDT) Received: from yoda.home (unknown [137.175.234.45]) (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 64D3799553; Wed, 27 Sep 2017 19:32:30 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 419CB2DA0695; Wed, 27 Sep 2017 19:32:29 -0400 (EDT) From: Nicolas Pitre To: Alexander Viro , linux-mm@kvack.org Cc: linux-fsdevel@vger.kernel.org, linux-embedded@vger.kernel.org, linux-kernel@vger.kernel.org, Chris Brandt Subject: [PATCH v4 5/5] cramfs: rehabilitate it Date: Wed, 27 Sep 2017 19:32:24 -0400 Message-Id: <20170927233224.31676-6-nicolas.pitre@linaro.org> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20170927233224.31676-1-nicolas.pitre@linaro.org> References: <20170927233224.31676-1-nicolas.pitre@linaro.org> X-Pobox-Relay-ID: 2143FCB2-A3DC-11E7-89C8-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 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 Tested-by: Chris Brandt --- Documentation/filesystems/cramfs.txt | 42 ++++++++++++++++++++++++++++++++++++ MAINTAINERS | 4 ++-- fs/cramfs/Kconfig | 9 +++++--- 3 files changed, 50 insertions(+), 5 deletions(-) -- 2.9.5 diff --git a/Documentation/filesystems/cramfs.txt b/Documentation/filesystems/cramfs.txt index 4006298f67..8875d306bc 100644 --- a/Documentation/filesystems/cramfs.txt +++ b/Documentation/filesystems/cramfs.txt @@ -45,6 +45,48 @@ 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, if the physical address +of the cramfs image is 0x80100000, the following command would mount it +on /mnt: + +$ mount -t cramfs_physmem -o physaddr=0x80100000 none /mnt + +To boot such an image as the root filesystem, the following kernel +commandline parameters must be provided: + + "rootfstype=cramfs_physmem rootflags=physaddr=0x80100000" + + +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 1c3feffb1c..f00aec6a66 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 306549be25..374d52e029 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.