From patchwork Sun Jul 23 12:07:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Fabio M. De Francesco" X-Patchwork-Id: 13323170 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 164ABC001B0 for ; Sun, 23 Jul 2023 12:07:30 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 60A2B6B0075; Sun, 23 Jul 2023 08:07:29 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 5BA756B0078; Sun, 23 Jul 2023 08:07:29 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4A8C86B007B; Sun, 23 Jul 2023 08:07:29 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 3ABF66B0075 for ; Sun, 23 Jul 2023 08:07:29 -0400 (EDT) Received: from smtpin09.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 09048A06E5 for ; Sun, 23 Jul 2023 12:07:29 +0000 (UTC) X-FDA: 81042751818.09.90CFFFA Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) by imf11.hostedemail.com (Postfix) with ESMTP id 2932D40007 for ; Sun, 23 Jul 2023 12:07:26 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=gmail.com header.s=20221208 header.b=UIcw8SNV; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf11.hostedemail.com: domain of fmdefrancesco@gmail.com designates 209.85.221.41 as permitted sender) smtp.mailfrom=fmdefrancesco@gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1690114047; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:references:dkim-signature; bh=jl9V448+HS+kG3h9U9ABN+uxksHk7/M2t2kRQ8frCBs=; b=NYJnEAR8Zb8Kbx3PXgwQ5FM6XXUychvFoCATIXT699zAkCkdM0wL4Nq8jzitYT7G1HnYhu Vgzmnv06fOgWPmvcyDzFUFRwk4AllSFfOygSq3MgzeGKshqzB68CKscJSv1vWQqlFJ75+F yhZ/Ht9iRCr64zQU5REIp+4B7wuBi+E= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=gmail.com header.s=20221208 header.b=UIcw8SNV; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (imf11.hostedemail.com: domain of fmdefrancesco@gmail.com designates 209.85.221.41 as permitted sender) smtp.mailfrom=fmdefrancesco@gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1690114047; a=rsa-sha256; cv=none; b=SQoNqC3305M+xyphwWLvtP087YF3kjNJI0OYYTyJ+u6k2FYeRlABZJnDoyErgX9j5/G+WZ 6QTUATohuPUU6TcazdCj83jx3mDILFoILm0uL/Q6IKQyTaUXE5s27Pi2HXF2esTpulwqZR EInfwZymM7l5vfhMLB0Ows5zA63QOgs= Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-31758eb5db8so376342f8f.2 for ; Sun, 23 Jul 2023 05:07:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1690114046; x=1690718846; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=jl9V448+HS+kG3h9U9ABN+uxksHk7/M2t2kRQ8frCBs=; b=UIcw8SNVSuvAizgs+6pAOn52gjXAnE/Wo4f9U3j9CIBWYFii4zlC7K53bRhNhvzq1N u2wY9sjM+3S9L27Q1E1tSoY1VEG+t3jLiq47prFi7X3j2SnDGzuV51Qmm/DlRA8dPew6 s4Icsi6AEwfW/nCNWOI5CGlecEQ3AQXJ+FCl5ldV/6cWzHX4Xy5pQ08Xuxr7YwFpcBXi zpLQoB1CbYy5XeEb/6IMx23rqxvzvVmSkyzq7x23gA1jITU7Hjp/Urox+v01q2SiVwWv kp+xFVdT5u49BBbe0DkWTFxDZXcgxqzAIObU+ly4CLVtsBVCUcHzRsEFyKPnGc+YqZ94 PNCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690114046; x=1690718846; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=jl9V448+HS+kG3h9U9ABN+uxksHk7/M2t2kRQ8frCBs=; b=dqvRu8QVJlU/ELlfBdlX/7W/TGQ23FMWejs4RlIdvY/glgpdfPKG5VDwznVFIW64AW VEI68FU6nVsYIc0nL7d0vCkG+K8hvN+I5Vov+voutOEVKfCA+aDR2mMo49KiB40VScNR eV61XZJy8FSg25WkiJSdqTjGUdJAgR4aDz0oqVP9uuNV5qjhZz5/nuqYq4nB02+Wz4Uc N+oyhVYJdOb5CgiHjn8osdQQyNQ/sHm+fSgHqw/rzwAHr5wAlZL2IVezUDfTsz42YVKV BBYEdOe3yMVXhH/oHHjss0eygyDUPS2pxSfj2b45tQOUUDUz1bpWqfplWPSJA04NcXYw Xy4w== X-Gm-Message-State: ABy/qLYAsRg81eAP1VaCYMHFJliB3RTuTL8327HvoYA0kiUcTstKbxg8 QbIx7Q+ao41/zhIExwTpJ9I= X-Google-Smtp-Source: APBJJlFJro/px5/72ampeOL2FhDNqs+UnxZgEBaBGjzVp/kUGIjSa1//DlV/GjH3QxXt8C8wZa15wA== X-Received: by 2002:a5d:4dd2:0:b0:314:3ca0:c8c2 with SMTP id f18-20020a5d4dd2000000b003143ca0c8c2mr6078555wru.11.1690114045420; Sun, 23 Jul 2023 05:07:25 -0700 (PDT) Received: from localhost.localdomain (host-87-20-104-222.retail.telecomitalia.it. [87.20.104.222]) by smtp.gmail.com with ESMTPSA id v4-20020adff684000000b0031431fb40fasm9511466wrp.89.2023.07.23.05.07.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Jul 2023 05:07:24 -0700 (PDT) From: "Fabio M. De Francesco" To: Jonathan Corbet , "Fabio M. De Francesco" , Jonathan Cameron , Linus Walleij , Mike Rapoport , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org Cc: Andrew Morton , Bagas Sanjaya , Ira Weiny , Matthew Wilcox , Randy Dunlap Subject: [RFC PATCH v2] Documentation/page_tables: Add info about MMU/TLB and Page Faults Date: Sun, 23 Jul 2023 14:07:09 +0200 Message-ID: <20230723120721.7139-1-fmdefrancesco@gmail.com> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: 2932D40007 X-Stat-Signature: 9hgc11m3whwsz6yc3n38zmk855bwdaap X-HE-Tag: 1690114046-858265 X-HE-Meta: U2FsdGVkX1+D9DzUaDd/8C9/PStDtSv+qDqZSKflG9YjI0U+vO48QKeQz3o0dOpInvel7j8u0xScXMdRaQRzLbY3AFmq0OvoW5yuPL4mSQ2YtQJfovO9r/1jhdBgTHWNiPFZx6i9Lk0Oox1m9R/tyiA/7nD+9OUNU1A+k80h2ARwKu7jRUcv5mB8XwooNyejLZt+IDVf1rUmrSIbX2Oa29uxQxBnlFHVQ+XJixhj7KCjOcH0gXW9M2avVwrBMUVNsx1hAD4hy9a4pFa2ZSKenDhBtvdbjCZuUH0XtyH3h8JE+SSt+CK8QmGt9iriS2Ip3RuKByzptt/ZetRGEcBgnsZx/Lf54Xkrj2RtXSw0STakjTMoLfxOQkk0Xy/BGQzkIvRqLqU1ScYsvC+zg4nO2YMHQ7ksCvtDkfNol/tGXdWclGGRtb5ooSqA046lckzPRGaHxj12g/7ydnD8mFw8A7WLjTBKrIN33ZxeWuASNSvTFZzMhNwvPcS7G6GYbQjup2IWtKdiyOFJhBKzONp5DCg2oE4Sy55yxHgsNhgM5cJN2jXIWSQZB/7yOsV9hwC/zhVV82z2LwIialJQtezNejC9uhcmzALTjB18Ae9h5WxgjXn+vH3P6pgpRmfdqTV9bcbwY4IB32Qh0KJmZOiPkK6XeKQv/bSkQTJmbWdqDEV5NrOu02tL/FTlJ9NWI8WnNswZMy41LCprM+LIRSG0eBDDeA1Pnz0Qob+MEBWGj5NDe+SqpivSp6BUVlmgLPQhVd2jBp2nGmpp2XLkNpHZkWdbu5JA/s7falTWsoEVZqso3XVc2tSS/5qBVI18LPgS3RTgDSI/O12XSsQxoBm+gvdcXzb9QOxoS0ddJndNQy47ThfbgWiV+lHpxYuh/Cgx8QH1DBU2gEC0wxL6scyBeJ7OC/2MhQffz+BON6XNruCxEY3fByLCglUKvuj/UWW1RGLoDk+OCpyaMwivr5t Wd0S9nUU tgXKtwgQ39wzyWEt0obCvEAjbtQg/UVTjA4J2eX51ogiuwxbWqbjbuXSBh4ESI7CG7qGqw210DtCfVdbIWkf+zIa9ePWqWP6lV0/e9bII6NG/wBnCaLJaaHpbmeS+8tHYcZSnKfvEQnCytX10t4voPUStrkWoVRxe7mUVvWMMTb9AlGfx7IahDZVNjcT0IiWU2INpCRrt/0qB5qEd52SYAIAAdlqN9vn5AAisI97L0XBaFj93wHAuhhxkyHQ2Q5fQUJTtb8Vv64ICvivyk2DzmdgLoIV/11yj3YvRsXV2ZWCGEcKuSv2orshZBnAJEzziIY5I0+hSfOtG9ADDcjLqgZEPMUibsVmV83ZFdEkZ8ZPdEnnKD3il+isxk53N5kMBs1r57/5UKea6lvcI5LsyzRCxgyr2R/8iUZppBOgaTQVtpW2SWhvWyOplhqTftdiGD185jPFdVRR56ke3c3z42CEW+eUT0DCWE+UOIAC5z9P0JqODU82U/98moQLY6OeDHn0QFS04smYt7xSAY9HyLiZBfaihb6QFlAa/33Y/GlviOgpIBDz5Vz1pJz5P6jT2FdafuRQ0C6NfVPO9WG4QQKwg+xN3n/NQFyorhVuDGOzhbHfsq4JqCSm2mpKqCjnNj9ZqDKndj3fhzyfw3VtfiizEGotyj4OCJYqIjmxGadXGs3+vOtyioI9I4cCbJUZhrQ641PtBfJXi6HI2fqV3orXl8Jpm0BJUdabaYPgzxDZ5ow8ys33rUx2B6sj/n23Gdwqxl5Y1HBZP4+czm3L0eydGp+E1RWGU3XUJaFQ0VNOZ/L5FQ3Exo1SyNWbZpnC0V/Z0vsug0mFT29o= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Extend page_tables.rst by adding a section about the role of MMU and TLB in translating between virtual addresses and physical page frames. Furthermore explain the concept behind Page Faults and how the Linux kernel handles TLB misses. Finally briefly explain how and why to disable the page faults handler. Cc: Andrew Morton Cc: Bagas Sanjaya Cc: Ira Weiny Cc: Jonathan Cameron Cc: Jonathan Corbet Cc: Linus Walleij Cc: Matthew Wilcox Cc: Mike Rapoport Cc: Randy Dunlap Signed-off-by: Fabio M. De Francesco --- v1->v2: Add further information about lower level functions in the page fault handler and add information about how and why to disable / enable the page fault handler (provided a link to a Ira's patch that make use of pagefault_disable() to prevent deadlocks). This is an RFC PATCH because of two reasons: 1) I've heard that there is consensus about the need to revise and extend the MM documentation, but I'm not sure about whether or not developers need these kind of introductory information. 2) While preparing this little patch I decided to take a quicj look at the code and found out it currently is not how I thought I remembered it. I'm especially speaking about the x86 case. I'm not sure that I've been able to properly understand what I described as a difference in workflow compared to most of the other architecture. Therefore, for the two reasons explained above, I'd like to hear from people actively involved in MM. If this is not what you want, feel free to throw it away. Otherwise I'd be happy to write more on this and other MM topics. I'm looking forward for comments on this small work. Documentation/mm/page_tables.rst | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/Documentation/mm/page_tables.rst b/Documentation/mm/page_tables.rst index 7840c1891751..2be56f50c88f 100644 --- a/Documentation/mm/page_tables.rst +++ b/Documentation/mm/page_tables.rst @@ -152,3 +152,90 @@ Page table handling code that wishes to be architecture-neutral, such as the virtual memory manager, will need to be written so that it traverses all of the currently five levels. This style should also be preferred for architecture-specific code, so as to be robust to future changes. + + +MMU, TLB, and Page Faults +========================= + +The Memory Management Unit (MMU) is a hardware component that handles virtual to +physical address translations. It uses a relatively small cache in hardware +called the Translation Lookaside Buffer (TLB) to speed up these translations. +When a process wants to access a memory location, the CPU provides a virtual +address to the MMU, which then uses the TLB to quickly find the corresponding +physical address. + +However, sometimes the MMU can't find a valid translation in the TLB. This +could be because the process is trying to access a range of memory that it's not +allowed to, or because the memory hasn't been loaded into RAM yet. When this +happens, the MMU triggers a page fault, which is a type of interrupt that +signals the CPU to pause the current process and run a special function to +handle the fault. + +One cause of page faults is due to bugs (or maliciously crafted addresses) and +happens when a process tries to access a range of memory that it doesn't have +permission to. This could be because the memory is reserved for the kernel or +for another process, or because the process is trying to write to a read-only +section of memory. When this happens, the kernel sends a Segmentation Fault +(SIGSEGV) signal to the process, which usually causes the process to terminate. + +An expected and more common cause of page faults is "lazy allocation". This is +a technique used by the Kernel to improve memory efficiency and reduce +footprint. Instead of allocating physical memory to a process as soon as it's +requested, the kernel waits until the process actually tries to use the memory. +This can save a significant amount of memory in cases where a process requests +a large block but only uses a small portion of it. + +A related technique is "Copy-on-Write" (COW), where the Kernel allows multiple +processes to share the same physical memory as long as they're only reading +from it. If a process tries to write to the shared memory, the kernel triggers +a page fault and allocates a separate copy of the memory for the process. This +allows the kernel to save memory and avoid unnecessary data copying and, by +doing so, it reduces latency. + +Now, let's see how the Linux kernel handles these page faults: + +1. For most architectures, `do_page_fault()` is the primary interrupt handler + for page faults. It delegates the actual handling of the page fault to + `handle_mm_fault()`. This function checks the cause of the page fault and + takes the appropriate action, such as loading the required page into + memory, granting the process the necessary permissions, or sending a + SIGSEGV signal to the process. + +2. In the specific case of the x86 architecture, the interrupt handler is + defined by the `DEFINE_IDTENTRY_RAW_ERRORCODE()` macro, which calls + `handle_page_fault()`. This function then calls either + `do_user_addr_fault()` or `do_kern_addr_fault()`, depending on whether + the fault occurred in user space or kernel space. Both of these functions + eventually lead to `handle_mm_fault()`, similar to the workflow in other + architectures. + +`handle_mm_fault()` (likely) ends up calling `__handle_mm_fault()` to carry +out the actual work of allocation of the page tables. It works by using +several functions to find the entry's offsets of the 4 - 5 layers of tables +and allocate the tables it needs to. The functions that look for the offset +have names like `*_offset()`, where the "*" is for pgd, p4d, pud, pmd, pte; +instead the functions to allocate the corresponding tables, layer by layer, +are named `*_alloc`, with the above mentioned convention to name them after +the corresponding types of tables in the hierarchy. + +At the very end of the walk with allocations, if it didn't return errors, +`__handle_mm_fault()` finally calls `handle_pte_fault()`, which via +`do_fault()` performs one of `do_read_fault()`, `do_cow_fault()`, +`do_shared_fault()`. "read", "cow", "shared" give hints about the reasons +and the kind of fault it's handling. + +The actual implementation of the workflow is very complex. Its design allows +Linux to handle page faults in a way that is tailored to the specific +characteristics of each architecture, while still sharing a common overall +structure. + +To conclude this brief overview from very high altitude of how Linux handles +page faults, let's add that page faults handler can be disabled and enabled +respectively with `pagefault_disable()` and `pagefault_enable()`. + +Several code path make use of the latter two functions because they need to +disable traps into the page faults handler, mostly to prevent deadlocks.[1] + +[1] mm/userfaultfd: Replace kmap/kmap_atomic() with kmap_local_page() +https://lore.kernel.org/all/20221025220136.2366143-1-ira.weiny@intel.com/ +