From patchwork Tue Aug 15 04:10:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 9900883 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3D706602C9 for ; Tue, 15 Aug 2017 04:10:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2FB9922AFC for ; Tue, 15 Aug 2017 04:10:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 24855285F7; Tue, 15 Aug 2017 04:10:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,RCVD_IN_SORBS_SPAM autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94F042866B for ; Tue, 15 Aug 2017 04:10:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752226AbdHOEKM (ORCPT ); Tue, 15 Aug 2017 00:10:12 -0400 Received: from mail-io0-f181.google.com ([209.85.223.181]:33877 "EHLO mail-io0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751850AbdHOEKK (ORCPT ); Tue, 15 Aug 2017 00:10:10 -0400 Received: by mail-io0-f181.google.com with SMTP id o9so619390iod.1 for ; Mon, 14 Aug 2017 21:10:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:in-reply-to:message-id:references :user-agent:mime-version; bh=T7EJXDwkdav6pOocjgN3uVAdGfr5yg5Eh6Z9jukm6Jo=; b=PJDo/wgjKdU+Dp1MK65egQTl177qnt7ksTuab2DxzBiH7Azi793YiKNDW+ySNBgFgD XJ4V2TN961sCLDR3LZDP4lUbOOBkKL17hBaElkRu43pJ+Ye2+1x44fmKg0iB/2MIhXk2 NzklxFHDvQgfn4sMBTif133CuWwZo4L3rt3xE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version; bh=T7EJXDwkdav6pOocjgN3uVAdGfr5yg5Eh6Z9jukm6Jo=; b=pHwOxBJMOlZJtqt/yrUdq60JXjiKIN8PxGIAzAneY0h8xZ1l6w5lToKzAy5CDD0dJk YU2pg7c3lwJ6LYkNfO3YSAFMPCR/UNZ62rH0ggsnCUt7dLzvscCYMJpTQwp7lJeFlnS4 uYe6gka3lrim3A3WbgQLGzcer9w0oq25Gt5i1zwHNAS/ZZX2KwCwXqCDwquoirCeYk1C 4OMx1D8ueMOXyl4Oqkjq9fIT4gYP+vDe3zQSAGnz/pYgDTdE3hRj//6fK26pQRiRh4i7 7IxW8a92UOXDEVSoUnD+0vP/3b9n48OlZ5plXTTNpf9nFMwotfQ0QLy9FO7oaLcJA4vX Ccmw== X-Gm-Message-State: AHYfb5jQ+2Sg5WQc+2iER38TfNAyv7GKDcAxdX3htyffoc89Sj1BEag8 E1WJLqnQMRlTFnFg X-Received: by 10.107.189.7 with SMTP id n7mr21229195iof.36.1502770209880; Mon, 14 Aug 2017 21:10:09 -0700 (PDT) Received: from xanadu.home (modemcable065.157-23-96.mc.videotron.ca. [96.23.157.65]) by smtp.gmail.com with ESMTPSA id w6sm478711itb.2.2017.08.14.21.10.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 14 Aug 2017 21:10:09 -0700 (PDT) Date: Tue, 15 Aug 2017 00:10:08 -0400 (EDT) From: Nicolas Pitre To: Chris Brandt cc: Alexander Viro , "linux-fsdevel@vger.kernel.org" , "linux-embedded@vger.kernel.org" , "linux-kernel@vger.kernel.org" Subject: RE: [PATCH 0/5] cramfs refresh for embedded usage In-Reply-To: Message-ID: References: <20170811192252.19062-1-nicolas.pitre@linaro.org> User-Agent: Alpine 2.20 (LFD 67 2015-01-07) MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Mon, 14 Aug 2017, Chris Brandt wrote: > On Monday, August 14, 2017, Nicolas Pitre wrote: > > > However, now with your mkcramfs tool, I can no longer mount my cramfs > > > image as the rootfs on boot. I was able to do that before (ie, 30 > > minutes > > > ago) when using the community mkcramfs (ie, 30 minutes ago). > > > > > > I get this: > > > > > > [ 1.712425] cramfs: checking physical address 0x1b000000 for linear > > cramfs image > > > [ 1.720531] cramfs: linear cramfs image appears to be 15744 KB in > > size > > > [ 1.728656] VFS: Mounted root (cramfs_physmem filesystem) readonly on > > device 0:12. > > > [ 1.737062] devtmpfs: mounted > > > [ 1.741139] Freeing unused kernel memory: 48K > > > [ 1.745545] This architecture does not have kernel memory protection. > > > [ 1.760381] Starting init: /sbin/init exists but couldn't execute it > > (error -22) > > > [ 1.769685] Starting init: /bin/sh exists but couldn't execute it > > (error -14) > > > > Is /sbin/init a link to busybox? > > Yes. > > > > I suppose it just boots if you do mkcramfs without -X? > > Correct. I just created another image and removed the "-X -X" when > creating it. Now I can boot that image as my rootfs. > (I'm using -X -X because I'm using a Cortex-A9 with MMU). > > > > If so could you share your non-working cramfs image with me? > > I will send it (in a separate email) I was able to reproduce. The following patch on top should partially fix it. I'm trying to figure out how to split a vma and link it properly in the case the vma cannot be mapped entirely. In the mean time shared libs won't be XIP. diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 5aedbd224e..4c7f01fcd2 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -285,10 +285,10 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, /* * 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. + * 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) +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); @@ -306,11 +306,16 @@ static u32 cramfs_get_block_range(struct inode *inode, u32 pgoff, u32 pages) 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); + 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; @@ -321,8 +326,8 @@ 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; + unsigned int pages, vma_pages, max_pages, offset; + unsigned long address; char *fail_reason; int ret; @@ -332,17 +337,20 @@ static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma) if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) return -EINVAL; - vma->vm_ops = &generic_file_vm_ops; + fail_reason = "vma is writable"; if (vma->vm_flags & VM_WRITE) - return 0; + goto fail; - length = vma->vm_end - vma->vm_start; - pages = (length + PAGE_SIZE - 1) >> PAGE_SHIFT; + vma_pages = (vma->vm_end - vma->vm_start + 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; + 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); + offset = cramfs_get_block_range(inode, vma->vm_pgoff, &pages); fail_reason = "unsuitable block layout"; if (!offset) goto fail; @@ -351,37 +359,60 @@ static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma) if (!PAGE_ALIGNED(address)) goto fail; - /* Don't map a partial page if it contains some other data */ + /* 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 += (pages - 1) * PAGE_SIZE + partial; - fail_reason = "last partial page is shared"; while ((unsigned long)data & 7) if (*data++ != 0) - goto fail; + goto nonzero; while (offset_in_page(data)) { - if (*(u64 *)data != 0) - goto fail; + if (*(u64 *)data != 0) { + nonzero: + pr_debug("mmap: %s: last page is shared\n", + file_dentry(file)->d_name.name); + pages--; + break; + } 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, " + + if (pages) { + /* + * Split the vma if we can't map it all so normal paging + * will take care of the rest through cramfs_readpage(). + */ + if (pages != vma_pages) { + if (1) { + fail_reason = "fix me"; + goto fail; + } + ret = split_vma(vma->vm_mm, vma, + vma->vm_start + pages * PAGE_SIZE, 0); + if (ret) + return ret; + } + + ret = remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT, + pages * PAGE_SIZE, vma->vm_page_prot); + 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, length, vma->vm_start, + address, pages, vma_pages, 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); + vma->vm_ops = &generic_file_vm_ops; return 0; } @@ -394,14 +425,15 @@ static unsigned long cramfs_physmem_get_unmapped_area(struct file *file, 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 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; - offset = cramfs_get_block_range(inode, pgoff, pages); - if (!offset) + 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",