From patchwork Thu Jul 20 15:28:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 123362 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp3220682vqt; Thu, 20 Jul 2023 09:03:32 -0700 (PDT) X-Google-Smtp-Source: APBJJlGFJcBtspieM0n7tmYFmMpwTtlRH1M7xHmA5ZJR4vLCS7dqD4KC1idziIfNK+XAM0FjtyPp X-Received: by 2002:a05:6e02:1549:b0:346:7c6e:bfee with SMTP id j9-20020a056e02154900b003467c6ebfeemr7009752ilu.1.1689869012424; Thu, 20 Jul 2023 09:03:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689869012; cv=none; d=google.com; s=arc-20160816; b=Ptk0rXybfMpx6ejYo+RC2ktkxxxir/5qEBmz/1PSVyFbiHIbyp4fm8irfoctPACD0Q l0c+zxYnkLhmqBn8lkDhoMHFTpAkfWgwat5VEl67BJyBAwqD2iLINvahYNa1J1QhpDSJ h7o75GhlR1KqfjAFxOa7Cm5X6VdZcC5mW/s3C+npQ+um+HKHa0KbXpBb8i+WVSrWQvEf xPI5BfI8ttpOKh6cT7akJkmQRsJ2AauYDst9f/KAbiQ/IBm6xkQEcSDhBs+YM7zZx5kW hKkrXzkYhGK668OTYOl5TtKEAuLlTCKq5tksbOiV5+ELK9JV2/Tmw987rqtNXK97tIo1 CsXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=lGsQzpftUqu/kmuJWlaGnOlUm9YEsSfvHqOENO4D8dg=; fh=2LqnLdVG3GyJbD0LfV3BtPUIqKcLhppTyoV15Mfwi7k=; b=NhUN4GHgzzArHhgkQdCKj/yqJzKWBM7ui7jlHhi98xly7dLV1dQol5gGd4VBi59S69 XsvkdUjJGazASHr3F3wT6lgwHqEycWezph99h0HwX/0aAzFbcPMIkhuWvWrTgiKYc2x1 9rdHx9okvuZVKpip/maUpoU/8AfsxeIkML9B1nObwTdl5cFOciAgrLOKkVWUuKTUSkFH ULOYJ/3X3cmQmNMDKQv1TbX9QooU2BNxZhiOyyrM1OcsP31/dh15Wp7LQgJnec1IkpNl yoo1KLcQStWOpty/k7m6PGpsyq/Wc8Sl7rbaZY4m1Iqn0Ma+SGeyRrmyMb6GYUFjyKUU 3jZw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=HP4VC4yq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h4-20020a63e144000000b0054ff7740abfsi1036716pgk.482.2023.07.20.09.03.18; Thu, 20 Jul 2023 09:03:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=HP4VC4yq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232193AbjGTP3G (ORCPT + 99 others); Thu, 20 Jul 2023 11:29:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231478AbjGTP27 (ORCPT ); Thu, 20 Jul 2023 11:28:59 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ADD5126B5 for ; Thu, 20 Jul 2023 08:28:44 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-583312344e7so8686547b3.1 for ; Thu, 20 Jul 2023 08:28:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689866924; x=1690471724; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=lGsQzpftUqu/kmuJWlaGnOlUm9YEsSfvHqOENO4D8dg=; b=HP4VC4yqfpbodAzQdaIPQ4nHY72QwI4xzaASWFSHnM+kJ/oVIJABmevzS7L4fyYt6u uod2tSIWVsovjnMAekiIbWj5Z08qROuyF2g0iu38AQHdWLp9uc/DhQPw2D1NORvQj8rV uva0LfWOLN7B+LKRWA9IWsmwQn8i3ANXZTuq8sB2F2XUzy3s5QLK0dgKqtQUdemy1mOg aYhL5pHQM2Ass9pi9bb1Y6ghGFIr1a/fzbGO3QUOVVsPHCkKnNHGrrFyZ/1q8z8TitC2 WKQTAvs1luUmaoKYOZcHjv3dRyMXEE1AlN1K4jMm4difaM43OPe7/ud3XATXsI+YplQg ffNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689866924; x=1690471724; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=lGsQzpftUqu/kmuJWlaGnOlUm9YEsSfvHqOENO4D8dg=; b=fgmQeuU1+pkBtBf1jWEGJFuqv8PAWoZJAo2Kh6IsLoChUlU+zwaRLsb98kMjURgJsT ZZrBIUYJdwuRbBvg8R3GvfxFTPWDaWyY/OBP5iHkBUn6jlCjR6laI3UWflNNGHTwM3dJ O9IxLHEYqJGqKlAcv20zI8/Aaw7zccMni762k3vuTl3VHKENz3oB04cVnppNmxGq+dU8 kjF7D3Qs3ggVAWUCxAtrHUjfnc5OmidDGDJ0I/UhsXBwRANjvmB8uXjMpCLYgarNN5Nu dD8RjmAlb+67UvqXDJug9LG/3Tc50+hUsPnOKa7YFYOJg0ELJMN0K1Y9ksuQJNbH8qTl ZJMQ== X-Gm-Message-State: ABy/qLYjvMj4q4DAhW94FFcGTLxkzKyJIFbJCVEcof6LoWXbmRyznuSU UlDDgzdrnxa5+ZFBwjDykgJVluCwHKshmgM= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a25:ab0e:0:b0:cc5:c7d6:ae13 with SMTP id u14-20020a25ab0e000000b00cc5c7d6ae13mr45030ybi.5.1689866923961; Thu, 20 Jul 2023 08:28:43 -0700 (PDT) Date: Thu, 20 Jul 2023 15:28:16 +0000 In-Reply-To: <20230720152820.3566078-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230720152820.3566078-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230720152820.3566078-2-aliceryhl@google.com> Subject: [RFC PATCH v1 1/5] rust: file: add bindings for `struct file` From: Alice Ryhl To: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Miguel Ojeda , Alexander Viro , Christian Brauner Cc: Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho , Daniel Xu X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771956089273908806 X-GMAIL-MSGID: 1771956089273908806 From: Wedson Almeida Filho Using these bindings it becomes possible to access files from drivers written in Rust. This patch only adds support for accessing the flags, and for managing the refcount of the file. Signed-off-by: Wedson Almeida Filho Co-Developed-by: Daniel Xu Signed-off-by: Daniel Xu Co-Developed-by: Alice Ryhl Signed-off-by: Alice Ryhl --- In this patch, I am defining an error type called `BadFdError`. I'd like your thoughts on doing it this way vs just using the normal `Error` type. Pros: * The type system makes it clear that the function can only fail with EBADF, and that no other errors are possible. * Since the compiler knows that `ARef` cannot be null and that `BadFdError` has only one possible value, the return type of `File::from_fd` is represented as a pointer with null being an error. Cons: * Defining additional error types involves boilerplate. * The return type becomes a tagged union, making it larger than a pointer. * The question mark operator will only utilize the `From` trait once, which prevents you from using the question mark operator on `BadFdError` in methods that return some third error type that the kernel `Error` is convertible into. rust/bindings/bindings_helper.h | 2 + rust/helpers.c | 7 ++ rust/kernel/file.rs | 176 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 4 files changed, 186 insertions(+) create mode 100644 rust/kernel/file.rs diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs new file mode 100644 index 000000000000..99657adf2472 --- /dev/null +++ b/rust/kernel/file.rs @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Files and file descriptors. +//! +//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and +//! [`include/linux/file.h`](../../../../include/linux/file.h) + +use crate::{ + bindings, + error::{code::*, Error, Result}, + types::{ARef, AlwaysRefCounted, Opaque}, +}; +use core::ptr; + +/// Flags associated with a [`File`]. +pub mod flags { + /// File is opened in append mode. + pub const O_APPEND: u32 = bindings::O_APPEND; + + /// Signal-driven I/O is enabled. + pub const O_ASYNC: u32 = bindings::FASYNC; + + /// Close-on-exec flag is set. + pub const O_CLOEXEC: u32 = bindings::O_CLOEXEC; + + /// File was created if it didn't already exist. + pub const O_CREAT: u32 = bindings::O_CREAT; + + /// Direct I/O is enabled for this file. + pub const O_DIRECT: u32 = bindings::O_DIRECT; + + /// File must be a directory. + pub const O_DIRECTORY: u32 = bindings::O_DIRECTORY; + + /// Like [`O_SYNC`] except metadata is not synced. + pub const O_DSYNC: u32 = bindings::O_DSYNC; + + /// Ensure that this file is created with the `open(2)` call. + pub const O_EXCL: u32 = bindings::O_EXCL; + + /// Large file size enabled (`off64_t` over `off_t`). + pub const O_LARGEFILE: u32 = bindings::O_LARGEFILE; + + /// Do not update the file last access time. + pub const O_NOATIME: u32 = bindings::O_NOATIME; + + /// File should not be used as process's controlling terminal. + pub const O_NOCTTY: u32 = bindings::O_NOCTTY; + + /// If basename of path is a symbolic link, fail open. + pub const O_NOFOLLOW: u32 = bindings::O_NOFOLLOW; + + /// File is using nonblocking I/O. + pub const O_NONBLOCK: u32 = bindings::O_NONBLOCK; + + /// Also known as `O_NDELAY`. + /// + /// This is effectively the same flag as [`O_NONBLOCK`] on all architectures + /// except SPARC64. + pub const O_NDELAY: u32 = bindings::O_NDELAY; + + /// Used to obtain a path file descriptor. + pub const O_PATH: u32 = bindings::O_PATH; + + /// Write operations on this file will flush data and metadata. + pub const O_SYNC: u32 = bindings::O_SYNC; + + /// This file is an unnamed temporary regular file. + pub const O_TMPFILE: u32 = bindings::O_TMPFILE; + + /// File should be truncated to length 0. + pub const O_TRUNC: u32 = bindings::O_TRUNC; + + /// Bitmask for access mode flags. + /// + /// # Examples + /// + /// ``` + /// use kernel::file; + /// # fn do_something() {} + /// # let flags = 0; + /// if (flags & file::flags::O_ACCMODE) == file::flags::O_RDONLY { + /// do_something(); + /// } + /// ``` + pub const O_ACCMODE: u32 = bindings::O_ACCMODE; + + /// File is read only. + pub const O_RDONLY: u32 = bindings::O_RDONLY; + + /// File is write only. + pub const O_WRONLY: u32 = bindings::O_WRONLY; + + /// File can be both read and written. + pub const O_RDWR: u32 = bindings::O_RDWR; +} + +/// Wraps the kernel's `struct file`. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `get_file` ensures that the +/// allocation remains valid at least until the matching call to `fput`. +#[repr(transparent)] +pub struct File(Opaque); + +// SAFETY: By design, the only way to access a `File` is via an immutable reference or an `ARef`. +// This means that the only situation in which a `File` can be accessed mutably is when the +// refcount drops to zero and the destructor runs. It is safe for that to happen on any thread, so +// it is ok for this type to be `Send`. +unsafe impl Send for File {} + +// SAFETY: It's OK to access `File` through shared references from other threads because we're +// either accessing properties that don't change or that are properly synchronised by C code. +unsafe impl Sync for File {} + +impl File { + /// Constructs a new `struct file` wrapper from a file descriptor. + /// + /// The file descriptor belongs to the current process. + pub fn from_fd(fd: u32) -> Result, BadFdError> { + // SAFETY: FFI call, there are no requirements on `fd`. + let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(BadFdError)?; + + // SAFETY: `fget` increments the refcount before returning. + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } + + /// Creates a reference to a [`File`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` points at a valid file and that its refcount does not + /// reach zero until after the end of the lifetime 'a. + pub unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `File` type being transparent makes the cast ok. + unsafe { &*ptr.cast() } + } + + /// Returns the flags associated with the file. + /// + /// The flags are a combination of the constants in [`flags`]. + pub fn flags(&self) -> u32 { + // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. + // + // This uses a volatile read because C code may be modifying this field in parallel using + // non-atomic unsynchronized writes. This corresponds to how the C macro READ_ONCE is + // implemented. + unsafe { core::ptr::addr_of!((*self.0.get()).f_flags).read_volatile() } + } +} + +// SAFETY: The type invariants guarantee that `File` is always ref-counted. +unsafe impl AlwaysRefCounted for File { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_file(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. + unsafe { bindings::fput(obj.cast().as_ptr()) } + } +} + +/// Represents the EBADF error code. +/// +/// Used for methods that can only fail with EBADF. +pub struct BadFdError; + +impl From for Error { + fn from(_: BadFdError) -> Error { + EBADF + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 85b261209977..650bfffc1e6f 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -32,6 +32,7 @@ mod allocator; mod build_assert; pub mod error; +pub mod file; pub mod init; pub mod ioctl; pub mod prelude; diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 3e601ce2548d..c5b2cfd02bac 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index f946f2ea640a..072f7ef80ea5 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,12 @@ void rust_helper_put_task_struct(struct task_struct *t) } EXPORT_SYMBOL_GPL(rust_helper_put_task_struct); +struct file *rust_helper_get_file(struct file *f) +{ + return get_file(f); +} +EXPORT_SYMBOL_GPL(rust_helper_get_file); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust From patchwork Thu Jul 20 15:28:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 123361 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp3219237vqt; Thu, 20 Jul 2023 09:02:03 -0700 (PDT) X-Google-Smtp-Source: APBJJlGx3ba9OA5ZOEd5+hCbtZScechR1wP7UX8sCX/RBmLpQOMmLEkaQQQ9X7nKC/I1yEu/C+IJ X-Received: by 2002:a17:906:77c1:b0:991:caa8:fc3a with SMTP id m1-20020a17090677c100b00991caa8fc3amr2537382ejn.72.1689868923373; Thu, 20 Jul 2023 09:02:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689868923; cv=none; d=google.com; s=arc-20160816; b=i8o5qx7IsQ8LaIsMJGyBaMbOqwpnNcjM4r4TYif61vSDArVhYH29X/IbgkdTkrvZl9 n1wj5TLPX/HU1mk1NcqpK93DYPYlA0rZNWhari1kQJmOK9SBv/fz/wMa4egCcfeyU5Li sQOv0voYpLXis1UQl/v7rUqBrOn5yamr8aYk8+FUlY2VVvEl9/1Aw9ek6vNcZIxC1PBY y0JZW+Vhz2eJzVNaglv2SrFRzavEx5L1n5dmuLYhpVAQOnwfr5EEePNRpfSZb2eetKdF k0lanJm8V3DqkNgm79/VBcjNm3dxG7w2iZKDPNA7GLoRfx2i/6xgHeZ/Vsemq8rjwRRb V7FA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=IQBUPgxHkhflJuYPJ1CvCZCjp5mdRng6N97hOUv3RDI=; fh=ZYQR/+QQsWt7zde90+eOYsbHRzRn99OqhKFN5RgQnoI=; b=fwfMgzbN2YxXGbXr7ai1gQeiT1kLoyw6Y6xcSwzQodSc49SWfhYmim1eYsfw8EyQ+A V9a1tdBfs0hY9zQCWsy4jt/rPBlpWhRSCrrF+nLaROrhlDxZFg47OAQIWl4xZG9LFyln 3C02bSMRPZ6YFmiCjktwLKxY9FGOTVE7cRJGIdhAqJRzUb9c6FUnVW3N2IOztc2IMIrs HoELsWZ5Knb0swv2/F4FSNc8rwnmTjPv26A5zsFk3mKWPjnvaHS+AumlADV1p+OXNU+P /qE9LNqYbwjSrjO7krAypj6pTqGqAcVGveNDrJ9V5R/LtmTuQ1CMIzQHR39kdvGTr8YV n4Fg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=umjfMOmn; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c22-20020a17090603d600b00992fec0f917si890012eja.634.2023.07.20.09.01.36; Thu, 20 Jul 2023 09:02:03 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=umjfMOmn; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232364AbjGTP3K (ORCPT + 99 others); Thu, 20 Jul 2023 11:29:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34200 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231800AbjGTP3C (ORCPT ); Thu, 20 Jul 2023 11:29:02 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3EDD126B8 for ; Thu, 20 Jul 2023 08:28:48 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-573d70da2dcso8525007b3.1 for ; Thu, 20 Jul 2023 08:28:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689866927; x=1690471727; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=IQBUPgxHkhflJuYPJ1CvCZCjp5mdRng6N97hOUv3RDI=; b=umjfMOmncgfgLKwMNiEIs8577emiyzixkvve2v76Ldzq9BfJ2Gsva1zZuV7MmD+zEm V73fo4vHJKN3JL0aZkO4wToR1GGZI6zAUng+M3D7w8R7KOD5DI5XFt33icbHulyHxvhl D5+UKe8+wLNlI3Y0OlBtcRaD9X/Oh4SoHkKCK5pTRUk6deSnW5vy3T1AIqtzp6PAXLY5 Dlwwx0Wxi+sgy88xAvX+Vq1+H+9JH46daacQaxG5vBeKlL61m/L52VErUYkIIgC/iY1p UgL6blkD2v7rwH7l2W/hozK4eWoRgzOMEkTe1YkafDUYMyaQvNAIvZ9dR7lwzd+z0uDI kQ3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689866927; x=1690471727; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=IQBUPgxHkhflJuYPJ1CvCZCjp5mdRng6N97hOUv3RDI=; b=i/lz1tF8eeMWTdqPVKzSoHwDr05l4EzvWSvCfsLefwtWxfW2HFd8BskFhKL4R/9qXN S1McSERpiV3cjhpH9cTu7tsn29OsCLKUNu9Ux7Vzpp6EunnIgvM9M3GAyVdgp3iFqCv1 p1kddaFjniCpeFOlvpQLxvLpOPQylkwiJHiZ8QtrYW5q32XsGmQ3/nfXm6x5GzJXPdKa UysA5n9Oe8KHUwHnSvPs+jg4NUM5IJWy1KVmxRr6oe3yOkqEAKPA1Y47YWsV3lbzTp8K tFXfkYkpGrFM7Nu/6Ea1vgFI/2/po14B9WGLtTxSrhRv5eVvdYS/qA7AxYz9ASuOyKiP nd2w== X-Gm-Message-State: ABy/qLbDu12MZ3WkdKfssNqLJk/TNywfIus6FQ8Snr2M2uhk/DP95sru myT+gQqsK0BMLmkat6a4KIVW8Q5d6xiwo30= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a81:ac4c:0:b0:57a:141f:b4f5 with SMTP id z12-20020a81ac4c000000b0057a141fb4f5mr61560ywj.7.1689866927507; Thu, 20 Jul 2023 08:28:47 -0700 (PDT) Date: Thu, 20 Jul 2023 15:28:17 +0000 In-Reply-To: <20230720152820.3566078-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230720152820.3566078-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230720152820.3566078-3-aliceryhl@google.com> Subject: [RFC PATCH v1 2/5] rust: cred: add Rust bindings for `struct cred` From: Alice Ryhl To: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Miguel Ojeda , Alexander Viro , Christian Brauner Cc: Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771955995688247025 X-GMAIL-MSGID: 1771955995688247025 From: Wedson Almeida Filho Make it possible to access credentials from Rust drivers. In particular, this patch makes it possible to get the id for the security context of a given file. Signed-off-by: Wedson Almeida Filho Co-Developed-by: Alice Ryhl Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 2 + rust/helpers.c | 22 +++++++++++ rust/kernel/cred.rs | 66 +++++++++++++++++++++++++++++++++ rust/kernel/file.rs | 15 ++++++++ rust/kernel/lib.rs | 1 + 5 files changed, 106 insertions(+) create mode 100644 rust/kernel/cred.rs diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs new file mode 100644 index 000000000000..ca3fac4851a2 --- /dev/null +++ b/rust/kernel/cred.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Credentials management. +//! +//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h) +//! +//! Reference: + +use crate::{ + bindings, + types::{AlwaysRefCounted, Opaque}, +}; + +/// Wraps the kernel's `struct cred`. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the +/// allocation remains valid at least until the matching call to `put_cred`. +#[repr(transparent)] +pub struct Credential(pub(crate) Opaque); + +// SAFETY: By design, the only way to access a `Credential` is via an immutable reference or an +// `ARef`. This means that the only situation in which a `Credential` can be accessed mutably is +// when the refcount drops to zero and the destructor runs. It is safe for that to happen on any +// thread, so it is ok for this type to be `Send`. +unsafe impl Send for Credential {} + +// SAFETY: It's OK to access `Credential` through shared references from other threads because +// we're either accessing properties that don't change or that are properly synchronised by C code. +unsafe impl Sync for Credential {} + +impl Credential { + /// Creates a reference to a [`Credential`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the + /// returned [`Credential`] reference. + pub unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Credential { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `Credential` type being transparent makes the cast ok. + unsafe { &*ptr.cast() } + } + + /// Get the id for this security context. + pub fn get_secid(&self) -> u32 { + let mut secid = 0; + // SAFETY: The invariants of this type ensures that the pointer is valid. + unsafe { bindings::security_cred_getsecid(self.0.get(), &mut secid) }; + secid + } +} + +// SAFETY: The type invariants guarantee that `Credential` is always ref-counted. +unsafe impl AlwaysRefCounted for Credential { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_cred(self.0.get()) }; + } + + unsafe fn dec_ref(obj: core::ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. + unsafe { bindings::put_cred(obj.cast().as_ptr()) }; + } +} diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index 99657adf2472..d379ae2906d9 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -7,6 +7,7 @@ use crate::{ bindings, + cred::Credential, error::{code::*, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; @@ -138,6 +139,20 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File { unsafe { &*ptr.cast() } } + /// Returns the credentials of the task that originally opened the file. + pub fn cred(&self) -> &Credential { + // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. + // + // This uses a volatile read because C code may be modifying this field in parallel using + // non-atomic unsynchronized writes. This corresponds to how the C macro READ_ONCE is + // implemented. + let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).f_cred).read_volatile() }; + // SAFETY: The lifetimes of `self` and `Credential` are tied, so it is guaranteed that + // the credential pointer remains valid (because the file is still alive, and it doesn't + // change over the lifetime of a file). + unsafe { Credential::from_ptr(ptr) } + } + /// Returns the flags associated with the file. /// /// The flags are a combination of the constants in [`flags`]. diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 650bfffc1e6f..07258bfa8960 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -31,6 +31,7 @@ #[cfg(not(testlib))] mod allocator; mod build_assert; +pub mod cred; pub mod error; pub mod file; pub mod init; diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index c5b2cfd02bac..d89f0df93615 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,9 +6,11 @@ * Sorted alphabetically. */ +#include #include #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 072f7ef80ea5..e13a7da430b1 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -22,12 +22,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -144,6 +146,26 @@ struct file *rust_helper_get_file(struct file *f) } EXPORT_SYMBOL_GPL(rust_helper_get_file); +const struct cred *rust_helper_get_cred(const struct cred *cred) +{ + return get_cred(cred); +} +EXPORT_SYMBOL_GPL(rust_helper_get_cred); + +void rust_helper_put_cred(const struct cred *cred) +{ + put_cred(cred); +} +EXPORT_SYMBOL_GPL(rust_helper_put_cred); + +#ifndef CONFIG_SECURITY +void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid) +{ + security_cred_getsecid(c, secid); +} +EXPORT_SYMBOL_GPL(rust_helper_security_cred_getsecid); +#endif + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust From patchwork Thu Jul 20 15:28:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 123356 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp3214711vqt; Thu, 20 Jul 2023 08:55:18 -0700 (PDT) X-Google-Smtp-Source: APBJJlG8rK8Jxy8N5ViCuPB4e3PYkUAmIRyVy6hUH6K1EW+ptdfSbG7Vtk00H/zYyCg49AmqEVIL X-Received: by 2002:a17:90a:4cc5:b0:263:b4b0:5d85 with SMTP id k63-20020a17090a4cc500b00263b4b05d85mr20112006pjh.17.1689868517907; Thu, 20 Jul 2023 08:55:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689868517; cv=none; d=google.com; s=arc-20160816; b=haSoHhptLQnQT4UK21r+BvATM/9YUeUetV7zaVTQQfjJ6k2REGNdOjzyD6ILR/GNHl njPdcDygBSMlPXSOg200XiDtcsvV32Cv/jbT6b3WskDKpa1OqVy51dPtiJMsziPnJ1x0 YrirMgTGwi7AwvyLj0Cefq2u+uErg69iN3r1ZSHZkrLwgi/Evvksvq0LIvwpAMqNq/Yi 24y4LIYpZcXQiznkvHtzZa6QhmfD2sMnlAqzN/svpBICJFTZ63WCtJ2krbw5VfOjtHsd bt1FNmweZY2nk19+eo5qw1V39qpDRdaEvZs7FMMEpFkEPn3mPAVpnM4mEsD5HufTDxeR LwvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=EyZV70aSLRGUBSW3Idz74sX+TofVqWIQD1mh1640q38=; fh=ZYQR/+QQsWt7zde90+eOYsbHRzRn99OqhKFN5RgQnoI=; b=uPKGzMN+eWnQ6PBq4EdRcDYADNw2H+W+4PVdZVeZPNn9e4IKA+GxiPNFe5buDhdXY2 MtmzEAn7eTwoKdbFuCDJGfQDRGKDlp+StPlmV8EJEIJKHebaVAmEZcjctTRQX+W7E+Ds SCrbU8zXGz+A4gBuB+ex25njY4dIMwHTzceXKhqVV60t6vThmH2nq8hitXjRTzCk8lD1 ZaeONw8PYcGQqQQWT0Uqnvqzwh3kq1siksnPFeoHvowF1dJMtKygC50RCgm20hF0tZgq J0o2P3V8vCPsl4pz3nLxWISdvhO2DuBh+4SZxxTN5O6OFS+BAE7sIMZTTB+LQkLy98qf te7g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=RqS707yH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id lc12-20020a170902fa8c00b001baff279a5esi1137374plb.78.2023.07.20.08.55.03; Thu, 20 Jul 2023 08:55:17 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=RqS707yH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232515AbjGTP3P (ORCPT + 99 others); Thu, 20 Jul 2023 11:29:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34170 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231293AbjGTP3D (ORCPT ); Thu, 20 Jul 2023 11:29:03 -0400 Received: from mail-ej1-x649.google.com (mail-ej1-x649.google.com [IPv6:2a00:1450:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F1FE1B9 for ; Thu, 20 Jul 2023 08:28:52 -0700 (PDT) Received: by mail-ej1-x649.google.com with SMTP id a640c23a62f3a-993eeb3a950so70923766b.2 for ; Thu, 20 Jul 2023 08:28:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689866931; x=1690471731; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=EyZV70aSLRGUBSW3Idz74sX+TofVqWIQD1mh1640q38=; b=RqS707yH9iuG7p6GJXSLRTbTgG0a3UfXdNmkgzKXyq+LZAk/vDmF962f9cun/ZxZCg 7d44NcEuve934uCnCmHBq7kvmoXcMgE8vYD2El840R8evkmUt6iB4SguESYzPUmKs136 pcRKzjfCHFo51fe3uLQ8VtOzzYCmY7RUStmHPVdkrUlC+8ku7Pp6CEefLRS5aIo53e8p OY9bAVtCRHmJh/24zpIY+BvIeuDWITw0KryIPXViTV+QktgVYIYQbQaYHISUNt6cyX5Z KJiJ81aEPRXETKLR/BgpiqXSvxeDfS6e4nf+/0XDdPzyofbowKZ44ErJDP1tOrhygDtm fGDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689866931; x=1690471731; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=EyZV70aSLRGUBSW3Idz74sX+TofVqWIQD1mh1640q38=; b=AO122V3k4okxv5KC+rdr4ofZOm3F67ME+hZNWpdlIM8DD51EvxgOP9bCPKXYc6wVIt NLY2AnaKoyJMx6uLTBUV3lCRrin4pVhVTDb798dmq+zz20We7d0ttc8oh+WbhEs5oG5z Ldxh35F6sNZOhfHRqrG4HXukLcBwtMC7N9jzGfX/ZVYFR5DdtyuM3Cmm0g+ZbCWkTI4j t89nztX9hzJHfAMPTzXKixSktxrITGhqee7haPjf8+Ux8a6DFNwPzDYvhPu4Kz1aGhTk YzA/c1bAbWpJRrYwKzZR4udrE9/abf3ljs1HMiLxejvHSQIz2yohd9TN2hBKOKcu4DKJ EmMg== X-Gm-Message-State: ABy/qLYJSLr/YafcS1qAm01PYT1ItZpwF/pjRaFv1TSBS8S6Ca2TAIg9 KUVKjut8R9AU6x8oVHpns+PtwPlZLtIpoSA= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:2bd7:b0:98e:1a1b:9c21 with SMTP id gv23-20020a1709072bd700b0098e1a1b9c21mr15466ejc.5.1689866930843; Thu, 20 Jul 2023 08:28:50 -0700 (PDT) Date: Thu, 20 Jul 2023 15:28:18 +0000 In-Reply-To: <20230720152820.3566078-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230720152820.3566078-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230720152820.3566078-4-aliceryhl@google.com> Subject: [RFC PATCH v1 3/5] rust: file: add `FileDescriptorReservation` From: Alice Ryhl To: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Miguel Ojeda , Alexander Viro , Christian Brauner Cc: Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771955571365318265 X-GMAIL-MSGID: 1771955571365318265 From: Wedson Almeida Filho This allows the creation of a file descriptor in two steps: first, we reserve a slot for it, then we commit or drop the reservation. The first step may fail (e.g., the current process ran out of available slots), but commit and drop never fail (and are mutually exclusive). Co-Developed-by: Alice Ryhl Signed-off-by: Wedson Almeida Filho Signed-off-by: Alice Ryhl --- rust/kernel/file.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index d379ae2906d9..8ddf8f04ae0f 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -11,7 +11,7 @@ error::{code::*, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; -use core::ptr; +use core::{marker::PhantomData, ptr}; /// Flags associated with a [`File`]. pub mod flags { @@ -179,6 +179,65 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } +/// A file descriptor reservation. +/// +/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it, +/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran +/// out of available slots), but commit and drop never fail (and are mutually exclusive). +/// +/// # Invariants +/// +/// The fd stored in this struct must correspond to a reserved file descriptor of the current task. +pub struct FileDescriptorReservation { + fd: u32, + /// Prevent values of this type from being moved to a different task. + /// + /// This is necessary because the C FFI calls assume that `current` is set to the task that + /// owns the fd in question. + _not_send_sync: PhantomData<*mut ()>, +} + +impl FileDescriptorReservation { + /// Creates a new file descriptor reservation. + pub fn new(flags: u32) -> Result { + // SAFETY: FFI call, there are no safety requirements on `flags`. + let fd: i32 = unsafe { bindings::get_unused_fd_flags(flags) }; + if fd < 0 { + return Err(Error::from_errno(fd)); + } + Ok(Self { + fd: fd as _, + _not_send_sync: PhantomData, + }) + } + + /// Returns the file descriptor number that was reserved. + pub fn reserved_fd(&self) -> u32 { + self.fd + } + + /// Commits the reservation. + /// + /// The previously reserved file descriptor is bound to `file`. + pub fn commit(self, file: ARef) { + // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`, and `file.ptr` is + // guaranteed to have an owned ref count by its type invariants. + unsafe { bindings::fd_install(self.fd, file.0.get()) }; + + // `fd_install` consumes both the file descriptor and the file reference, so we cannot run + // the destructors. + core::mem::forget(self); + core::mem::forget(file); + } +} + +impl Drop for FileDescriptorReservation { + fn drop(&mut self) { + // SAFETY: `self.fd` was returned by a previous call to `get_unused_fd_flags`. + unsafe { bindings::put_unused_fd(self.fd) }; + } +} + /// Represents the EBADF error code. /// /// Used for methods that can only fail with EBADF. From patchwork Thu Jul 20 15:28:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 123350 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp3212294vqt; Thu, 20 Jul 2023 08:50:43 -0700 (PDT) X-Google-Smtp-Source: APBJJlE0uU+6gR1cxY+hCF4lBsWwi3Ex0RcMO5wwuhdyYMvZv/cAWVqxCCZgoPsVPkBOXUxc9yc2 X-Received: by 2002:a05:6512:3c81:b0:4fb:8de9:ac13 with SMTP id h1-20020a0565123c8100b004fb8de9ac13mr3357919lfv.23.1689868243502; Thu, 20 Jul 2023 08:50:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689868243; cv=none; d=google.com; s=arc-20160816; b=oRmEkSwxYWYASDkWtkPTs24iP23agD6AG/6O1DoX0DCHq61BKc8jc/ZUFK46x7rJ69 PnflHoroEDJPuR3e78X3DOw8gMMeXIa46Wpal9S9r8/5clN6/EzYSt1cGIXag+3rn8W4 lUMtOgFVLPtWXrzr8V3yek7Q53yI6ukxStRjODn4ExdO/b1NuOcfc2JDoseYj/qglVow jjM4c6ZWayAq0ZLXifzcJDOgaYzgT94NIB8rU5wL+JCg9nQ4WZdHhpI9p/npmZWp6m8y iF5BihmQ3K3b1d+KuRG4SDGd42l59NCMKPZxmb9m7Z4jF/gFg/xoPLSWr1U9eCHp0/Bp U6fA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=8tH3XEerZJwrZmU22bF8N/0qUJWteANYMAoh9Uhhjis=; fh=QJeT4Tw1+lehlJr34+f1S62NYu5oqf+8bwCeYvKnO+o=; b=mOB+ohFJq2YR1/N2qCJVdv5F4jzuNAnvTGt3RSFFdYUOjSoG7I3wB/82BinhNfGuEi GrJyGC91nqilrWhKaxDbiJjYVsNefjsdnSgaxNUN7i/XhIkse/1D4rMC+0JFUS42QUsY hzJ6czeg6n+fBrV2zydTpsNbn687EHP/v+jn/56qdftI6w8TmsCrVbDsk0LaaptV+PBY A6yUo+B89eTIwlc2YD6YqQ8DuOMaQbEZOOEOwIfQ7l4pJaVVKiPW7+vIH6RX9M4fOzh2 GYuvt7nziVP9Vy05b1oGKWz1WOLlW/OUaazAy+TGv66/8y8B+F0TxLYweYVv1pF9x8KT bL2g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=iIbHUoHV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j11-20020aa7c0cb000000b0051fef304630si1027397edp.390.2023.07.20.08.50.19; Thu, 20 Jul 2023 08:50:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=iIbHUoHV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232533AbjGTP3S (ORCPT + 99 others); Thu, 20 Jul 2023 11:29:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34208 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231919AbjGTP3D (ORCPT ); Thu, 20 Jul 2023 11:29:03 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 26BBF2701 for ; Thu, 20 Jul 2023 08:28:55 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-c64ef5bde93so773687276.0 for ; Thu, 20 Jul 2023 08:28:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689866934; x=1690471734; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8tH3XEerZJwrZmU22bF8N/0qUJWteANYMAoh9Uhhjis=; b=iIbHUoHVCIkaKMm/BUsR4YwpCcAILtijBEEpiPzLGsxFloPgn0f7EOrpei60KDIcvk 8t9TBzVqQs+AkQvHturJdtqihaNRMzMFCKXFW+yYzJtUuSGFzvt6b7X4xrQ742/qZmKU PvEKOBKF4OD/QkC7sV6V53SmlhclUJxyOXH9z0797NDGNgsxIgCVTE77X5wl3hBXbpX4 CUYQc58iS7Vz7i0p4RGy5F1G9zOILpr96cQBOoIdxky3VX2EsWb49rl1/kluJqBrvrQt WqjWtykIW08YaMiVbMm4RK5QZ+3LafZMQodf7O1gjLNykfiDOSypoIOhwMpCer+173uW j3fA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689866934; x=1690471734; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8tH3XEerZJwrZmU22bF8N/0qUJWteANYMAoh9Uhhjis=; b=MQ26Pg6CCJTf8oxondeajr4YGhimCSoHc4GoPigpAO80qRzwAG6qvRkKED3J5VaAFN u3Oz+TMOEN8PRH4sNPHMFZDs0rZDe0BgIKdy/17TnSXH7dm8oOvWi7oizP2KMp5UWRCr 1n3SP1ugT5ObCO3Qd1gRCeT8R/xTUcizodLa1uuhCMo+hNzJ6KNdbZeUy3IzyAAwVykP ffUaX5mRBqTB8mUGZ5rtS+zwvmtLmEvOsu528vtdME5swh0c6f0I8glrOUBTduqcuhUZ tbq7BEzWjvEBE482/NBJ+msA1fiC6GJXyloz+amQIVFPmsaLXK0rEp1EnU+6M+cRpkNB Kvdg== X-Gm-Message-State: ABy/qLZ7EgFLwfO/pZSiiV0aTPOEvpUU6PUu5PMEmZFshcbv91kZj8UZ 8WxORwg9N1RdUIClc1y6hiRqMJJ2MP3zOdU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a25:2551:0:b0:c86:e7cf:4064 with SMTP id l78-20020a252551000000b00c86e7cf4064mr39916ybl.6.1689866934433; Thu, 20 Jul 2023 08:28:54 -0700 (PDT) Date: Thu, 20 Jul 2023 15:28:19 +0000 In-Reply-To: <20230720152820.3566078-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230720152820.3566078-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230720152820.3566078-5-aliceryhl@google.com> Subject: [RFC PATCH v1 4/5] rust: file: add bindings for `poll_table` From: Alice Ryhl To: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Miguel Ojeda , Alexander Viro , Christian Brauner Cc: Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771955283373035965 X-GMAIL-MSGID: 1771955283373035965 These bindings make it possible to register a `struct poll_table` with a `CondVar` so that notifying the condition variable will mark a given file as notified in the poll table. This patch introduces a wrapper around `CondVar` (which is just a wrapper around `wait_list`) rather than extending `CondVar` itself because using the condition variable with poll tables makes it necessary to use `POLLHUP | POLLFREE` to clear the wait list when the condition variable is destroyed. This is not necessary with the ordinary `CondVar` because all of its methods will borrow the `CondVar` for longer than the duration in which it enqueues something to the wait list. This is not the case when registering a `PollTable`. Signed-off-by: Alice Ryhl --- rust/bindings/bindings_helper.h | 2 + rust/bindings/lib.rs | 1 + rust/kernel/file.rs | 3 ++ rust/kernel/file/poll_table.rs | 93 +++++++++++++++++++++++++++++++++ rust/kernel/sync/condvar.rs | 2 +- 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/file/poll_table.rs diff --git a/rust/kernel/file/poll_table.rs b/rust/kernel/file/poll_table.rs new file mode 100644 index 000000000000..d6d134355088 --- /dev/null +++ b/rust/kernel/file/poll_table.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Utilities for working with `struct poll_table`. + +use crate::{ + bindings, + file::File, + prelude::*, + sync::{CondVar, LockClassKey}, + types::Opaque, +}; +use core::ops::Deref; + +/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class. +#[macro_export] +macro_rules! new_poll_condvar { + ($($name:literal)?) => { + $crate::file::PollCondVar::new($crate::optional_name!($($name)?), $crate::static_lock_class!()) + }; +} + +/// Wraps the kernel's `struct poll_table`. +#[repr(transparent)] +pub struct PollTable(Opaque); + +impl PollTable { + /// Creates a reference to a [`PollTable`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a, the pointer will point at a valid poll + /// table, and that it is only accessed via the returned reference. + pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `PollTable` type being transparent makes the cast ok. + unsafe { &mut *ptr.cast() } + } + + fn get_qproc(&self) -> bindings::poll_queue_proc { + let ptr = self.0.get(); + // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc` + // field is not modified concurrently with this call. + unsafe { (*ptr)._qproc } + } + + /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified + /// using the condition variable. + pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) { + if let Some(qproc) = self.get_qproc() { + // SAFETY: The pointers to `self` and `file` are valid because they are references. + // + // Before the wait list is destroyed, the destructor of `PollCondVar` will clear + // everything in the wait list, so the wait list is not used after it is freed. + unsafe { qproc(file.0.get() as _, cv.wait_list.get(), self.0.get()) }; + } + } +} + +/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`]. +/// +/// [`CondVar`]: crate::sync::CondVar +#[pin_data(PinnedDrop)] +pub struct PollCondVar { + #[pin] + inner: CondVar, +} + +impl PollCondVar { + /// Constructs a new condvar initialiser. + #[allow(clippy::new_ret_no_self)] + pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pin_init!(Self { + inner <- CondVar::new(name, key), + }) + } +} + +// Make the `CondVar` methods callable on `PollCondVar`. +impl Deref for PollCondVar { + type Target = CondVar; + + fn deref(&self) -> &CondVar { + &self.inner + } +} + +#[pinned_drop] +impl PinnedDrop for PollCondVar { + fn drop(self: Pin<&mut Self>) { + // Clear anything registered using `register_wait`. + self.inner.notify(1, bindings::POLLHUP | bindings::POLLFREE); + } +} diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ed353399c4e5..699ecac2db89 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -144,7 +144,7 @@ pub fn wait_uninterruptible(&self, guard: &mut Guard<'_, } /// Calls the kernel function to notify the appropriate number of threads with the given flags. - fn notify(&self, count: i32, flags: u32) { + pub(crate) fn notify(&self, count: i32, flags: u32) { // SAFETY: `wait_list` points to valid memory. unsafe { bindings::__wake_up( diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index 8ddf8f04ae0f..7281264cbaa1 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -13,6 +13,9 @@ }; use core::{marker::PhantomData, ptr}; +mod poll_table; +pub use self::poll_table::{PollCondVar, PollTable}; + /// Flags associated with a [`File`]. pub mod flags { /// File is opened in append mode. diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index d89f0df93615..7d83e1a7a362 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,3 +20,4 @@ /* `bindgen` gets confused at certain things. */ const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL; const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO; +const __poll_t BINDINGS_POLLFREE = POLLFREE; diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs index 9bcbea04dac3..eeb291cc60db 100644 --- a/rust/bindings/lib.rs +++ b/rust/bindings/lib.rs @@ -51,3 +51,4 @@ mod bindings_helper { pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL; pub const __GFP_ZERO: gfp_t = BINDINGS___GFP_ZERO; +pub const POLLFREE: __poll_t = BINDINGS_POLLFREE; From patchwork Thu Jul 20 15:28:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 123373 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c923:0:b0:3e4:2afc:c1 with SMTP id j3csp3225899vqt; Thu, 20 Jul 2023 09:09:30 -0700 (PDT) X-Google-Smtp-Source: APBJJlGLydtE3ZA50qEhXZh2QYaQ6lLfdVWflDKEtcDzCEOjOiEkOSBks9rfyg5LQZIANEVqvlgT X-Received: by 2002:a2e:9915:0:b0:2b6:b864:fac6 with SMTP id v21-20020a2e9915000000b002b6b864fac6mr2683256lji.37.1689869370231; Thu, 20 Jul 2023 09:09:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689869370; cv=none; d=google.com; s=arc-20160816; b=qPYlHAGDuvS5YK28eO2wRajwDudi8lcnjUhElqiaVa3eWHLEa+tX31wjyuU+PEpBX/ cqdKAV3GLvOyopofpn3nAevWDT4XJ/kC8MIRlvwHMvT1Nfe1LghNz/aOL79GdCGCCbge Px84eHej3Vwrb2zOyPU3MPpBhUabWLCY0ZKYGTSD1ZuppJ8DYIHYdLPr3Sexhlvrlx54 +zU0Sdt/6c9hvbKPK0zpNMjAJ2BZygroZkSUL7HTdfxGuCSmhL5BqLmvFdcbhwYic4P1 lH2fLMRYquQR220AxrnZMMpIhU+2VsRqY0XdNUD9X3L0QMx5VOJFq7klbtpseVlWpdoX T2fg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=d/u9EQyW+X21UxdbxspElMqoKZgJyUHYdK5EQ3Z7BOw=; fh=QJeT4Tw1+lehlJr34+f1S62NYu5oqf+8bwCeYvKnO+o=; b=N/Dv0OcOxCuhiW8JBkl390W6fbs0wd4paI29mIqlvgcxqfqAg9uLez7jljsLv3XdXw T7mfr6ZN2RQLVD5wD8sbJQtvMTKGE9y7lXJVUbfHQRtu1idzbDhToKJtwWxDkC5EdswE wJq5Hwx8IUvJl9N7qObt9UYls7CVeesTW/cBpt8F3nUkjhgs+3ETjM9KOGxIqE8TS7Xz AMOwwOg2W/O1poL2/+AoqNS9y2cFP3kdAeRsBR8pBGCQ5M6U0r2Av+jUmFqAv96JDiTD 5/rciHSXNT9xEHikAb534Mmgz+vCVTHorHVAKdJiyYRaCzZK96lXf6uUxOQVfcBDC7Re 84PA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=3Hwd44nZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t9-20020a1709066bc900b00992c30f5887si823498ejs.474.2023.07.20.09.09.05; Thu, 20 Jul 2023 09:09:30 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=3Hwd44nZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232547AbjGTP3V (ORCPT + 99 others); Thu, 20 Jul 2023 11:29:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34198 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230366AbjGTP3D (ORCPT ); Thu, 20 Jul 2023 11:29:03 -0400 Received: from mail-ed1-x54a.google.com (mail-ed1-x54a.google.com [IPv6:2a00:1450:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C60B7270E for ; Thu, 20 Jul 2023 08:28:59 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-51a595bc30dso1236318a12.0 for ; Thu, 20 Jul 2023 08:28:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1689866938; x=1690471738; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=d/u9EQyW+X21UxdbxspElMqoKZgJyUHYdK5EQ3Z7BOw=; b=3Hwd44nZ28dd7XQpwbotYQrWBx55skJp3Gg5KtDbRpDdMOffpWdvgIzNW860/54HaT Azxf/5by8rXcrok2m41Mqp1TMzDWRinsNR8PQskZDazzTs+Gp7tZqhBOc1yUUgTuJmRr kksHZP3kh1tFtsq2GBDhXDOpYxYoVGwh08aplvBGp9TKQ48GqSDmZqAyZ2GTmAZhYpJ1 o2H8FoOGoPqkY2ao9JEaJJHSfeUSbfw+8DSGPm6uorPl8pnz36deNwerOjK72eTjgqXq PVbSr14PujluBch8hecMx3je20sH5Q9iXokyshWyBaVVH59tY43OZqL9Vt46qTAXsIUY M1Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689866938; x=1690471738; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=d/u9EQyW+X21UxdbxspElMqoKZgJyUHYdK5EQ3Z7BOw=; b=i/apRflH7GBUxVWusztM43I/kb3wk+gb28PNJah3yic5lkqywl1V7+kA2+U8xH18Nh nLib2rZ7TvxFASz7FcwAmVMjVFsm7AYyjk1fE7EG4kotX7iMGz92JM//SyEKPLIJnOeP fMIGQ2NyrXRvyvjyrJiTQzwPgDXBDSmTJFw4aiZA9cicsmZUnStToQbxOrd3rWG5A1j4 7f8SdAk9PTKs5Jg3nAva7/w1bJhYZ4YHlHzvk6TtHV1ih9TydrDPDz4GjLuEPBhRq63Q 4GrDHTj9hQZpHBUVnjqy9mtmOV+hnhyrl2RUyt6MoF+2DFb525ZSWahot6jZAeRXm79d MQVw== X-Gm-Message-State: ABy/qLarUcizh8uoUk6cxzkT13sgL7fm+tOz6IycH6A1nJykN22IVV+4 SSPPDYezSMbTM9SAUqW+r5IdKtkFiJgXFuA= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a05:6402:e9c:b0:51e:3810:e3b1 with SMTP id h28-20020a0564020e9c00b0051e3810e3b1mr39802eda.1.1689866938115; Thu, 20 Jul 2023 08:28:58 -0700 (PDT) Date: Thu, 20 Jul 2023 15:28:20 +0000 In-Reply-To: <20230720152820.3566078-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230720152820.3566078-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.255.g8b1d071c50-goog Message-ID: <20230720152820.3566078-6-aliceryhl@google.com> Subject: [RFC PATCH v1 5/5] rust: file: add `DeferredFdCloser` From: Alice Ryhl To: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, Miguel Ojeda , Alexander Viro , Christian Brauner Cc: Wedson Almeida Filho , Alex Gaynor , Boqun Feng , Gary Guo , " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771956464558351366 X-GMAIL-MSGID: 1771956464558351366 This adds a new type called `DeferredFdCloser` that can be used to close files by their fd in a way that is safe even if the file is currently held using `fdget`. This is done by grabbing an extra refcount to the file and dropping it in a task work once we return to userspace. See comments on `binder_do_fd_close` and commit `80cd795630d65` for motivation. Signed-off-by: Alice Ryhl --- This is an implementation of `binder_deferred_fd_close` in Rust. I think the fact that binder needs to close fds in this way raises the question of how we want the Rust APIs for closing files to look. Apparently, fdget is not just used in easily reviewable regions, but also around things like the ioctl syscall, meaning that all ioctls must abide by the fdget safety requirements. rust/bindings/bindings_helper.h | 2 + rust/helpers.c | 7 +++ rust/kernel/file.rs | 80 ++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index 7281264cbaa1..9b1f4efdf7ac 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -11,7 +11,8 @@ error::{code::*, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; -use core::{marker::PhantomData, ptr}; +use alloc::boxed::Box; +use core::{alloc::AllocError, marker::PhantomData, mem, ptr}; mod poll_table; pub use self::poll_table::{PollCondVar, PollTable}; @@ -241,6 +242,83 @@ fn drop(&mut self) { } } +/// Helper used for closing file descriptors in a way that is safe even if the file is currently +/// held using `fdget`. +/// +/// See comments on `binder_do_fd_close` and commit `80cd795630d65`. +pub struct DeferredFdCloser { + inner: Box, +} + +/// SAFETY: This just holds an allocation with no real content, so there's no safety issue with +/// moving it across threads. +unsafe impl Send for DeferredFdCloser {} +unsafe impl Sync for DeferredFdCloser {} + +#[repr(C)] +struct DeferredFdCloserInner { + twork: mem::MaybeUninit, + file: *mut bindings::file, +} + +impl DeferredFdCloser { + /// Create a new `DeferredFdCloser`. + pub fn new() -> Result { + Ok(Self { + inner: Box::try_new(DeferredFdCloserInner { + twork: mem::MaybeUninit::uninit(), + file: core::ptr::null_mut(), + })?, + }) + } + + /// Schedule a task work that closes the file descriptor when this task returns to userspace. + pub fn close_fd(mut self, fd: u32) { + let file = unsafe { bindings::close_fd_get_file(fd) }; + if !file.is_null() { + self.inner.file = file; + + // SAFETY: Since DeferredFdCloserInner is `#[repr(C)]`, casting the pointers gives a + // pointer to the `twork` field. + let inner = Box::into_raw(self.inner) as *mut bindings::callback_head; + + // SAFETY: Getting a pointer to current is always safe. + let current = unsafe { bindings::get_current() }; + // SAFETY: The `file` pointer points at a valid file. + unsafe { bindings::get_file(file) }; + // SAFETY: Due to the above `get_file`, even if the current task holds an `fdget` to + // this file right now, the refcount will not drop to zero until after it is released + // with `fdput`. This is because when using `fdget`, you must always use `fdput` before + // returning to userspace, and our task work runs after any `fdget` users have returned + // to user space. + // + // Note: fl_owner_t is currently a void pointer. + unsafe { bindings::filp_close(file, current as bindings::fl_owner_t) }; + // SAFETY: The `inner` pointer is compatible with the `do_close_fd` method. + // + // The call to `task_work_add` can't fail, because we are scheduling the task work to + // the current task. + unsafe { + bindings::init_task_work(inner, Some(Self::do_close_fd)); + bindings::task_work_add(current, inner, bindings::task_work_notify_mode_TWA_RESUME); + } + } else { + // Free the allocation. + drop(self.inner); + } + } + + unsafe extern "C" fn do_close_fd(inner: *mut bindings::callback_head) { + // SAFETY: In `close_fd` we use this method together with a pointer that originates from a + // `Box`, and we have just been given ownership of that allocation. + let inner = unsafe { Box::from_raw(inner as *mut DeferredFdCloserInner) }; + // SAFETY: This drops a refcount we acquired in `close_fd`. + unsafe { bindings::fput(inner.file) }; + // Free the allocation. + drop(inner); + } +} + /// Represents the EBADF error code. /// /// Used for methods that can only fail with EBADF. diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 7d83e1a7a362..6d0d044fa8cd 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include /* `bindgen` gets confused at certain things. */ const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL; diff --git a/rust/helpers.c b/rust/helpers.c index e13a7da430b1..d147ec5bc0a3 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -31,6 +31,7 @@ #include #include #include +#include #include __noreturn void rust_helper_BUG(void) @@ -166,6 +167,12 @@ void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid) EXPORT_SYMBOL_GPL(rust_helper_security_cred_getsecid); #endif +void rust_helper_init_task_work(struct callback_head *twork, task_work_func_t func) +{ + init_task_work(twork, func); +} +EXPORT_SYMBOL_GPL(rust_helper_init_task_work); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust