Received: by 2002:a05:7412:3b8b:b0:fc:a2b0:25d7 with SMTP id nd11csp324987rdb; Thu, 8 Feb 2024 07:05:59 -0800 (PST) X-Google-Smtp-Source: AGHT+IG5ocG3JeffcSxFseUWBDqiStLn4kSkEgJNI6sQFfLfrfJnSBgY3ujKl84qpaFgVsBrnVmJ X-Received: by 2002:a05:6402:12c6:b0:560:7572:4a9 with SMTP id k6-20020a05640212c600b00560757204a9mr6521627edx.21.1707404758947; Thu, 08 Feb 2024 07:05:58 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707404758; cv=pass; d=google.com; s=arc-20160816; b=WAwJxa2/llYyZ395q+Rin4qyLhxIH/D5UcR9iO9ySMzML1iHsYhkiKp1wMiHMlAlmX Cd2FutjOdS7JznvyHT9usxLf+obItbxI/bMtAbgiPH9ryz4+OS7F9E9CpCTltl44FBfJ aIUL0KAiPuiyDlUtRiQot9jPAVe4EMc22vPsOkkAyShvZGPD93L+1GhTg7BSuxek4Jgi +U9Y+reVLoiQXE33pcRB6Tc2/ZRDNkBy6duPYXyV58p1Z+HbBg8dbj5sEXa0u0zRNFNH /6zOx2jwoIHyg+hlDGcL8Go5/E5imbBcuJxW9Y85aG8RnU0t9exZ2MSYNEYgkRGoAlbb WdQw== 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=/1RcVIIytdlhLHmoNj+deLulYTGt9lRpDm9txekPAmg=; fh=KoMR4+Hw2U3Ei4QSUqlAgWGs0ZtMRCzlmYnhu3FvoR0=; b=iqfQ8VX0BQYGbWXdQ5hlly2HjZxLknwn5wGY+6XC7o1i32vM+DZoZH7synnF7GHbKe JLXHZZ61o8gbKEMkRuAbkH+JR19Co5kh0UA8yeR2/x/OOACqEUHwieWYS2oxtOMJ/ZNj WU8GeckUyOaqfhB8lmrM3TC7tgst/5OfTKgVUy38eBwlLuGk2CqOuRQdIkiesEcpMZdi AwJsTVs3A7NjSP9V/189zpkG9WFC+EsbfOEy9pvNM9DHASkYP2WOHLhG0YszzwEhp6pZ 8KYxv7raZLV84jpHeYIzbJB6cHFWx5UDXZv3Ic+wkCa/VxT/hCfjmXDeZDhiaiX55TW/ GQEg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=wAi5tOo2; 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-58264-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58264-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com X-Forwarded-Encrypted: i=2; AJvYcCXdfCXp7Vf4GH8B5IfESqGkOw3NwnMCMhEQXvbbTcbzYs3g4Bs6Zu4nrR50MPize6J6T3RaLSAfpfxSi+TsIVUzGcUgQZchW3FyTjHtNw== Return-Path: Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id r17-20020aa7cfd1000000b0055f27dea051si988106edy.347.2024.02.08.07.05.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Feb 2024 07:05:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-58264-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=wAi5tOo2; 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-58264-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58264-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 am.mirrors.kernel.org (Postfix) with ESMTPS id 7EEC41F235A6 for ; Thu, 8 Feb 2024 15:05:58 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8FEBF7B3DB; Thu, 8 Feb 2024 15:05:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="wAi5tOo2" Received: from mail-vs1-f41.google.com (mail-vs1-f41.google.com [209.85.217.41]) (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 DD70679956 for ; Thu, 8 Feb 2024 15:05:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.41 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707404745; cv=none; b=CHv5ilQzIx8qS7Bm0agFU9J3wTeU3D96RbQMenR8Th8GEjepainDLyPYLh8/Uo3px5Q6zDYm9P5FgQyQK+choG6ZzM/51qeVn8HF+wUEhPhhXow9voMsm+PaZemrjV+u4uVAWfGLySNn4COaeOZ+lfA0a3r4KhqM171tafEiQNw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707404745; c=relaxed/simple; bh=bWFo1Lrp7yi5ftyvRv/uFM8AEPJoN0Y0hTCzDzCPAXg=; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject: To:Cc:Content-Type; b=AeYAOG8t+TMafgUYg5na3RpsHq7efP6jIzv1bUsZAz73kgNv6XeYAQnV4WbmbPiXyv0A8ehuLeffhjt5I45ZR1JfkFOY49zL3fNLU344y+OfZoqn96ss/xP5sItY5BMz8jw2z6693RbO3jbCJBz1BHEBkGGtphsQGbs1c65Yfek= 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=wAi5tOo2; arc=none smtp.client-ip=209.85.217.41 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-vs1-f41.google.com with SMTP id ada2fe7eead31-46d2d20c923so426695137.0 for ; Thu, 08 Feb 2024 07:05:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1707404741; x=1708009541; 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=/1RcVIIytdlhLHmoNj+deLulYTGt9lRpDm9txekPAmg=; b=wAi5tOo2p4V8WRiTq6PjVFVAwRi8AWnE7+zMhnJpKP93/F7hPShu4TBrnmuhDkJaQS MICwUURUu5joh3w/qL/mjvg4PKvhTolfiUaN9ud1nmkVfMgeDJC8CIVkw3YNgJRpmAfL /sj7M/mWEA113M+6ZZrZkCh19psXNgRACtNVF5R2wT9Oz13lvANEUaNXEvyVqoQyiXfw MwGMeCIV+apNEcgaWKECqG/gzYtQ6LFl5yXgkGwVUIJ1YqUmViQs+OT/rRLrVtATjb3Y syoobWQAurH7cxHuN/QmTqB4+b6cO6d/rG9EDq7g4qxpFMFQuR8EhyUPohyVXoTmt85D Gd4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707404741; x=1708009541; 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=/1RcVIIytdlhLHmoNj+deLulYTGt9lRpDm9txekPAmg=; b=evdA+bmvXvRst8p6N0uo4QbaL6k6CkK8xC2xYC6w1rDqZH0m9VdVmqT2QyqDl6vaZ2 EDLzSux1K5MDFgcL/1xCKMHlbwJc9tHw+L+UfI8Rk0b1uuZKU9ZoJqzSgPitOwaA1TGE YqaAiInVsW4xS7xw9mEMApKbk0uNRcK8MXpfHE0RFIEdhHzdI3/rMyI7ffxm/frt4nCr +a4gDy2oO3hXxDzE+8ve8A6RwhgS6II/dkx2bgw3eRb9VeT7GqLim7rjfYpY4kRxlWC6 VwXkcTgg83ILLnxkwRCl+/dCbwA9QbyDpT9bMf00zhc+5gCkOy6u8VDQ0LeueTWmmoVw gxuA== X-Gm-Message-State: AOJu0YxlI7zF72dTpoz5+DKSj+8n3eXuE+0K2tif3mQc4shMRpmwEesS SpYomZ1bMi0DSvUMARwR4gweTQlQDQcevTgfKW4P0sPJiKfLyyqISF3k3rCkSdwr7BwENW4vOlT jCbjPUdkuw8E7x0CtZu8kaYxjCEJ7Emx5x4km X-Received: by 2002:a05:6122:2326:b0:4c0:230c:1143 with SMTP id bq38-20020a056122232600b004c0230c1143mr5804657vkb.10.1707404741486; Thu, 08 Feb 2024 07:05:41 -0800 (PST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 References: <20240202-alice-file-v4-0-fc9c2080663b@google.com> <20240202-alice-file-v4-3-fc9c2080663b@google.com> In-Reply-To: From: Alice Ryhl Date: Thu, 8 Feb 2024 16:05:30 +0100 Message-ID: Subject: Re: [PATCH v4 3/9] rust: file: add Rust abstraction for `struct file` To: Trevor Gross Cc: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?UTF-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Peter Zijlstra , Alexander Viro , Christian Brauner , Greg Kroah-Hartman , =?UTF-8?B?QXJ2ZSBIasO4bm5ldsOlZw==?= , Todd Kjos , Martijn Coenen , Joel Fernandes , Carlos Llamas , Suren Baghdasaryan , Dan Williams , Kees Cook , Matthew Wilcox , Thomas Gleixner , Daniel Xu , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Feb 6, 2024 at 3:48=E2=80=AFAM Trevor Gross wro= te: > > On Fri, Feb 2, 2024 at 5:56=E2=80=AFAM Alice Ryhl = wrote: > > > > From: Wedson Almeida Filho > > > > This abstraction makes it possible to manipulate the open files for a > > process. The new `File` struct wraps the C `struct file`. When accessin= g > > it using the smart pointer `ARef`, the pointer will own a > > reference count to the file. When accessing it as `&File`, then the > > reference does not own a refcount, but the borrow checker will ensure > > that the reference count does not hit zero while the `&File` is live. > > > > Since this is intended to manipulate the open files of a process, we > > introduce an `fget` constructor that corresponds to the C `fget` > > method. In future patches, it will become possible to create a new fd i= n > > a process and bind it to a `File`. Rust Binder will use these to send > > fds from one process to another. > > > > We also provide a method for accessing the file's flags. Rust Binder > > will use this to access the flags of the Binder fd to check whether the > > non-blocking flag is set, which affects what the Binder ioctl does. > > > > This introduces a struct for the EBADF error type, rather than just > > using the Error type directly. This has two advantages: > > * `File::from_fd` returns a `Result, BadFdError>`, which the > > compiler will represent as a single pointer, with null being an error= . > > This is possible because the compiler understands that `BadFdError` > > has only one possible value, and it also understands that the > > `ARef` smart pointer is guaranteed non-null. > > * Additionally, we promise to users of the method that the method can > > only fail with EBADF, which means that they can rely on this promise > > without having to inspect its implementation. > > That said, there are also two disadvantages: > > * Defining additional error types involves boilerplate. > > * 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. (However, it works fine in method= s > > that return `Error`.) > > > > 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 > > --- > > fs/file.c | 7 + > > rust/bindings/bindings_helper.h | 2 + > > rust/helpers.c | 7 + > > rust/kernel/file.rs | 249 ++++++++++++++++++++++++++++++++ > > rust/kernel/lib.rs | 1 + > > 5 files changed, 266 insertions(+) > > create mode 100644 rust/kernel/file.rs > > > > diff --git a/fs/file.c b/fs/file.c > > index 3b683b9101d8..f2eab5fcb87f 100644 > > --- a/fs/file.c > > +++ b/fs/file.c > > @@ -1115,18 +1115,25 @@ EXPORT_SYMBOL(task_lookup_next_fdget_rcu); > > /* > > * Lightweight file lookup - no refcnt increment if fd table isn't sha= red. > > * > > * You can use this instead of fget if you satisfy all of the followin= g > > * conditions: > > * 1) You must call fput_light before exiting the syscall and returnin= g control > > * to userspace (i.e. you cannot remember the returned struct file = * after > > * returning to userspace). > > * 2) You must not call filp_close on the returned struct file * in be= tween > > * calls to fget_light and fput_light. > > * 3) You must not clone the current task in between the calls to fget= _light > > * and fput_light. > > * > > * The fput_needed flag returned by fget_light should be passed to the > > * corresponding fput_light. > > + * > > + * (As an exception to rule 2, you can call filp_close between fget_li= ght and > > + * fput_light provided that you capture a real refcount with get_file = before > > + * the call to filp_close, and ensure that this real refcount is fput = *after* > > + * the fput_light call.) > > + * > > + * See also the documentation in rust/kernel/file.rs. > > */ > > static unsigned long __fget_light(unsigned int fd, fmode_t mask) > > { > > Should this be split to its own patch so it can be applied separately if = needed? I don't think that's necessary. > > [...] > > + /// Also known as `O_NDELAY`. > > + /// > > + /// This is effectively the same flag as [`O_NONBLOCK`] on all arc= hitectures > > + /// except SPARC64. > > + pub const O_NDELAY: u32 =3D bindings::O_NDELAY; > > This is O_NDELAY, should the AKA say O_NONBLOCK? > > [...] > > +/// Wraps the kernel's `struct file`. > > It is probably better to say what it does for the summary, and mention > what it wraps later. I added a bit more info. > > +/// # Refcounting > > +/// > > +/// Instances of this type are reference-counted. The reference count = is incremented by the > > +/// `fget`/`get_file` functions and decremented by `fput`. The Rust ty= pe `ARef` represents a > > +/// pointer that owns a reference count on the file. > > +/// > > +/// Whenever a process opens a file descriptor (fd), it stores a point= er to the file in its `struct > > +/// files_struct`. This pointer owns a reference count to the file, en= suring the file isn't > > +/// prematurely deleted while the file descriptor is open. In Rust ter= minology, the pointers in > > +/// `struct files_struct` are `ARef` pointers. > > +/// > > +/// ## Light refcounts > > +/// > > +/// Whenever a process has an fd to a file, it may use something calle= d a "light refcount" as a > > +/// performance optimization. Light refcounts are acquired by calling = `fdget` and released with > > +/// `fdput`. The idea behind light refcounts is that if the fd is not = closed between the calls to > > +/// `fdget` and `fdput`, then the refcount cannot hit zero during that= time, as the `struct > > +/// files_struct` holds a reference until the fd is closed. This means= that it's safe to access the > > +/// file even if `fdget` does not increment the refcount. > > +/// > > +/// The requirement that the fd is not closed during a light refcount = applies globally across all > > +/// threads - not just on the thread using the light refcount. For thi= s reason, light refcounts are > > +/// only used when the `struct files_struct` is not shared with other = threads, since this ensures > > +/// that other unrelated threads cannot suddenly start using the fd an= d close it. Therefore, > > +/// calling `fdget` on a shared `struct files_struct` creates a normal= refcount instead of a light > > +/// refcount. > > +/// > > +/// Light reference counts must be released with `fdput` before the sy= stem call returns to > > +/// userspace. This means that if you wait until the current system ca= ll returns to userspace, then > > +/// all light refcounts that existed at the time have gone away. > > +/// > > +/// ## Rust references > > +/// > > +/// The reference type `&File` is similar to light refcounts: > > +/// > > +/// * `&File` references don't own a reference count. They can only ex= ist as long as the reference > > +/// count stays positive, and can only be created when there is some= mechanism in place to ensure > > +/// this. > > +/// > > +/// * The Rust borrow-checker normally ensures this by enforcing that = the `ARef` from which > > +/// a `&File` is created outlives the `&File`. > > +/// > > +/// * Using the unsafe [`File::from_ptr`] means that it is up to the c= aller to ensure that the > > +/// `&File` only exists while the reference count is positive. > > +/// > > +/// * You can think of `fdget` as using an fd to look up an `ARef` in the `struct > > +/// files_struct` and create an `&File` from it. The "fd cannot be c= losed" rule is like the Rust > > +/// rule "the `ARef` must outlive the `&File`". > > +/// > > +/// # Invariants > > +/// > > +/// * Instances of this type are refcounted using the `f_count` field. > > +/// * If an fd with active light refcounts is closed, then it must be = the case that the file > > +/// refcount is positive until all light refcounts of the fd have be= en dropped. > > +/// * A light refcount must be dropped before returning to userspace. > > +#[repr(transparent)] > > +pub struct File(Opaque); > > + > > +// SAFETY: > > +// - `File::dec_ref` can be called from any thread. > > +// - It is okay to send ownership of `File` across thread boundaries. > > Shouldn't this be lowecase `file` because it is referring to the > underlying C object? Done. > > +unsafe impl Send for File {} > > [...] > > + /// Returns the flags associated with the file. > > + /// > > + /// The flags are a combination of the constants in [`flags`]. > > + pub fn flags(&self) -> u32 { > > A typedef used here and in the constants module could be useful > > type FileFlags =3D u32; Maybe, but it doesn't actually do anything as far as the type checker is concerned, so meh. > > + // This `read_volatile` is intended to correspond to a READ_ON= CE call. > > + // > > + // SAFETY: The file is valid because the shared reference guar= antees a nonzero refcount. > > + // > > + // TODO: Replace with `read_once` when available on the Rust s= ide. > > Shouldn't the TODO become a `FIXME(read_once): ...` since it is going > into the codebase? I'm not sure we necessarily have a convention for that? But I'll change it. > > Some suggestions but nothing blocking > > Reviewed-by: Trevor Gross