From patchwork Fri Dec 20 15:47:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Axboe X-Patchwork-Id: 13916939 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 E3870E7718B for ; Fri, 20 Dec 2024 15:48:59 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 9AB2F6B009A; Fri, 20 Dec 2024 10:48:50 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 95C8F6B009B; Fri, 20 Dec 2024 10:48:50 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 787A96B009C; Fri, 20 Dec 2024 10:48:50 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 54DB46B009A for ; Fri, 20 Dec 2024 10:48:50 -0500 (EST) Received: from smtpin20.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 131A2AF883 for ; Fri, 20 Dec 2024 15:48:50 +0000 (UTC) X-FDA: 82915767984.20.A9654ED Received: from mail-il1-f178.google.com (mail-il1-f178.google.com [209.85.166.178]) by imf18.hostedemail.com (Postfix) with ESMTP id 945391C0017 for ; Fri, 20 Dec 2024 15:48:31 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=kernel-dk.20230601.gappssmtp.com header.s=20230601 header.b=2eX0Oqxa; spf=pass (imf18.hostedemail.com: domain of axboe@kernel.dk designates 209.85.166.178 as permitted sender) smtp.mailfrom=axboe@kernel.dk; dmarc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1734709691; 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:in-reply-to:references:references:dkim-signature; bh=ks2mp2gCJ77yF3ZCGIs6WN32l2VaUGiu+2pglDT6eiI=; b=DEX9g5q7LaW+9yRq0XbDvucMqKDkc5AdnKVU3XbzWluIdhpCOg4n7A7pAt66QKZA7doSH/ jGejtPBAKNjY02qUhwaFZ6AIy0f798MuPKHdC8YxRp81F6u7rZ4D0oVbvlvYUetKYhK5eT JruCvV+F72t7a0IfN6wV6u/Lf9Dak10= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=kernel-dk.20230601.gappssmtp.com header.s=20230601 header.b=2eX0Oqxa; spf=pass (imf18.hostedemail.com: domain of axboe@kernel.dk designates 209.85.166.178 as permitted sender) smtp.mailfrom=axboe@kernel.dk; dmarc=none ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1734709691; a=rsa-sha256; cv=none; b=8aMgRONF5xNS1JKHX7k10jJf08BSyxJi8hLlaCOSCGtGPSqNk2eawqKfNAFuTgWF6bMJKo xneqhiQDgsgBgSxAxmX027dO2+wYVUCR19mnGeQ8THki5CUBJCAaBj07R8myTItpVGhiJs 5oE0mckC9ibnI8ISkdaeNxhPTwEBjq4= Received: by mail-il1-f178.google.com with SMTP id e9e14a558f8ab-3a78b39034dso6240935ab.3 for ; Fri, 20 Dec 2024 07:48:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel-dk.20230601.gappssmtp.com; s=20230601; t=1734709726; x=1735314526; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ks2mp2gCJ77yF3ZCGIs6WN32l2VaUGiu+2pglDT6eiI=; b=2eX0OqxafDINvG63AdrPljvfhsQ7cjr2teE9Er5bA4he+8NHVCDhS2vKSusfrd0x1l gI/gMVOADmj5qUdYcuhrQW02bwkD7WMdU1ggCIFYU1MoyppWiOb1VQKV19O+XyMopbuz OpNn0fVc6175cC1rB9eUdeE4IlPa1O2v6D67pTep6ZNbhPSQOiIqSYWAtYcxGJZPbHyS ePd96Eo/O80yomiitTxowUGPz0hlQDvq1rDA9GsDAWshCKW/yjZl+E4Lyej5Q1hBLcSF PrBRSCZXldPCrfm3mlGeE2sWvKnKiwgPbKJPHBuXBDn4LnnviZ9HRjoT4CrVIbES9XgS FKrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734709726; x=1735314526; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ks2mp2gCJ77yF3ZCGIs6WN32l2VaUGiu+2pglDT6eiI=; b=R0kwmPf+j86bRlVqtnNiHNKa7Q/WOxxTlTzjVEyeX/pRlaNfozk6QsrWEwixbTdi6p qq8gSAT65XmQ3296FDZqc8hTAYN//e9UVd1MPjpKVhVN449tKr0xdHpSGytgtrgFzuyg NJIsmgyK3J31GsTfdiv2hsgXimrKtKLRMTY6pTzHSn4z4SpgjZNspvBVPvl1sXnKX2xp 9WFOwn306zow9JRKyGQLbo/9PwEPcvfm2QwzNg1Me59wsA6BSxWZ6NOt8WwC3bDTLCzR UIcx68n8rUjciWDZziLgJZOyzbaG7tvqJHy4AHrUx49mBwCv8xAHBymkdIchYDxf8NLV f6+g== X-Gm-Message-State: AOJu0Yzr1Ug1SsDEE9B5xkKYzq6/0rg6/HYoJardPm9bXYYDNmuaGhUk HaD82u5+1OWYxvK+aB9YOVRFq1EAYhjZdCqwspcp//KChRclVbs/8reydXN5voqHV02cXrVsE/z t X-Gm-Gg: ASbGncuk3Y4OIpWN+h4+7xSAhbcjcL+WMt05LcM7JU6rv7OPlJ6hIwpf1g/kkHYKsLK IJZNST+1w02dASTjnKSbnZfQBGLhDo2//+zbES7ERfbYPssirppppAX9BToraksNfm6CBAyzfqQ rU7VFwJmOPWI1UdseJAhhRyTFD4B5WLQ7khekX13mo4HmLd1njLbDHFb3qxRXwTXVhh4fPlCR1A 1/gpMlApVhIhrsjO73FOLq/rrIwi0zpi3cUatrryAK77AHyP6itJFmJtd1n X-Google-Smtp-Source: AGHT+IG1Q5MpgKTbxJc/Yphg2SqFQXSKzJLSB4ruy07feq+/t9lmMQDAi0QHm0P3EjCYdC27xoRmeQ== X-Received: by 2002:a05:6e02:3201:b0:3a7:be5e:e22d with SMTP id e9e14a558f8ab-3c2d1aa3e86mr30848135ab.2.1734709725732; Fri, 20 Dec 2024 07:48:45 -0800 (PST) Received: from localhost.localdomain ([96.43.243.2]) by smtp.gmail.com with ESMTPSA id 8926c6da1cb9f-4e68bf66ed9sm837821173.45.2024.12.20.07.48.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2024 07:48:44 -0800 (PST) From: Jens Axboe To: linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: hannes@cmpxchg.org, clm@meta.com, linux-kernel@vger.kernel.org, willy@infradead.org, kirill@shutemov.name, bfoster@redhat.com, Jens Axboe Subject: [PATCH 08/12] mm/filemap: add read support for RWF_DONTCACHE Date: Fri, 20 Dec 2024 08:47:46 -0700 Message-ID: <20241220154831.1086649-9-axboe@kernel.dk> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241220154831.1086649-1-axboe@kernel.dk> References: <20241220154831.1086649-1-axboe@kernel.dk> MIME-Version: 1.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: 945391C0017 X-Rspam-User: X-Stat-Signature: cgy18wiwu9x7ncxpeytwdohtnk8mmnfi X-HE-Tag: 1734709711-625257 X-HE-Meta: U2FsdGVkX1/3ioBYfIwMAymCHmb7H3TV5dq6hp36EeXce/UbvX0v5IX0shOO7wSQcqKGTzR/JrM7cED7crPRxi3fdSpoQs5g854BWdMoofOequwPC/HZ/otxnKHoZhGZcQSURNYnPSIe/aZ9CDpfgnhfJHFC1geDbO4rHiIngQLNybPKq8XAyORwHRShDzs4Wd6TUYMbfvwpjIBwDaeinsVjqOAyYfMAdm8UFMsSfcVgrFTGtN464kPdJzepYPl1GtSMCwYq1iHKXlcpAcV4dw3fhVMFhEbasrB5J8hTZidVzZ0P/H8sMNgT2tmDUZNZAoe3IaKZ2ZtsIvO9a6yAo6xEAY5P/gxCP51aie76JRQI52YyC/f+zMKdR5ed2QFCUqwUXg1SkV5E4Q7Z3ei1fykcs2kOJNXEdSK9nn53GbisTsBgyy4CYFE/f1z1oXgAyaz2fbpKXqSMbSl5MyHthkzPFlqIW0aK2Ybiz+j0d3gFtggA2lq5Nvlf8HaXBoV99M6RF77bPJnVD06yPSs6yYhKUaYC1wpmCfF6EwnHmMmmj5TwXYxS9Q7A8k/tv/Il2Vpsw69OcLsrQevOXTMgRE3UQNwz+GJkqvb81PjswO4aHrmi+md/fKEG3imLL3YdH+vXKfbOUqbb9LAwyjF3nOOr9gUu+IT6I11CiNGeA8DStHn7DfvwQc6hwbtJTwq2Sa2tnxGC8JfFKvCigZxad+o63yPMap+llAmNwqssrswqhuZWHpefk5Qk1a5Roi/NmkgdN+nA3RfAumg0vovZPgc/PkkZUXhYF69pdNQSRttVEt0m2vOvTzWDjWsI8jvzNBA0M23+LyBnl5O6fIcTfBLgQuMtE6jqk5GPW8NjBILYry0RxlVmAJksWixxgLAv6+TWr4LN8RBeSVh58PV7yxpCJNtyctpOHhkwuFX5bMko7HwSed16U3JnuMoK7bUOu7dKPuguGOl6puiHJRe zmR0bRhF WOvc8RrQYTLGP1QaDWcRWwuWo6MkkT2dBkYfpHDLK8PGdxkugGJNH0GJWxZkQYCM0JWUnqJRJvEPsyKMsB78m5AZSjOTIvn2yEZqT6K9gXwd6oEFI8x7B4JO3tApxXCc5ryB76UaY9pBqvFt4RfnixIXnxUl9gs9UrmaEdIoBbV145o2yga4PqaHuomFpI22emgNVK9wIFfBHXPDg5cVHqVWrkeCGRccGAT94NdXVnursaDxdX3t7hCPpFvjOJOLtGtKU1W/0JBphKTdSjj7PggIj3rziDiBFogzv+VIWiAoLh88yLa8ISuVtwMGdtodWESiVz5Fv9hDEw4xjmgVyuylc1HelKs5C1sOf X-Bogosity: Ham, tests=bogofilter, spamicity=0.002999, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Add RWF_DONTCACHE as a read operation flag, which means that any data read wil be removed from the page cache upon completion. Uses the page cache to synchronize, and simply prunes folios that were instantiated when the operation completes. While it would be possible to use private pages for this, using the page cache as synchronization is handy for a variety of reasons: 1) No special truncate magic is needed 2) Async buffered reads need some place to serialize, using the page cache is a lot easier than writing extra code for this 3) The pruning cost is pretty reasonable and the code to support this is much simpler as a result. You can think of uncached buffered IO as being the much more attractive cousin of O_DIRECT - it has none of the restrictions of O_DIRECT. Yes, it will copy the data, but unlike regular buffered IO, it doesn't run into the unpredictability of the page cache in terms of reclaim. As an example, on a test box with 32 drives, reading them with buffered IO looks as follows: Reading bs 65536, uncached 0 1s: 145945MB/sec 2s: 158067MB/sec 3s: 157007MB/sec 4s: 148622MB/sec 5s: 118824MB/sec 6s: 70494MB/sec 7s: 41754MB/sec 8s: 90811MB/sec 9s: 92204MB/sec 10s: 95178MB/sec 11s: 95488MB/sec 12s: 95552MB/sec 13s: 96275MB/sec where it's quite easy to see where the page cache filled up, and performance went from good to erratic, and finally settles at a much lower rate. Looking at top while this is ongoing, we see: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 7535 root 20 0 267004 0 0 S 3199 0.0 8:40.65 uncached 3326 root 20 0 0 0 0 R 100.0 0.0 0:16.40 kswapd4 3327 root 20 0 0 0 0 R 100.0 0.0 0:17.22 kswapd5 3328 root 20 0 0 0 0 R 100.0 0.0 0:13.29 kswapd6 3332 root 20 0 0 0 0 R 100.0 0.0 0:11.11 kswapd10 3339 root 20 0 0 0 0 R 100.0 0.0 0:16.25 kswapd17 3348 root 20 0 0 0 0 R 100.0 0.0 0:16.40 kswapd26 3343 root 20 0 0 0 0 R 100.0 0.0 0:16.30 kswapd21 3344 root 20 0 0 0 0 R 100.0 0.0 0:11.92 kswapd22 3349 root 20 0 0 0 0 R 100.0 0.0 0:16.28 kswapd27 3352 root 20 0 0 0 0 R 99.7 0.0 0:11.89 kswapd30 3353 root 20 0 0 0 0 R 96.7 0.0 0:16.04 kswapd31 3329 root 20 0 0 0 0 R 96.4 0.0 0:11.41 kswapd7 3345 root 20 0 0 0 0 R 96.4 0.0 0:13.40 kswapd23 3330 root 20 0 0 0 0 S 91.1 0.0 0:08.28 kswapd8 3350 root 20 0 0 0 0 S 86.8 0.0 0:11.13 kswapd28 3325 root 20 0 0 0 0 S 76.3 0.0 0:07.43 kswapd3 3341 root 20 0 0 0 0 S 74.7 0.0 0:08.85 kswapd19 3334 root 20 0 0 0 0 S 71.7 0.0 0:10.04 kswapd12 3351 root 20 0 0 0 0 R 60.5 0.0 0:09.59 kswapd29 3323 root 20 0 0 0 0 R 57.6 0.0 0:11.50 kswapd1 [...] which is just showing a partial list of the 32 kswapd threads that are running mostly full tilt, burning ~28 full CPU cores. If the same test case is run with RWF_DONTCACHE set for the buffered read, the output looks as follows: Reading bs 65536, uncached 0 1s: 153144MB/sec 2s: 156760MB/sec 3s: 158110MB/sec 4s: 158009MB/sec 5s: 158043MB/sec 6s: 157638MB/sec 7s: 157999MB/sec 8s: 158024MB/sec 9s: 157764MB/sec 10s: 157477MB/sec 11s: 157417MB/sec 12s: 157455MB/sec 13s: 157233MB/sec 14s: 156692MB/sec which is just chugging along at ~155GB/sec of read performance. Looking at top, we see: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 7961 root 20 0 267004 0 0 S 3180 0.0 5:37.95 uncached 8024 axboe 20 0 14292 4096 0 R 1.0 0.0 0:00.13 top where just the test app is using CPU, no reclaim is taking place outside of the main thread. Not only is performance 65% better, it's also using half the CPU to do it. Signed-off-by: Jens Axboe --- mm/filemap.c | 28 ++++++++++++++++++++++++++-- mm/swap.c | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 220dc7c6e12f..dd563208d09d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2473,6 +2473,8 @@ static int filemap_create_folio(struct kiocb *iocb, struct folio_batch *fbatch) folio = filemap_alloc_folio(mapping_gfp_mask(mapping), min_order); if (!folio) return -ENOMEM; + if (iocb->ki_flags & IOCB_DONTCACHE) + __folio_set_dropbehind(folio); /* * Protect against truncate / hole punch. Grabbing invalidate_lock @@ -2518,6 +2520,8 @@ static int filemap_readahead(struct kiocb *iocb, struct file *file, if (iocb->ki_flags & IOCB_NOIO) return -EAGAIN; + if (iocb->ki_flags & IOCB_DONTCACHE) + ractl.dropbehind = 1; page_cache_async_ra(&ractl, folio, last_index - folio->index); return 0; } @@ -2547,6 +2551,8 @@ static int filemap_get_pages(struct kiocb *iocb, size_t count, return -EAGAIN; if (iocb->ki_flags & IOCB_NOWAIT) flags = memalloc_noio_save(); + if (iocb->ki_flags & IOCB_DONTCACHE) + ractl.dropbehind = 1; page_cache_sync_ra(&ractl, last_index - index); if (iocb->ki_flags & IOCB_NOWAIT) memalloc_noio_restore(flags); @@ -2594,6 +2600,20 @@ static inline bool pos_same_folio(loff_t pos1, loff_t pos2, struct folio *folio) return (pos1 >> shift == pos2 >> shift); } +static void filemap_end_dropbehind_read(struct address_space *mapping, + struct folio *folio) +{ + if (!folio_test_dropbehind(folio)) + return; + if (folio_test_writeback(folio) || folio_test_dirty(folio)) + return; + if (folio_trylock(folio)) { + if (folio_test_clear_dropbehind(folio)) + folio_unmap_invalidate(mapping, folio, 0); + folio_unlock(folio); + } +} + /** * filemap_read - Read data from the page cache. * @iocb: The iocb to read. @@ -2707,8 +2727,12 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, } } put_folios: - for (i = 0; i < folio_batch_count(&fbatch); i++) - folio_put(fbatch.folios[i]); + for (i = 0; i < folio_batch_count(&fbatch); i++) { + struct folio *folio = fbatch.folios[i]; + + filemap_end_dropbehind_read(mapping, folio); + folio_put(folio); + } folio_batch_init(&fbatch); } while (iov_iter_count(iter) && iocb->ki_pos < isize && !error); diff --git a/mm/swap.c b/mm/swap.c index 10decd9dffa1..ba02bd5ba145 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -427,6 +427,8 @@ static void folio_inc_refs(struct folio *folio) */ void folio_mark_accessed(struct folio *folio) { + if (folio_test_dropbehind(folio)) + return; if (lru_gen_enabled()) { folio_inc_refs(folio); return;