Received: by 2002:ab2:6857:0:b0:1ef:ffd0:ce49 with SMTP id l23csp484788lqp; Thu, 21 Mar 2024 07:11:59 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXVKbECToQn0lMNLTxLIesZx0nNEV5tMx1f+zKKQP1iw0KT5jbM0sewOwkMzddjwgeXgsXO34vhGwtcxo+H8Q2SBdl7LVVNi82K6NMOJA== X-Google-Smtp-Source: AGHT+IFe1bFihpXLSv6j6vwxQQBdxyeXru2GKbtLxa9Ce6pFZIjOsTDDtuz02tCmKklEAiKSCQpW X-Received: by 2002:a05:6214:2a87:b0:690:d9f3:7585 with SMTP id jr7-20020a0562142a8700b00690d9f37585mr4007808qvb.21.1711030318926; Thu, 21 Mar 2024 07:11:58 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1711030318; cv=pass; d=google.com; s=arc-20160816; b=fYWGqKC2phgXwu8arpRNnQzxo9MsuBq+fKTJaXYz7EydCUT6xuI6O/4vXh7IdBI0pC Lrhx32kowh3Sbk0NIBh5A+7GYAcDLrMALqDzZXmdaxwIlw8L/cdN5fA4LTonfLSpJyNM dhw9ndj9E6i3t7wuNu3k7dTDyjPnRprylrDYc3CWb25fuYh4bSpyAufNncZZQ9VpY2IU 5ERy6brkEjVKM+cxH/GVNGu/2ghhxgkefidthpLkcUVB14QsCPmscCMLcJm9DGw1Txcc rfhcxn/Vp3/Vtz/Fpbc5RGLu8ebMEXu0qBybMEMImnjXVtN4M3NtaHT76jzDZsbCW3nC P6dQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:list-unsubscribe:list-subscribe :list-id:precedence:dkim-signature; bh=ck4TkMLqNJOKAoGnoaiXGuXYDSdMyWKTEEYgwReH5mM=; fh=dWWYMCwLVBUNJ4u+pmWvKSNzVnx4m//1cSKsLn1BoP8=; b=yN8XJdKjJElx9spsMGjSS+YVfCfK6iDN070Q1p2h4oPsGG8lbZUZ9gjzl6GIONvrq0 n6hVltTNkBxuzcfoMbrtZkocQnP9WFOcPKULZOyD4gx2rgImTi6Wi9L/dUneBA5gn1Yd fzLsK4Y5K4ptz4OIl7Bn6hSFl7qV+IIlB0G/z77GWs2YC5g3CfCDAI/npeP/UKvWTHgF jXXL0CK/xo4xLbcGf/bfDlBUplin3G1p59yWHDdzNnYK/Z538p1m2f0AeLXNBOIqUqML 1RWUsa/CNkEH76m5HVP+8NXQmFygob8z8bqPj+cy3FezJATvgmaubui/J6s9kAzo00kE UCsA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=pDDvbZRT; arc=pass (i=1 spf=pass spfdomain=google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-110125-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-110125-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id ey3-20020a0562140b6300b00690be4c0571si16709503qvb.186.2024.03.21.07.11.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Mar 2024 07:11:58 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-110125-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=pDDvbZRT; arc=pass (i=1 spf=pass spfdomain=google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-110125-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-110125-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 940291C20B30 for ; Thu, 21 Mar 2024 14:11:58 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 96DF184FD8; Thu, 21 Mar 2024 14:11:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pDDvbZRT" Received: from mail-qt1-f182.google.com (mail-qt1-f182.google.com [209.85.160.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3A1984A5A for ; Thu, 21 Mar 2024 14:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.182 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711030309; cv=none; b=DD4hoa2ULZyajvR6C5d0ws91KMsoKEo5tvyDDmqL0Aqi72M+VpXHo7rB+8wWWEcbiQpWpW9gx/cUWHb7YtrodIjczlhTisGGLUDt93R609/RWsYdksbdoLtxkrKWHE2fdiJSP8zDGCXRrWs374JZJnDTlgZQ5dKRsB5qQkMb/1s= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711030309; c=relaxed/simple; bh=3B+X67e3QFN64speoGIjrADStYrLAT5tuVafIoMIefY=; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject: To:Cc:Content-Type; b=O/DmWyV0NGy+ey0aqk6dfuCivxWRxd6kEFZ+z3yiVZ5vksFVIbrC/zsZjFmJ0J+i1PeX4r29WqjNrRFT7FtcXESyTDLJl2Xzn3BU1MhvDf4bTZZnkUoykOt2hU4F72iB/NmnLl//F2dt5cZCceb/Yzzf+WvGbIZO2IKDLsz4iuQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pDDvbZRT; arc=none smtp.client-ip=209.85.160.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Received: by mail-qt1-f182.google.com with SMTP id d75a77b69052e-430baec7bb5so18972341cf.0 for ; Thu, 21 Mar 2024 07:11:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1711030307; x=1711635107; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=ck4TkMLqNJOKAoGnoaiXGuXYDSdMyWKTEEYgwReH5mM=; b=pDDvbZRTKvrF+tfVPggq4ntsQZE2jbNnObJIs+v1rvnetHoDpNVDnHxFnivcjZayDX VMsj8dQbRljoYeiedWeeHwUwPz34xYJOENGjp/NJRPyhRFads0QqOVsrq2z4OPRat8e2 srJSEglkXvPAy+TMq+JAYgB8h1RwlDo0npkCjKefT540TAJGAhLTFfxI6NP4UeLyy0Yn p3BH4+MbMnoInKswx5R0CVMaYMCbXDUJqbIBO5/nemqCTkitoL7s9ANpcfqCN89jMAoi fdZzS8wqQguFnqcv3HmE2XK4874NoKNQgbhXeDA53geVImWR4EQ80KRhupnDUZcC43Es vCDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711030307; x=1711635107; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ck4TkMLqNJOKAoGnoaiXGuXYDSdMyWKTEEYgwReH5mM=; b=ogSl9GLSUlTT7C62jtB7MF5pzyJpxfAz2Rbpo5NO+ZPU1NixmqtTP/zT6/po4qh3nm yvUGg+FSnapKafPReMb6WZeHRR7tAAXmoKcq3WkOA2woR4R+KqNaJCLxZBCj5dsiqJ6p J3IJYchQDgnMh+9bicMSOBWE7cxMOkNCSTwYn4VV8imYi9R6lERDVOXyArKcHf6u5cnB rBm9oCcEUgQnaG+5AvLf6A0JsOGJw1+wWXe4ZyxfOtWuFUGCLKUQPkBv2F0LTpiPwXFn kLRKGraC4bFVDBBhcOe715H7KWK6Ivreqsan+gPeO7L5wCzD02VXrlLq+1SoEqKWl4wu kPEA== X-Forwarded-Encrypted: i=1; AJvYcCVOkdwEsNYrLeQRtIh830rz9pQ6NfGtTEe3POZU0NioApQbX+INNrj9BHH4gW68eMWal3fexarXZFLxtBE9wnvzU5bsl4bAo17WCmGf X-Gm-Message-State: AOJu0YzJrLKKueN9GVBKb78P7PfopfEc9muMl0NjTCpF4Qxrxb1oUGMP Gsc8kHiVR0RqNgv/7pQwQ5WOkP2Tac+Zh8DIEKly//ANBi8aviTcBR7uFP7QGKuyJg1AX9x2ybu 46BIsR7SLRVhpYnKEPODSEUN55tACued3xIi5 X-Received: by 2002:a05:620a:4509:b0:78a:2d35:3071 with SMTP id t9-20020a05620a450900b0078a2d353071mr3931578qkp.38.1711030306353; Thu, 21 Mar 2024 07:11:46 -0700 (PDT) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 References: <20240320084630.2727355-1-aliceryhl@google.com> <9ed03148-5ceb-40f2-9c2d-31e2b8918888@proton.me> In-Reply-To: From: Alice Ryhl Date: Thu, 21 Mar 2024 15:11:35 +0100 Message-ID: Subject: Re: [PATCH v3 4/4] rust: add abstraction for `struct page` To: Benno Lossin Cc: a.hindborg@samsung.com, akpm@linux-foundation.org, alex.gaynor@gmail.com, arnd@arndb.de, arve@android.com, bjorn3_gh@protonmail.com, boqun.feng@gmail.com, brauner@kernel.org, cmllamas@google.com, gary@garyguo.net, gregkh@linuxfoundation.org, joel@joelfernandes.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, maco@android.com, ojeda@kernel.org, rust-for-linux@vger.kernel.org, surenb@google.com, tkjos@android.com, viro@zeniv.linux.org.uk, wedsonaf@gmail.com, willy@infradead.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Mar 21, 2024 at 2:56=E2=80=AFPM Benno Lossin wrote: > > On 3/21/24 14:42, Alice Ryhl wrote: > > On Thu, Mar 21, 2024 at 2:16=E2=80=AFPM Benno Lossin wrote: > >> > >> On 3/20/24 09:46, Alice Ryhl wrote: > >>>> On 3/11/24 11:47, Alice Ryhl wrote: > >>>>> +/// A pointer to a page that owns the page allocation. > >>>>> +/// > >>>>> +/// # Invariants > >>>>> +/// > >>>>> +/// The pointer points at a page, and has ownership over the page. > >>>> > >>>> Why not "`page` is valid"? > >>>> Do you mean by ownership of the page that `page` has ownership of th= e > >>>> allocation, or does that entail any other property/privilege? > >>> > >>> I can add "at a valid page". > >> > >> I don't think that helps, what you need as an invariant is that the > >> pointer is valid. > > > > To me "points at a page" implies that the pointer is valid. I mean, if > > it was dangling, it would not point at a page? > > > > But I can reword to something else if you have a preferred phrasing. > > I would just say "`page` is valid" or "`self.page` is valid". > > >>>>> + /// Runs a piece of code with this page mapped to an address. > >>>>> + /// > >>>>> + /// The page is unmapped when this call returns. > >>>>> + /// > >>>>> + /// It is up to the caller to use the provided raw pointer cor= rectly. > >>>> > >>>> This says nothing about what 'correctly' means. What I gathered from= the > >>>> implementation is that the supplied pointer is valid for the executi= on > >>>> of `f` for `PAGE_SIZE` bytes. > >>>> What other things are you allowed to rely upon? > >>>> > >>>> Is it really OK for this function to be called from multiple threads= ? > >>>> Could that not result in the same page being mapped multiple times? = If > >>>> that is fine, what about potential data races when two threads write= to > >>>> the pointer given to `f`? > >>>> > >>>>> + pub fn with_page_mapped(&self, f: impl FnOnce(*mut u8) -> T= ) -> T { > >>> > >>> I will say: > >>> > >>> /// It is up to the caller to use the provided raw pointer correctly. > >>> /// The pointer is valid for `PAGE_SIZE` bytes and for the duration i= n > >>> /// which the closure is called. Depending on the gfp flags and kerne= l > >>> /// configuration, the pointer may only be mapped on the current thre= ad, > >>> /// and in those cases, dereferencing it on other threads is UB. Othe= r > >>> /// than that, the usual rules for dereferencing a raw pointer apply. > >>> /// (E.g., don't cause data races, the memory may be uninitialized, a= nd > >>> /// so on.) > >> > >> I would simplify and drop "depending on the gfp flags and kernel..." a= nd > >> just say that the pointer is only valid on the current thread. > > > > Sure, that works for me. > > > >> Also would it make sense to make the pointer type *mut [u8; PAGE_SIZE]= ? > > > > I think it's a trade-off. That makes the code more error-prone, since > > `pointer::add` now doesn't move by a number of bytes, but a number of > > pages. > > Yeah. As long as you document that the pointer is valid for r/w with > offsets in `0..PAGE_SIZE` bytes, leaving the type as is, is fine by me. > > > >>> It's okay to map it multiple times from different threads. > >> > >> Do you still need to take care of data races? > >> So would it be fine to execute this code on two threads in parallel? > >> > >> static PAGE: Page =3D ...; // assume we have a page accessible b= y both threads > >> > >> PAGE.with_page_mapped(|ptr| { > >> loop { > >> unsafe { ptr.write(0) }; > >> pr_info!("{}", unsafe { ptr.read() }); > >> } > >> }); > > > > Like I said, the usual pointer rules apply. Two threads can access it > > in parallel as long as one of the following are satisfied: > > > > * Both accesses are reads. > > * Both accesses are atomic. > > * They access disjoint byte ranges. > > > > Other than the fact that it uses a thread-local mapping on machines > > that can't address all of their memory at the same time, it's > > completely normal memory. It's literally just a PAGE_SIZE-aligned > > allocation of PAGE_SIZE bytes. > > Thanks for the info, what do you think of this?: > > /// It is up to the caller to use the provided raw pointer correctly. The= pointer is valid for reads > /// and writes for `PAGE_SIZE` bytes and for the duration in which the cl= osure is called. The > /// pointer must only be used on the current thread. The caller must also= ensure that no data races > /// occur: when mapping the same page on two threads accesses to memory w= ith the same offset must be > /// synchronized. I would much rather phrase it in terms of "the usual pointer" rules. I mean, the memory could also be uninitialized if you don't pass __GFP_ZERO when you create it, so you also have to make sure to follow the rules about uninitialized memory. I don't want to be in the business of listing all requirements for accessing memory here. > >> If this is not allowed, I don't really like the API. As a raw version = it > >> would be fine, but I think we should have a safer version (eg by takin= g > >> `&mut self`). > > > > I don't understand what you mean. It is the *most* raw API that `Page` > > has. I can make them private if you want me to. The API cannot take > > `&mut self` because I need to be able to unsafely perform concurrent > > writes to disjoint byte ranges. > > If you don't need these functions to be public, I think we should > definitely make them private. > Also we could add a `raw` suffix to the functions to make it clear that > it is a primitive API. If you think that it is highly unlikely that we > get a safer version, then I don't think there is value in adding the > suffix. The old code on the Rust branch didn't have these functions, but that's because the old `read_raw` and `write_raw` methods did all of these things directly in their implementation: * Map the memory so we can get a pointer. * Get a pointer to a subslice (with bounds checks!) * Do the actual read/write. I thought that doing this many things in a single function was convoluted, so I decided to refactor the code by extracting the "get a pointer to the page" logic into `with_page_mapped` and the "point to subslice with bounds check" logic into `with_pointer_into_page`. That way, each function has only one responsibility, instead of mixing three responsibilities into one. So even if we get a safer version, I would not want to get rid of this method. I don't want to inline its implementation into more complicated functions. The safer method would call the raw method, and then do whatever additional logic it wants to do on top of that. Alice