From 8d464561153c99fb0c21610f0ba2fffb5d6e1ef3 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:43:00 +0200 Subject: [PATCH 01/58] Add kernel.german.md Co-authored-by: Benedikt Weber <44091658+bewee@users.noreply.github.com> --- kernel.german.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 kernel.german.md diff --git a/kernel.german.md b/kernel.german.md new file mode 100644 index 00000000000000..f74405d54527a9 --- /dev/null +++ b/kernel.german.md @@ -0,0 +1,105 @@ +# Custom Rust Kernel bauen + +## 1. Vorbereitung + +Kernel holen (z.B. [`github.com/niklasmohrin/linux`](https://github.com/niklasmohrin/linux)), [Arch Iso holen](https://archlinux.org/download/) (relativ neu, mit Installer) + +## 2. Kernel bauen + +Siehe [`quick-start.rst`](https://github.com/niklasmohrin/linux/blob/ramfs/Documentation/rust/quick-start.rst) für Toolchain. + +```console +$ mkdir -p builds/{kernel, modules} +$ cd mylinuxclone +$ make O=../builds/kernel defconfig # wir wollen das repo selbst nicht zum bauen benutzen +$ cd ../builds/kernel +$ rustup default nightly-2021-02-20 +$ make menuconfig # Rust Support auswählen, Rest erstmal egal +$ make ARCH=x86_64 CC=clang -j12 # baut Kernel und gewählte Module +... +something about bzImage # irgendwie sowas sollte am Ende stehen +... +$ make INSTALL_MOD_PATH=../modules modules_install # Alle Module sammeln +``` + +## 3. VM aufbauen + +- qemu und ovmf installieren (man braucht vor allem eine `OVMF.fd`) +- `qemu-img create -f qcow2 archinstaller-clean.qcow2 8G` +- VM launchen mit Befehl unten, wobei das `-cdrom ...` mit benutzt werden muss +- `archinstall` guided installer, Profil minimal (kein XOrg) +- root account passwort muss gesetzt werden für SSH +- falls später was fehlt `pacman -S neovim openssh tree` oder so + +## 4. Snapshots + +Jetzt bietet es sich an, einen Snapshot zu machen: + +``` +qemu-img create -b archinstaller-clean.qcow2 snapshot1.qcow2 +``` + +Hierbei ist wichtig, dass der Snapshot nicht mehr funktioniert, falls das Basis Image verändert wird (also nichtmal booten am besten). Falls man wieder da anfangen will, sollte ein neuer Snapshot mit der gleichen Basis erstellt werden. + +Es gibt auch noch die `-snapshot` Flag beim starten, da arbeitet man immer nur auf einem Snapshot der nach Ende der Session weggeschmissen wird (wir wissen aber nicht, ob es safe ist das Basis Image damit zu booten). + +## 5. VM launchen + +Hier sollte das `pool/current.qcow2` durch Pfad zum Disk Image und `OVMF.fd` durch vollen Pfad zur Datei ersetzt werden + +```sh +#!/bin/sh + +qemu-system-x86_64 \ + -drive file=pool/current.qcow2,format=qcow2 \ + -boot menu=on \ + -bios OVMF.fd \ + -nic user,hostfwd=tcp::2222-:22 \ + -m 4096 \ + -cpu host \ + -enable-kvm + # -nographic \ + # -cdrom archlinux-2021.05.01-x86_64.iso \ + # -snapshot \ + # -vga virtio -display sdl,gl=on \ + # -fsdev local,id=fs1,path=share,security_model=none \ + # -device virtio-9p-pci,fsdev=fs1,mount_tag=shared_folder \ + # -kernel ../linux/arch/x86/boot/bzImage \ + # -append "console=ttyS0" \ +``` + +## 6. SSHD konfigurieren + +Im Guest in `/etc/ssh/sshd_config` (`pacman -S openssh`) die Option `PermitRootLogin yes` setzen. +Dann noch mit `systemctl enable --now sshd` den Server aktivieren. + +## 7. Kernel und Module im Guest installieren + +Bevor wir `builds/modules` rekursiv in die VM kopieren, sollten wir den Symlink auf den Sourcecode entfernen, weil sonst kopieren wir den mit. WICHTIG: nicht die Pfade mit `/` enden lassen, sonst wird das Verzeichnis hinter dem Link gelöscht. + +```console +$ rm builds/modules/{source, build} +$ scp -P 2222 builds/kernel//bzImage root@127.0.0.1:/boot/vmlinuz-rust +$ scp -r -P 2222 builds/modules/lib/* root@127.0.0.1:/lib/ +``` + +## 8. Boot Manager anpassen + +Der Arch Installer hat uns systemd-boot installiert. + +```console +$ cd /boot/loader/entries/ +$ cp linux-rust.conf +$ nvim linux-rust.conf + +ESC ESC :wq here you go +$ bootctl install +$ reboot +``` + +## 9. Testen + +Am besten man hat `rust_minimal` als eingebautes Modul kompiliert, dann kann man nach dem reboot in `dmesg | less` nach Rust suchen (type: `/rust`, dann `n` zum nächsten Suchergebnis). +Mit `modprobe rust_print` wird das dynamische Modul geladen, das sollte jetzt in `dmesg | tail` und `lsmod | grep rust` auftauchen. + +Kernelmodule die nicht in `/lib/modules/.../` (`...` sollte durch den Output von `uname -r` / die Versionsnummer ersetzt werden; in unserem Fall `5.12.0-rc4+`) liegen, können mit `insmod example.ko` und `rmmod example.ko` geladen und entladen werden. From 0ce7b365d6c3654b09993662ada89a2b32e9f04a Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:52:40 +0200 Subject: [PATCH 02/58] kernel crate: Extend basic kernel types to suit our needs This commit is the merged version with upstream, fix coming later --- rust/kernel/error.rs | 210 ++++++++++++++++++++++++++++++++++-------- rust/kernel/macros.rs | 19 ++++ rust/kernel/types.rs | 62 ++++++++++++- 3 files changed, 252 insertions(+), 39 deletions(-) create mode 100644 rust/kernel/macros.rs diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 0b6e60adc9210c..3479bf1e0b26bb 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -4,14 +4,17 @@ //! //! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h) -use crate::str::CStr; -use crate::{bindings, c_types}; +use crate::{bindings, c_types, declare_constant_from_bindings, macros::DO_NEGATE, str::CStr}; use alloc::{alloc::AllocError, collections::TryReserveError}; use core::convert::From; use core::fmt; use core::num::TryFromIntError; use core::str::{self, Utf8Error}; +extern "C" { + fn rust_helper_is_err(p: *mut c_types::c_void) -> bool; +} + /// Generic integer kernel error. /// /// The kernel defines a set of integer generic error codes based on C and @@ -24,42 +27,6 @@ use core::str::{self, Utf8Error}; pub struct Error(c_types::c_int); impl Error { - /// Invalid argument. - pub const EINVAL: Self = Error(-(bindings::EINVAL as i32)); - - /// Out of memory. - pub const ENOMEM: Self = Error(-(bindings::ENOMEM as i32)); - - /// Bad address. - pub const EFAULT: Self = Error(-(bindings::EFAULT as i32)); - - /// Illegal seek. - pub const ESPIPE: Self = Error(-(bindings::ESPIPE as i32)); - - /// Try again. - pub const EAGAIN: Self = Error(-(bindings::EAGAIN as i32)); - - /// Device or resource busy. - pub const EBUSY: Self = Error(-(bindings::EBUSY as i32)); - - /// Restart the system call. - pub const ERESTARTSYS: Self = Error(-(bindings::ERESTARTSYS as i32)); - - /// Operation not permitted. - pub const EPERM: Self = Error(-(bindings::EPERM as i32)); - - /// No such process. - pub const ESRCH: Self = Error(-(bindings::ESRCH as i32)); - - /// No such file or directory. - pub const ENOENT: Self = Error(-(bindings::ENOENT as i32)); - - /// Interrupted system call. - pub const EINTR: Self = Error(-(bindings::EINTR as i32)); - - /// Bad file number. - pub const EBADF: Self = Error(-(bindings::EBADF as i32)); - /// Creates an [`Error`] from a kernel error code. /// /// It is a bug to pass an out-of-range `errno`. `EINVAL` would @@ -94,6 +61,173 @@ impl Error { pub fn to_kernel_errno(self) -> c_types::c_int { self.0 } + + pub fn is_err_ptr(p: *mut c_types::c_void) -> bool { + unsafe { rust_helper_is_err(p) } + } + + pub fn as_err_ptr(&self) -> *mut T { + self.0 as *mut _ + } + + pub fn from_err_ptr(p: *mut c_types::c_void) -> Self { + Self(p as _) + } + + pub fn parse_ptr(p: *mut T) -> KernelResult<*mut T> { + if !Self::is_err_ptr(p as _) { + Ok(p) + } else { + Err(Self::from_err_ptr(p as _)) + } + } +} + +macro_rules! declare_error { + ($name:ident, $doc:expr) => { + declare_constant_from_bindings!($name, $doc, i32, DO_NEGATE); + }; +} + +#[macro_export] +macro_rules! ret_err_ptr { + ($ex:expr) => { + match $ex { + Ok(val) => val, + Err(err) => return err.as_err_ptr(), + } + }; +} + +#[rustfmt::skip] +impl Error { + // See `man 3 errno`. + declare_error!(E2BIG, "Argument list too long (POSIX.1-2001)."); + declare_error!(EACCES, "Permission denied (POSIX.1-2001)."); + declare_error!(EADDRINUSE, "Address already in use (POSIX.1-2001)."); + declare_error!(EADDRNOTAVAIL, "Address not available (POSIX.1-2001)."); + declare_error!(EAFNOSUPPORT, "Address family not supported (POSIX.1-2001)."); + declare_error!(EAGAIN, "Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1-2001)."); + declare_error!(EALREADY, "Connection already in progress (POSIX.1-2001)."); + declare_error!(EBADE, "Invalid exchange."); + declare_error!(EBADF, "Bad file descriptor (POSIX.1-2001)."); + declare_error!(EBADFD, "File descriptor in bad state."); + declare_error!(EBADMSG, "Bad message (POSIX.1-2001)."); + declare_error!(EBADR, "Invalid request descriptor."); + declare_error!(EBADRQC, "Invalid request code."); + declare_error!(EBADSLT, "Invalid slot."); + declare_error!(EBUSY, "Device or resource busy (POSIX.1-2001)."); + declare_error!(ECANCELED, "Operation canceled (POSIX.1-2001)."); + declare_error!(ECHILD, "No child processes (POSIX.1-2001)."); + declare_error!(ECHRNG, "Channel number out of range."); + declare_error!(ECOMM, "Communication error on send."); + declare_error!(ECONNABORTED, "Connection aborted (POSIX.1-2001)."); + declare_error!(ECONNREFUSED, "Connection refused (POSIX.1-2001)."); + declare_error!(ECONNRESET, "Connection reset (POSIX.1-2001)."); + declare_error!(EDEADLK, "Resource deadlock avoided (POSIX.1-2001)."); + declare_error!(EDEADLOCK, "On most architectures, a synonym for EDEADLK. On some architectures (e.g., Linux MIPS, PowerPC, SPARC), it is a separate error code \"File locking dead-lock error\"."); + declare_error!(EDESTADDRREQ, "Destination address required (POSIX.1-2001)."); + declare_error!(EDOM, "Mathematics argument out of domain of function (POSIX.1, C99)."); + declare_error!(EDQUOT, "Disk quota exceeded (POSIX.1-2001)."); + declare_error!(EEXIST, "File exists (POSIX.1-2001)."); + declare_error!(EFAULT, "Bad address (POSIX.1-2001)."); + declare_error!(EFBIG, "File too large (POSIX.1-2001)."); + declare_error!(EHOSTDOWN, "Host is down."); + declare_error!(EHOSTUNREACH, "Host is unreachable (POSIX.1-2001)."); + declare_error!(EHWPOISON, "Memory page has hardware error."); + declare_error!(EIDRM, "Identifier removed (POSIX.1-2001)."); + declare_error!(EILSEQ, "Invalid or incomplete multibyte or wide character (POSIX.1, C99)."); + declare_error!(EINPROGRESS, "Operation in progress (POSIX.1-2001)."); + declare_error!(EINTR, "Interrupted function call (POSIX.1-2001); see signal(7)."); + declare_error!(EINVAL, "Invalid argument (POSIX.1-2001)."); + declare_error!(EIO, "Input/output error (POSIX.1-2001)."); + declare_error!(EISCONN, "Socket is connected (POSIX.1-2001)."); + declare_error!(EISDIR, "Is a directory (POSIX.1-2001)."); + declare_error!(EISNAM, "Is a named type file."); + declare_error!(EKEYEXPIRED, "Key has expired."); + declare_error!(EKEYREJECTED, "Key was rejected by service."); + declare_error!(EKEYREVOKED, "Key has been revoked."); + declare_error!(EL2HLT, "Level 2 halted."); + declare_error!(EL2NSYNC, "Level 2 not synchronized."); + declare_error!(EL3HLT, "Level 3 halted."); + declare_error!(EL3RST, "Level 3 reset."); + declare_error!(ELIBACC, "Cannot access a needed shared library."); + declare_error!(ELIBBAD, "Accessing a corrupted shared library."); + declare_error!(ELIBMAX, "Attempting to link in too many shared libraries."); + declare_error!(ELIBSCN, ".lib section in a.out corrupted"); + declare_error!(ELIBEXEC, "Cannot exec a shared library directly."); + declare_error!(ELNRNG, "Link number out of range."); + declare_error!(ELOOP, "Too many levels of symbolic links (POSIX.1-2001)."); + declare_error!(EMEDIUMTYPE, "Wrong medium type."); + declare_error!(EMFILE, "Too many open files (POSIX.1-2001). Commonly caused by exceeding the RLIMIT_NOFILE resource limit described in getrlimit(2). Can also be caused by exceeding the limit specified in /proc/sys/fs/nr_open."); + declare_error!(EMLINK, "Too many links (POSIX.1-2001)."); + declare_error!(EMSGSIZE, "Message too long (POSIX.1-2001)."); + declare_error!(EMULTIHOP, "Multihop attempted (POSIX.1-2001)."); + declare_error!(ENAMETOOLONG, "Filename too long (POSIX.1-2001)."); + declare_error!(ENETDOWN, "Network is down (POSIX.1-2001)."); + declare_error!(ENETRESET, "Connection aborted by network (POSIX.1-2001)."); + declare_error!(ENETUNREACH, "Network unreachable (POSIX.1-2001)."); + declare_error!(ENFILE, "Too many open files in system (POSIX.1-2001). On Linux, this is probably a result of encountering the /proc/sys/fs/file-max limit (see proc(5))."); + declare_error!(ENOANO, "No anode."); + declare_error!(ENOBUFS, "No buffer space available (POSIX.1 (XSI STREAMS option))."); + declare_error!(ENODATA, "No message is available on the STREAM head read queue (POSIX.1-2001)."); + declare_error!(ENODEV, "No such device (POSIX.1-2001)."); + declare_error!(ENOENT, "No such file or directory (POSIX.1-2001)."); + declare_error!(ENOEXEC, "Exec format error (POSIX.1-2001)."); + declare_error!(ENOKEY, "Required key not available."); + declare_error!(ENOLCK, "No locks available (POSIX.1-2001)."); + declare_error!(ENOLINK, "Link has been severed (POSIX.1-2001)."); + declare_error!(ENOMEDIUM, "No medium found."); + declare_error!(ENOMEM, "Not enough space/cannot allocate memory (POSIX.1-2001)."); + declare_error!(ENOMSG, "No message of the desired type (POSIX.1-2001)."); + declare_error!(ENONET, "Machine is not on the network."); + declare_error!(ENOPKG, "Package not installed."); + declare_error!(ENOPROTOOPT, "Protocol not available (POSIX.1-2001)."); + declare_error!(ENOSPC, "No space left on device (POSIX.1-2001)."); + declare_error!(ENOSR, "No STREAM resources (POSIX.1 (XSI STREAMS option))."); + declare_error!(ENOSTR, "Not a STREAM (POSIX.1 (XSI STREAMS option))."); + declare_error!(ENOSYS, "Function not implemented (POSIX.1-2001)."); + declare_error!(ENOTBLK, "Block device required."); + declare_error!(ENOTCONN, "The socket is not connected (POSIX.1-2001)."); + declare_error!(ENOTDIR, "Not a directory (POSIX.1-2001)."); + declare_error!(ENOTEMPTY, "Directory not empty (POSIX.1-2001)."); + declare_error!(ENOTRECOVERABLE, "State not recoverable (POSIX.1-2008)."); + declare_error!(ENOTSOCK, "Not a socket (POSIX.1-2001)."); + declare_error!(ENOTTY, "Inappropriate I/O control operation (POSIX.1-2001)."); + declare_error!(ENOTUNIQ, "Name not unique on network."); + declare_error!(ENXIO, "No such device or address (POSIX.1-2001)."); + declare_error!(EOPNOTSUPP, "Operation not supported on socket (POSIX.1-2001)."); + declare_error!(EOVERFLOW, "Value too large to be stored in data type (POSIX.1-2001)."); + declare_error!(EOWNERDEAD, "Owner died (POSIX.1-2008)."); + declare_error!(EPERM, "Operation not permitted (POSIX.1-2001)."); + declare_error!(EPFNOSUPPORT, "Protocol family not supported."); + declare_error!(EPIPE, "Broken pipe (POSIX.1-2001)."); + declare_error!(EPROTO, "Protocol error (POSIX.1-2001)."); + declare_error!(EPROTONOSUPPORT, "Protocol not supported (POSIX.1-2001)."); + declare_error!(EPROTOTYPE, "Protocol wrong type for socket (POSIX.1-2001)."); + declare_error!(ERANGE, "Result too large (POSIX.1, C99)."); + declare_error!(EREMCHG, "Remote address changed."); + declare_error!(EREMOTE, "Object is remote."); + declare_error!(EREMOTEIO, "Remote I/O error."); + declare_error!(ERESTART, "Interrupted system call should be restarted."); + declare_error!(ERFKILL, "Operation not possible due to RF-kill."); + declare_error!(EROFS, "Read-only filesystem (POSIX.1-2001)."); + declare_error!(ESHUTDOWN, "Cannot send after transport endpoint shutdown."); + declare_error!(ESPIPE, "Invalid seek (POSIX.1-2001)."); + declare_error!(ESOCKTNOSUPPORT, "Socket type not supported."); + declare_error!(ESRCH, "No such process (POSIX.1-2001)."); + declare_error!(ESTALE, "Stale file handle (POSIX.1-2001)."); + declare_error!(ESTRPIPE, "Streams pipe error."); + declare_error!(ETIME, "Timer expired (POSIX.1 (XSI STREAMS option))."); + declare_error!(ETIMEDOUT, "Connection timed out (POSIX.1-2001)."); + declare_error!(ETOOMANYREFS, "Too many references: cannot splice."); + declare_error!(ETXTBSY, "Text file busy (POSIX.1-2001)."); + declare_error!(EUCLEAN, "Structure needs cleaning."); + declare_error!(EUNATCH, "Protocol driver not attached."); + declare_error!(EUSERS, "Too many users."); + declare_error!(EWOULDBLOCK, "Operation would block (may be same value as EAGAIN) (POSIX.1-2001)."); + declare_error!(EXDEV, "Improper link (POSIX.1-2001)."); + declare_error!(EXFULL, "Exchange full."); } impl fmt::Debug for Error { diff --git a/rust/kernel/macros.rs b/rust/kernel/macros.rs new file mode 100644 index 00000000000000..27c6762c396592 --- /dev/null +++ b/rust/kernel/macros.rs @@ -0,0 +1,19 @@ +#![allow(dead_code)] + +pub const DO_NEGATE: bool = true; +pub const DO_NOT_NEGATE: bool = false; + +#[macro_export] +macro_rules! declare_constant_from_bindings { + ($name:ident, $doc:expr) => { + #[doc=$doc] + #[allow(unused)] + pub const $name: Self = Self(crate::bindings::$name as _); + }; + ($name:ident, $doc:expr, $intermediate:ty, $negate:expr) => { + #[doc=$doc] + #[allow(unused)] + pub const $name: Self = + Self(if $negate { -1 } else { 1 } * (crate::bindings::$name as $intermediate)); + }; +} diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 027a91812c7b0c..bfc78a0db1e043 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -4,12 +4,16 @@ //! //! C header: [`include/linux/types.h`](../../../../include/linux/types.h) -use core::{ops::Deref, pin::Pin}; +use core::{ + ops::{BitAnd, BitOr, Deref}, + pin::Pin, +}; use alloc::{boxed::Box, sync::Arc}; use crate::bindings; use crate::c_types; +use crate::declare_constant_from_bindings; use crate::sync::{Ref, RefCounted}; /// Permissions. @@ -17,6 +21,7 @@ use crate::sync::{Ref, RefCounted}; /// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h) /// /// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h) +#[derive(Clone, Copy)] pub struct Mode(bindings::umode_t); impl Mode { @@ -31,6 +36,61 @@ impl Mode { } } +#[rustfmt::skip] +impl Mode { + // See `man 7 inode`. + + // file type + declare_constant_from_bindings!(S_IFMT, "bit mask for the file type bit field"); + + declare_constant_from_bindings!(S_IFSOCK, "socket"); + declare_constant_from_bindings!(S_IFLNK, "symbolic link"); + declare_constant_from_bindings!(S_IFREG, "regular file"); + declare_constant_from_bindings!(S_IFBLK, "block device"); + declare_constant_from_bindings!(S_IFDIR, "directory"); + declare_constant_from_bindings!(S_IFCHR, "character device"); + declare_constant_from_bindings!(S_IFIFO, "FIFO"); + + // file mode component of the st_mode field + declare_constant_from_bindings!(S_ISUID, "set-user-ID bit (see execve(2))"); + declare_constant_from_bindings!(S_ISGID, "set-group-ID bit (see below)"); + declare_constant_from_bindings!(S_ISVTX, "sticky bit (see below)"); + + declare_constant_from_bindings!(S_IRWXU, "owner has read, write, and execute permission"); + declare_constant_from_bindings!(S_IRUSR, "owner has read permission"); + declare_constant_from_bindings!(S_IWUSR, "owner has write permission"); + declare_constant_from_bindings!(S_IXUSR, "owner has execute permission"); + + declare_constant_from_bindings!(S_IRWXG, "group has read, write, and execute permission"); + declare_constant_from_bindings!(S_IRGRP, "group has read permission"); + declare_constant_from_bindings!(S_IWGRP, "group has write permission"); + declare_constant_from_bindings!(S_IXGRP, "group has execute permission"); + + declare_constant_from_bindings!(S_IRWXO, "others (not in group) have read, write, and execute permission"); + declare_constant_from_bindings!(S_IROTH, "others have read permission"); + declare_constant_from_bindings!(S_IWOTH, "others have write permission"); + declare_constant_from_bindings!(S_IXOTH, "others have execute permission"); + + // extras + declare_constant_from_bindings!(S_IRWXUGO, ""); +} + +impl BitAnd for Mode { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self(self.0 & rhs.0) + } +} + +impl BitOr for Mode { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + /// Used to convert an object into a raw pointer that represents it. /// /// It can eventually be converted back into the object. This is used to store objects as pointers From 9bf5e0298d56b5570c93cad26c2952ba624f2227 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:54:51 +0200 Subject: [PATCH 03/58] kernel crate: Add file system abstractions --- rust/helpers.c | 30 ++++- rust/kernel/fs.rs | 293 +++++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 5 + 3 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/fs.rs diff --git a/rust/helpers.c b/rust/helpers.c index cf4ddd705f222c..3d9f92c5b2f076 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -2,10 +2,11 @@ #include #include -#include #include #include #include +#include +#include #include #include #include @@ -151,3 +152,30 @@ static_assert( __alignof__(size_t) == __alignof__(uintptr_t), "Rust code expects C size_t to match Rust usize" ); + +void rust_helper_dget(struct dentry *dentry) +{ + dget(dentry); +} +EXPORT_SYMBOL_GPL(rust_helper_dget); + +void rust_helper_mapping_set_unevictable(struct address_space *mapping) +{ + mapping_set_unevictable(mapping); +} +EXPORT_SYMBOL_GPL(rust_helper_mapping_set_unevictable); + +void rust_helper_mapping_set_gfp_mask(struct address_space *mapping, gfp_t mask) +{ + mapping_set_gfp_mask(mapping, mask); +} +EXPORT_SYMBOL_GPL(rust_helper_mapping_set_gfp_mask); + +const gfp_t RUST_HELPER_GFP_HIGHUSER = GFP_HIGHUSER; +EXPORT_SYMBOL_GPL(RUST_HELPER_GFP_HIGHUSER); + +#if !defined(CONFIG_ARM) +// See https://github.com/rust-lang/rust-bindgen/issues/1671 +static_assert(__builtin_types_compatible_p(size_t, uintptr_t), + "size_t must match uintptr_t, what architecture is this??"); +#endif diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs new file mode 100644 index 00000000000000..83d092441fc0c3 --- /dev/null +++ b/rust/kernel/fs.rs @@ -0,0 +1,293 @@ +use alloc::boxed::Box; +use core::{convert::TryFrom, mem, ptr}; + +use crate::ret_err_ptr; +use crate::{bindings, buffer::Buffer, c_types::*, prelude::*, CStr, Error, KernelResult}; + +pub type FileSystemType = bindings::file_system_type; +pub type SuperBlock = bindings::super_block; + +pub trait FileSystemBase { + type MountOptions = c_void; + + const NAME: CStr<'static>; + const FS_FLAGS: c_int; + const OWNER: *mut bindings::module; + + // TODO: is that a fair return type here? + fn mount( + fs_type: &'_ mut FileSystemType, + flags: c_int, + device_name: CStr, + data: Option<&mut Self::MountOptions>, + ) -> KernelResult<*mut bindings::dentry>; + + // fn kill_superblock(sb: &mut SuperBlock); + + // fn fill_superblock(sb: Box, data: Box, silent: bool); + + unsafe extern "C" fn mount_raw( + fs_type: *mut bindings::file_system_type, + flags: c_int, + device_name: *const c_char, + data: *mut c_void, + ) -> *mut bindings::dentry { + pr_emerg!("in mount_raw"); + let fs_type = &mut *fs_type; + let device_name = CStr::from_ptr(device_name); + let data = (data as *mut Self::MountOptions).as_mut(); + ret_err_ptr!(Self::mount(fs_type, flags, device_name, data)) + } + + unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { + // let sb = SuperBlock::from_raw(sb); + // self.kill_superblock(sb); + // let _ = SuperBlock::into_raw(sb); + } + + // fn mount_bdev(flags: u32, dev_name: &CStr, data: Box) { + // bindings::mount_bdev( + // Self::file_system_type(), + // flags, + // CStr::into_raw(dev_name), + // MountOptions::into_raw(data), + // self.fill_super_raw + // ); + // } + + // unsafe extern "C" fn fill_super_raw(sb: *mut bindings::super_block, data: *mut c_void, silent: bool) { + // let sb = Box::from_raw(sb); + // let data = MountOptions::from_raw(data); + // self.fill_superblock(sb, data, silent); + // sb.s_magic = SuperBlock::MAGIC; + // sb.s_blocksize = SuperBlock::BLOCKSIZE; + // sb.s_blocksize_bits = SuperBlock::BLOCKSIZE_BITS; + // let s_ops = bindings::super_operations { + // alloc_inode: SuperBlock::alloc_inode_raw as *mut _, + // drop_inode: SuperBlock::drop_inode_raw as *mut _, + // statfs: SuperBlock::statfs_raw as *mut _, + // ..Default::defaults() + // }; + // sb.s_op = s_ops; + // // ... register SuperBlock (associated) dropt_node, statfs, constants + // let _ = Box::into_raw(sb); + // let _ = MountOptions::into_raw(data); + // } + + fn fill_super( + _sb: &mut SuperBlock, + _data: Option<&mut Self::MountOptions>, + _silent: c_int, + ) -> KernelResult { + pr_emerg!("Using default FileSystem::fill_super"); + Ok(()) + } + + unsafe extern "C" fn fill_super_raw( + sb: *mut bindings::super_block, + data: *mut c_void, + silent: c_int, + ) -> c_int { + pr_emerg!("in fill_super_raw"); + let sb = &mut *sb; + let data = (data as *mut Self::MountOptions).as_mut(); + Self::fill_super(sb, data, silent) + .map(|_| 0) + .unwrap_or_else(|e| e.to_kernel_errno()) + } +} + +pub trait DeclaredFileSystemType: FileSystemBase { + fn file_system_type() -> *mut bindings::file_system_type; +} + +#[macro_export] +macro_rules! declare_fs_type { + ($T:ty, $S:ident) => { + static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { + name: <$T as $crate::fs::FileSystemBase>::NAME.as_str() as *const _ as *const _, + fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, + mount: Some(<$T as $crate::fs::FileSystemBase>::mount_raw), + kill_sb: Some(<$T as $crate::fs::FileSystemBase>::kill_sb_raw), + owner: <$T as $crate::fs::FileSystemBase>::OWNER, + ..$crate::fs::DEFAULT_FS_TYPE + }; + impl $crate::fs::DeclaredFileSystemType for $T { + fn file_system_type() -> *mut $crate::bindings::file_system_type { + unsafe { &mut $S as *mut _ } + } + } + }; +} + +pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { + fn register() -> KernelResult { + let err = unsafe { bindings::register_filesystem(Self::file_system_type()) }; + if err == 0 { + Ok(()) + } else { + Err(Error::from_kernel_errno(err)) + } + } + + fn unregister() -> KernelResult { + let err = unsafe { bindings::unregister_filesystem(Self::file_system_type()) }; + if err == 0 { + Ok(()) + } else { + Err(Error::from_kernel_errno(err)) + } + } + + fn mount_nodev( + flags: c_int, + data: Option<&mut Self::MountOptions>, + ) -> KernelResult<*mut bindings::dentry> { + Error::parse_ptr(unsafe { + bindings::mount_nodev( + Self::file_system_type(), + flags, + data.map(|p| p as *mut _ as *mut _) + .unwrap_or_else(ptr::null_mut), + Some(Self::fill_super_raw), + ) + }) + } +} + +impl FileSystem for T {} + +pub const DEFAULT_SUPER_OPS: bindings::super_operations = bindings::super_operations { + statfs: None, + drop_inode: None, + show_options: None, + alloc_inode: None, + destroy_inode: None, + dirty_inode: None, + write_inode: None, + evict_inode: None, + put_super: None, + sync_fs: None, + freeze_super: None, + freeze_fs: None, + thaw_super: None, + unfreeze_fs: None, + remount_fs: None, + umount_begin: None, + show_devname: None, + show_path: None, + show_stats: None, + quota_read: None, + free_inode: None, + quota_write: None, + get_dquots: None, + bdev_try_to_free_page: None, + nr_cached_objects: None, + free_cached_objects: None, +}; + +pub const DEFAULT_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations = + bindings::address_space_operations { + readpage: None, + readahead: None, + write_begin: None, + write_end: None, + set_page_dirty: None, + writepage: None, + writepages: None, + readpages: None, + bmap: None, + invalidatepage: None, + releasepage: None, + freepage: None, + direct_IO: None, + migratepage: None, + isolate_page: None, + putback_page: None, + launder_page: None, + is_partially_uptodate: None, + is_dirty_writeback: None, + error_remove_page: None, + swap_activate: None, + swap_deactivate: None, + }; + +pub const DEFAULT_INODE_OPERATIONS: bindings::inode_operations = bindings::inode_operations { + create: None, + lookup: None, + link: None, + unlink: None, + symlink: None, + mkdir: None, + rmdir: None, + mknod: None, + rename: None, + listxattr: None, + fiemap: None, + update_time: None, + tmpfile: None, + set_acl: None, + get_link: None, + permission: None, + get_acl: None, + readlink: None, + setattr: None, + getattr: None, + atomic_open: None, +}; + +pub const DEFAULT_FS_TYPE: bindings::file_system_type = bindings::file_system_type { + name: ptr::null(), + fs_flags: 0, + init_fs_context: None, + parameters: ptr::null(), + mount: None, + kill_sb: None, + owner: ptr::null_mut(), + next: ptr::null_mut(), + fs_supers: bindings::hlist_head { + first: ptr::null_mut(), + }, + s_lock_key: bindings::lock_class_key {}, + s_umount_key: bindings::lock_class_key {}, + s_vfs_rename_key: bindings::lock_class_key {}, + s_writers_key: [bindings::lock_class_key {}; 3], + i_lock_key: bindings::lock_class_key {}, + i_mutex_key: bindings::lock_class_key {}, + i_mutex_dir_key: bindings::lock_class_key {}, +}; + +pub const DEFAULT_FILE_OPERATIONS: bindings::file_operations = bindings::file_operations { + owner: ptr::null_mut(), + llseek: None, + read: None, + write: None, + read_iter: None, + write_iter: None, + iopoll: None, + iterate: None, + iterate_shared: None, + poll: None, + unlocked_ioctl: None, + compat_ioctl: None, + mmap: None, + mmap_supported_flags: 0, + open: None, + flush: None, + release: None, + fsync: None, + fasync: None, + lock: None, + sendpage: None, + get_unmapped_area: None, + check_flags: None, + flock: None, + splice_write: None, + splice_read: None, + setlease: None, + fallocate: None, + show_fdinfo: None, + copy_file_range: None, + remap_file_range: None, + fadvise: None, +}; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 7ceb8985f83656..74d035ec795091 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -44,9 +44,12 @@ pub mod bindings; pub mod buffer; pub mod c_types; pub mod chrdev; +pub mod dentry; +#[macro_use] mod error; pub mod file; pub mod file_operations; +pub mod fs; pub mod miscdev; pub mod pages; pub mod str; @@ -70,6 +73,8 @@ pub mod sysctl; pub mod io_buffer; pub mod iov_iter; +#[macro_use] +mod macros; pub mod of; pub mod platdev; mod types; From c6c55abacebcc1ac942f6516e70611ff17c9e3c3 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:55:41 +0200 Subject: [PATCH 04/58] kernel crate: Add vision for dentry and super_block wrappers Co-authored-by: SqYtCO --- rust/kernel/dentry.rs | 81 ++++++++++++++++++++++++++++++++++++++ rust/kernel/super_block.rs | 53 +++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 rust/kernel/dentry.rs create mode 100644 rust/kernel/super_block.rs diff --git a/rust/kernel/dentry.rs b/rust/kernel/dentry.rs new file mode 100644 index 00000000000000..f3c8b226108c2d --- /dev/null +++ b/rust/kernel/dentry.rs @@ -0,0 +1,81 @@ +use alloc::boxed::Box; +use core::{ + mem, + ops::{Deref, DerefMut}, +}; + +use crate::bindings; +pub type Inode = bindings::inode; + +#[repr(transparent)] +pub struct Dentry(bindings::dentry); + +impl Deref for Dentry { + type Target = bindings::dentry; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Dentry { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Dentry { + pub fn as_raw_inner(self: Box) -> *mut bindings::dentry { + Box::into_raw(self) as *mut _ + } + + pub fn make_root(inode: &mut Inode) -> Option<&mut Self> { + unsafe { + Some(bindings::d_make_root(inode as *mut _)) + .filter(|p| !p.is_null()) + .map(|p| mem::transmute(&mut *p)) + } + } + + pub fn lookup(&mut self, query: *const bindings::qstr) -> Option<&mut Self> { + unsafe { + Some(bindings::d_lookup(&mut self.0 as *mut _, query)) + .filter(|p| !p.is_null()) + .map(|p| mem::transmute(&mut *p)) + } + } + + pub fn get(&mut self) { + // couldn't find in bindings, lol + unimplemented!() + } + + pub fn put(&mut self) { + unsafe { + bindings::dput(&mut self.0 as *mut _); + } + } + + pub fn drop_dentry(&mut self) { + unsafe { + bindings::d_drop(&mut self.0 as *mut _); + } + } + + pub fn delete_dentry(&mut self) { + unsafe { + bindings::d_delete(&mut self.0 as *mut _); + } + } + + pub fn add(&mut self, inode: &mut Inode) { + unsafe { + bindings::d_add(&mut self.0 as *mut _, inode as *mut _); + } + } + + pub fn instantiate(&mut self, inode: &mut Inode) { + unsafe { + bindings::d_instantiate(&mut self.0 as *mut _, inode as *mut _); + } + } +} diff --git a/rust/kernel/super_block.rs b/rust/kernel/super_block.rs new file mode 100644 index 00000000000000..ce925d3c377ae8 --- /dev/null +++ b/rust/kernel/super_block.rs @@ -0,0 +1,53 @@ +use crate::bindings; + +pub trait SuperBlock { + type Inode; + + const MAGIC: u64; + const BLOCKSIZE: u64; + const BLOCKSIZE_BITS: u8; + + pub fn as_inner(&mut self) -> &mut bindings::super_block; + pub fn from_inner(sb: &mut bindings::super_block) -> &mut Self; + + const statfs_implemented: bool = false; // TODO add a derive macro to auto-generate these + pub fn statfs(&mut self, dentry: Box, buf: Box) -> KernelResult<()> { + unreachable!() + } + + unsafe extern "C" fn statfs_raw(dentry: *mut bindings::dentry, buf: *mut bindings::kstatfs) -> i32 { + let dentry = Dentry::from_raw(*dentry); + let buf = KStatsfs::from_raw(*buf); + let res = Self::statsfs(dentry, buf); + let _ = Dentry::into_raw(dentry); + let _ = KStatsfs::into_raw(buf); + res + } + + const drop_inode_implemented: bool = false; + pub fn drop_inode(inode: Box) -> KernelResult { + unreachable!() + } + + unsafe extern "C" fn drop_inode_raw(inode: *mut bindings::inode) -> i32 { + let inode = Inode::from_raw(*inode); + let res = Self::drop_inode(inode); + let _ = Inode::into_raw(inode); + res + } + + const alloc_inode_implemented: bool = false; + pub fn alloc_inode(&mut self) -> Box { + unreachable!() + } + + unsafe extern "C" fn alloc_inode(sb: *mut bindings::super_block) -> *mut bindings::inode { + let inode = Inode::from_raw(*inode); + let res = Self::from_inner(sb).alloc_inode(inode); + let _ = Inode::into_raw(inode); + res + } + + // TODO add all the lots of other methods + +} From ef8f7806fe5f1ed0f4ac0786d9410e4178459ff6 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:58:02 +0200 Subject: [PATCH 05/58] bs2ramfs: Add mvp (squashed changes from mvp branch) --- fs/Kconfig | 1 + fs/Makefile | 1 + fs/bs2ramfs/Kconfig | 6 + fs/bs2ramfs/Makefile | 1 + fs/bs2ramfs/bs2ramfs.rs | 363 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 372 insertions(+) create mode 100644 fs/bs2ramfs/Kconfig create mode 100644 fs/bs2ramfs/Makefile create mode 100644 fs/bs2ramfs/bs2ramfs.rs diff --git a/fs/Kconfig b/fs/Kconfig index 141a856c50e717..e486325a8697a8 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -20,6 +20,7 @@ if BLOCK config FS_IOMAP bool +source "fs/bs2ramfs/Kconfig" source "fs/ext2/Kconfig" source "fs/ext4/Kconfig" source "fs/jbd2/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 9c708e1fbe8fb3..d7d5e1c97d64fa 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_NETFS_SUPPORT) += netfs/ obj-$(CONFIG_FSCACHE) += fscache/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ obj-$(CONFIG_EXT4_FS) += ext4/ +obj-$(CONFIG_BS2_RAMFS) += bs2ramfs/ # We place ext4 before ext2 so that clean ext3 root fs's do NOT mount using the # ext2 driver, which doesn't know about journalling! Explicitly request ext2 # by giving the rootfstype= parameter. diff --git a/fs/bs2ramfs/Kconfig b/fs/bs2ramfs/Kconfig new file mode 100644 index 00000000000000..c6b47f488849b4 --- /dev/null +++ b/fs/bs2ramfs/Kconfig @@ -0,0 +1,6 @@ +config BS2_RAMFS + tristate "BS2 ramfs" + depends on MMU && RUST + default n + help + Enables the rust implementation of ramfs. diff --git a/fs/bs2ramfs/Makefile b/fs/bs2ramfs/Makefile new file mode 100644 index 00000000000000..dbc55398e16511 --- /dev/null +++ b/fs/bs2ramfs/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_BS2_RAMFS) += bs2ramfs.o diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs new file mode 100644 index 00000000000000..a5573005bea318 --- /dev/null +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -0,0 +1,363 @@ +#![no_std] +#![feature(allocator_api, global_asm)] + +use alloc::boxed::Box; +use core::{mem, ptr}; + +use kernel::{ + bindings, c_types::*, declare_fs_type, file::File, file_operations::PointerWrapper, prelude::*, + CStr, Error, Mode, +}; + +// should be renamed at some point +use kernel::fs::{ + DeclaredFileSystemType, FileSystem, FileSystemBase, FileSystemType, SuperBlock, + DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, + DEFAULT_SUPER_OPS, +}; + +type Inode = bindings::inode; + +const PAGE_SHIFT: u32 = 12; // x86 (maybe) +const MAX_LFS_FILESIZE: c_longlong = c_longlong::MAX; +const BS2RAMFS_MAGIC: u64 = 0x858458f6; // ~~one less than~~ ramfs, should not clash with anything (maybe) + +extern "C" { + fn rust_helper_dget(dentry: *mut bindings::dentry); + fn rust_helper_mapping_set_unevictable(mapping: *mut bindings::address_space); + fn rust_helper_mapping_set_gfp_mask( + mapping: *mut bindings::address_space, + mask: bindings::gfp_t, + ); + static RUST_HELPER_GFP_HIGHUSER: bindings::gfp_t; +} + +module! { + type: BS2Ramfs, + name: b"bs2ramfs", + author: b"Rust for Linux Contributors", + description: b"RAMFS", + license: b"GPL v2", +} + +struct BS2Ramfs; + +impl FileSystemBase for BS2Ramfs { + const NAME: CStr<'static> = kernel::cstr!("bs2ramfs_name"); + const FS_FLAGS: c_int = bindings::FS_USERNS_MOUNT as _; + const OWNER: *mut bindings::module = ptr::null_mut(); + + fn mount( + fs_type: &'_ mut FileSystemType, + flags: c_int, + device_name: CStr, + data: Option<&mut Self::MountOptions>, + ) -> KernelResult<*mut bindings::dentry> { + Self::mount_nodev(flags, data) + } + + // fn kill_superblock(sb: &mut SuperBlock) { + // unreachable!() + // } + unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { + let _ = Box::from_raw(mem::replace(&mut (*sb).s_fs_info, ptr::null_mut())); + bindings::kill_litter_super(sb); + } + + fn fill_super( + sb: &mut SuperBlock, + data: Option<&mut Self::MountOptions>, + silent: c_int, + ) -> KernelResult { + unsafe { ramfs_fill_super_impl(sb, data, silent) } + } +} +kernel::declare_fs_type!(BS2Ramfs, BS2RAMFS_FS_TYPE); + +impl KernelModule for BS2Ramfs { + fn init() -> KernelResult { + pr_emerg!("bs2 ramfs in action"); + Self::register().map(move |_| Self) + } +} + +impl Drop for BS2Ramfs { + fn drop(&mut self) { + let _ = Self::unregister(); + pr_info!("bs2 ramfs out of action"); + } +} + +struct ramfs_mount_opts { + mode: bindings::mode_t, +} + +struct ramfs_fs_info { + mount_opts: ramfs_mount_opts, +} + +const RAMFS_DEFAULT_MODE: Mode = Mode::from_int(0o775); + +unsafe extern "C" fn ramfs_mmu_get_unmapped_area( + file: *mut bindings::file, + addr: c_ulong, + len: c_ulong, + pgoff: c_ulong, + flags: c_ulong, +) -> c_ulong { + pr_emerg!( + "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" + ); + unimplemented!() +} + +unsafe extern "C" fn ramfs_show_options( + m: *mut bindings::seq_file, + root: *mut bindings::dentry, +) -> c_int { + pr_emerg!("ramfs show options, doing nothing"); + 0 +} + +const RAMFS_FILE_OPS: bindings::file_operations = bindings::file_operations { + read_iter: Some(bindings::generic_file_read_iter), + write_iter: Some(bindings::generic_file_write_iter), + mmap: Some(bindings::generic_file_mmap), + fsync: Some(bindings::noop_fsync), + splice_read: Some(bindings::generic_file_splice_read), + splice_write: Some(bindings::iter_file_splice_write), + llseek: Some(bindings::generic_file_llseek), + get_unmapped_area: Some(ramfs_mmu_get_unmapped_area), + ..DEFAULT_FILE_OPERATIONS +}; + +static ramfs_ops: bindings::super_operations = bindings::super_operations { + statfs: Some(bindings::simple_statfs), + drop_inode: Some(bindings::generic_delete_inode), + show_options: Some(ramfs_show_options), + ..DEFAULT_SUPER_OPS +}; + +static ramfs_aops: bindings::address_space_operations = bindings::address_space_operations { + readpage: Some(bindings::simple_readpage), + write_begin: Some(bindings::simple_write_begin), + write_end: Some(bindings::simple_write_end), + set_page_dirty: Some(bindings::__set_page_dirty_nobuffers), + ..DEFAULT_ADDRESS_SPACE_OPERATIONS +}; + +// impl FileOperations for BS2Ramfs // niklas: I think it's another struct, not BS2Ramfs + +static ramfs_file_inode_ops: bindings::inode_operations = bindings::inode_operations { + setattr: Some(bindings::simple_setattr), + getattr: Some(bindings::simple_getattr), + ..DEFAULT_INODE_OPERATIONS +}; + +#[no_mangle] +pub unsafe fn ramfs_get_inode( + sb: *mut bindings::super_block, + dir: *mut Inode, + mode: bindings::mode_t, + dev: bindings::dev_t, +) -> *mut Inode { + let inode = bindings::new_inode(sb); + + if let Some(inode @ &mut _) = inode.as_mut() { + inode.i_ino = bindings::get_next_ino() as _; + bindings::inode_init_owner(&mut bindings::init_user_ns as *mut _, inode, dir, mode as _); + (*inode.i_mapping).a_ops = &ramfs_aops; + rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); + rust_helper_mapping_set_unevictable(inode.i_mapping); + inode.i_atime = bindings::current_time(inode); + inode.i_mtime = inode.i_atime; + inode.i_ctime = inode.i_atime; + match mode & Mode::S_IFMT.as_int() as bindings::mode_t { + bindings::S_IFREG => { + inode.i_op = &ramfs_file_inode_ops; + inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; + } + bindings::S_IFDIR => { + inode.i_op = &ramfs_dir_inode_ops; + inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; + bindings::inc_nlink(inode); + } + bindings::S_IFLNK => { + inode.i_op = &bindings::page_symlink_inode_operations; + bindings::inode_nohighmem(inode); + } + _ => { + bindings::init_special_inode(inode, mode as _, dev); + } + } + } + + inode +} + +unsafe extern "C" fn ramfs_mknod( + ns: *mut bindings::user_namespace, + dir: *mut Inode, + dentry: *mut bindings::dentry, + mode: bindings::umode_t, + dev: bindings::dev_t, +) -> i32 { + let inode = ramfs_get_inode((*dir).i_sb, dir, mode as _, dev); + + if !inode.is_null() { + bindings::d_instantiate(dentry, inode); + rust_helper_dget(dentry); + (*dir).i_ctime = bindings::current_time(dir); + (*dir).i_mtime = (*dir).i_ctime; + 0 + } else { + Error::ENOSPC.to_kernel_errno() + } +} + +unsafe extern "C" fn ramfs_mkdir( + ns: *mut bindings::user_namespace, + dir: *mut Inode, + dentry: *mut bindings::dentry, + mode: bindings::umode_t, +) -> i32 { + if ramfs_mknod( + ns, + dir, + dentry, + mode | Mode::S_IFDIR.as_int() as bindings::umode_t, + 0, + ) < 0 + { + bindings::inc_nlink(dir); + } + 0 +} + +unsafe extern "C" fn ramfs_create( + ns: *mut bindings::user_namespace, + dir: *mut Inode, + dentry: *mut bindings::dentry, + mode: bindings::umode_t, + excl: bool, +) -> i32 { + ramfs_mknod( + ns, + dir, + dentry, + mode | Mode::S_IFREG.as_int() as bindings::umode_t, + 0, + ) +} + +#[no_mangle] +unsafe extern "C" fn ramfs_symlink( + ns: *mut bindings::user_namespace, + dir: *mut Inode, + dentry: *mut bindings::dentry, + symname: *const c_char, +) -> i32 { + pr_info!("in symlink"); + let inode = ramfs_get_inode( + (*dir).i_sb, + dir, + (Mode::S_IFLNK | Mode::S_IRWXUGO).as_int() as _, + 0, + ); + pr_info!("got inode {:?}", inode); + + if inode.is_null() { + return Error::ENOSPC.to_kernel_errno(); + } + + let l = bindings::strlen(symname) + 1; + pr_info!("str has len {:?}", l); + let ret = bindings::page_symlink(inode, symname, l as _); + if ret == 0 { + pr_info!("page_symlink is ok"); + bindings::d_instantiate(dentry, inode); + pr_info!("d_instantiate is ok"); + rust_helper_dget(dentry); + pr_info!("dget is ok"); + (*dir).i_mtime = bindings::current_time(dir); + (*dir).i_ctime = (*dir).i_mtime; + pr_info!("current_time is ok"); + } else { + bindings::iput(inode); + pr_info!("iput is ok"); + } + ret +} + +static ramfs_dir_inode_ops: bindings::inode_operations = bindings::inode_operations { + create: Some(ramfs_create), + lookup: Some(bindings::simple_lookup), + link: Some(bindings::simple_link), + unlink: Some(bindings::simple_unlink), + symlink: Some(ramfs_symlink), + mkdir: Some(ramfs_mkdir), + rmdir: Some(bindings::simple_rmdir), + mknod: Some(ramfs_mknod), + rename: Some(bindings::simple_rename), + ..DEFAULT_INODE_OPERATIONS +}; + +// #[no_mangle] +// unsafe extern "C" fn ramfs_fill_super( +// sb: *mut bindings::super_block, +// data: *mut c_void, +// silent: c_int, +// ) -> i32 { +// pr_emerg!("Reached ramfs_fill_super (not_impl)"); +// match ramfs_fill_super_impl(sb, data, silent) { +// Ok(_) => 0, +// Err(e) => e.to_kernel_errno(), +// } +// } + +#[no_mangle] +unsafe fn ramfs_fill_super_impl( + sb: *mut bindings::super_block, + _data: Option<&mut ::MountOptions>, + silent: c_int, +) -> KernelResult { + pr_emerg!("Reached ramfs_fill_super_impl"); + let mut sb = &mut *sb; + sb.s_fs_info = ptr::null_mut(); + + pr_emerg!("Reached ramfs_super_impl:Boxleak"); + // freed in kill_superblock + let fsi = Box::leak(Box::try_new(ramfs_fs_info { + mount_opts: ramfs_mount_opts { mode: 0o775 }, + })?); + sb.s_fs_info = fsi as *mut _ as *mut _; + + sb.s_maxbytes = MAX_LFS_FILESIZE; + sb.s_blocksize = kernel::PAGE_SIZE as _; + sb.s_blocksize_bits = PAGE_SHIFT as _; + sb.s_magic = BS2RAMFS_MAGIC; + sb.s_op = &ramfs_ops as *const _ as *mut _; + sb.s_time_gran = 1; + + pr_emerg!("SB members set"); + let inode = ramfs_get_inode( + sb as *mut _, + ptr::null_mut(), + (Mode::S_IFDIR.as_int() as bindings::mode_t | fsi.mount_opts.mode) as _, + 0, + ); + + pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); + // niklas: added because I saw it in ctiedt/rsramfs + if inode.is_null() { + return Err(Error::ENOMEM); + } + sb.s_root = bindings::d_make_root(inode); + pr_emerg!("(rust) s_root: {:?}", sb.s_root); + + if sb.s_root.is_null() { + Err(Error::ENOMEM) + } else { + Ok(()) + } +} From 1f1b1ff3580bab8b902c6faadcfd7ccccab3be42 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 16:58:59 +0200 Subject: [PATCH 06/58] add `b` and `scp_all` helper scripts --- b | 8 ++++++++ scp_all | 13 +++++++++++++ 2 files changed, 21 insertions(+) create mode 100755 b create mode 100755 scp_all diff --git a/b b/b new file mode 100755 index 00000000000000..db8323e252fb7d --- /dev/null +++ b/b @@ -0,0 +1,8 @@ +#!/bin/sh + +set -x +REPO_DIR=$(dirname $0) +MOD_DIR=$(realpath $REPO_DIR/_mod_inst) +BUILD_DIR=$(realpath $REPO_DIR/bs2build/) + +RUSTUP_TOOLCHAIN="nightly-2021-02-20" make O="$BUILD_DIR" CC=clang LLVM=1 ARCH=x86_64 INSTALL_MOD_PATH="$MOD_DIR" $@ diff --git a/scp_all b/scp_all new file mode 100755 index 00000000000000..2f30b646446f00 --- /dev/null +++ b/scp_all @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e +set -x + +REPO_DIR=`dirname $0` + +$REPO_DIR/b -j12 +$REPO_DIR/b modules_install +rm $REPO_DIR/_mod_inst/lib/modules/*/{build,source} +scp -P 2222 $REPO_DIR/bs2build/arch/x86_64/boot/bzImage root@127.0.0.1:/boot/vmlinuz-rust +scp -r -P 2222 $REPO_DIR/_mod_inst/lib/* root@127.0.0.1:/lib/ +# ssh -p 2222 root@127.0.0.1 "systemctl reboot --boot-loader-entry=linux-rust.conf" From b6bf8650ca4fe196141c229b39d70ec7a334fa6c Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 17:31:46 +0200 Subject: [PATCH 07/58] kernel crate & bs2ramfs: Updates from rebase This mainly includes: - `sed -i 's/KernelResult/Result/g' rust/kernel/**/*.rs` - fixing some `CStr`s - adding small things I missed when rebasing I tested with the VM and everything seems to work. Namely, ```shell $ ./run.sh $ echo a > bs3/a $ cat bs3/a a ``` worked, so it should all be good. I think there are some new compiler warnings, we'll have to see through them some other time :^) --- fs/bs2ramfs/bs2ramfs.rs | 15 +++++++-------- rust/kernel/error.rs | 2 +- rust/kernel/fs.rs | 20 ++++++++++---------- rust/kernel/super_block.rs | 4 ++-- rust/kernel/types.rs | 2 +- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index a5573005bea318..411ae5de9aa75d 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -5,8 +5,7 @@ use alloc::boxed::Box; use core::{mem, ptr}; use kernel::{ - bindings, c_types::*, declare_fs_type, file::File, file_operations::PointerWrapper, prelude::*, - CStr, Error, Mode, + bindings, c_types::*, declare_fs_type, file::File, prelude::*, str::CStr, Error, Mode, }; // should be renamed at some point @@ -43,16 +42,16 @@ module! { struct BS2Ramfs; impl FileSystemBase for BS2Ramfs { - const NAME: CStr<'static> = kernel::cstr!("bs2ramfs_name"); + const NAME: &'static CStr = kernel::c_str!("bs2ramfs_name"); const FS_FLAGS: c_int = bindings::FS_USERNS_MOUNT as _; const OWNER: *mut bindings::module = ptr::null_mut(); fn mount( fs_type: &'_ mut FileSystemType, flags: c_int, - device_name: CStr, + device_name: &CStr, data: Option<&mut Self::MountOptions>, - ) -> KernelResult<*mut bindings::dentry> { + ) -> Result<*mut bindings::dentry> { Self::mount_nodev(flags, data) } @@ -68,14 +67,14 @@ impl FileSystemBase for BS2Ramfs { sb: &mut SuperBlock, data: Option<&mut Self::MountOptions>, silent: c_int, - ) -> KernelResult { + ) -> Result { unsafe { ramfs_fill_super_impl(sb, data, silent) } } } kernel::declare_fs_type!(BS2Ramfs, BS2RAMFS_FS_TYPE); impl KernelModule for BS2Ramfs { - fn init() -> KernelResult { + fn init() -> Result { pr_emerg!("bs2 ramfs in action"); Self::register().map(move |_| Self) } @@ -320,7 +319,7 @@ unsafe fn ramfs_fill_super_impl( sb: *mut bindings::super_block, _data: Option<&mut ::MountOptions>, silent: c_int, -) -> KernelResult { +) -> Result { pr_emerg!("Reached ramfs_fill_super_impl"); let mut sb = &mut *sb; sb.s_fs_info = ptr::null_mut(); diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 3479bf1e0b26bb..54fa7fbf8f6fbc 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -74,7 +74,7 @@ impl Error { Self(p as _) } - pub fn parse_ptr(p: *mut T) -> KernelResult<*mut T> { + pub fn parse_ptr(p: *mut T) -> Result<*mut T> { if !Self::is_err_ptr(p as _) { Ok(p) } else { diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 83d092441fc0c3..dc034ff37f8867 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -2,7 +2,7 @@ use alloc::boxed::Box; use core::{convert::TryFrom, mem, ptr}; use crate::ret_err_ptr; -use crate::{bindings, buffer::Buffer, c_types::*, prelude::*, CStr, Error, KernelResult}; +use crate::{bindings, buffer::Buffer, c_types::*, prelude::*, str::CStr, Error, Result}; pub type FileSystemType = bindings::file_system_type; pub type SuperBlock = bindings::super_block; @@ -10,7 +10,7 @@ pub type SuperBlock = bindings::super_block; pub trait FileSystemBase { type MountOptions = c_void; - const NAME: CStr<'static>; + const NAME: &'static CStr; const FS_FLAGS: c_int; const OWNER: *mut bindings::module; @@ -18,9 +18,9 @@ pub trait FileSystemBase { fn mount( fs_type: &'_ mut FileSystemType, flags: c_int, - device_name: CStr, + device_name: &CStr, data: Option<&mut Self::MountOptions>, - ) -> KernelResult<*mut bindings::dentry>; + ) -> Result<*mut bindings::dentry>; // fn kill_superblock(sb: &mut SuperBlock); @@ -34,7 +34,7 @@ pub trait FileSystemBase { ) -> *mut bindings::dentry { pr_emerg!("in mount_raw"); let fs_type = &mut *fs_type; - let device_name = CStr::from_ptr(device_name); + let device_name = CStr::from_char_ptr(device_name); let data = (data as *mut Self::MountOptions).as_mut(); ret_err_ptr!(Self::mount(fs_type, flags, device_name, data)) } @@ -78,7 +78,7 @@ pub trait FileSystemBase { _sb: &mut SuperBlock, _data: Option<&mut Self::MountOptions>, _silent: c_int, - ) -> KernelResult { + ) -> Result { pr_emerg!("Using default FileSystem::fill_super"); Ok(()) } @@ -105,7 +105,7 @@ pub trait DeclaredFileSystemType: FileSystemBase { macro_rules! declare_fs_type { ($T:ty, $S:ident) => { static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { - name: <$T as $crate::fs::FileSystemBase>::NAME.as_str() as *const _ as *const _, + name: <$T as $crate::fs::FileSystemBase>::NAME.as_char_ptr() as *const _, fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, mount: Some(<$T as $crate::fs::FileSystemBase>::mount_raw), kill_sb: Some(<$T as $crate::fs::FileSystemBase>::kill_sb_raw), @@ -121,7 +121,7 @@ macro_rules! declare_fs_type { } pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { - fn register() -> KernelResult { + fn register() -> Result { let err = unsafe { bindings::register_filesystem(Self::file_system_type()) }; if err == 0 { Ok(()) @@ -130,7 +130,7 @@ pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { } } - fn unregister() -> KernelResult { + fn unregister() -> Result { let err = unsafe { bindings::unregister_filesystem(Self::file_system_type()) }; if err == 0 { Ok(()) @@ -142,7 +142,7 @@ pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { fn mount_nodev( flags: c_int, data: Option<&mut Self::MountOptions>, - ) -> KernelResult<*mut bindings::dentry> { + ) -> Result<*mut bindings::dentry> { Error::parse_ptr(unsafe { bindings::mount_nodev( Self::file_system_type(), diff --git a/rust/kernel/super_block.rs b/rust/kernel/super_block.rs index ce925d3c377ae8..e694bbd18d9d07 100644 --- a/rust/kernel/super_block.rs +++ b/rust/kernel/super_block.rs @@ -11,7 +11,7 @@ pub trait SuperBlock { pub fn from_inner(sb: &mut bindings::super_block) -> &mut Self; const statfs_implemented: bool = false; // TODO add a derive macro to auto-generate these - pub fn statfs(&mut self, dentry: Box, buf: Box) -> KernelResult<()> { + pub fn statfs(&mut self, dentry: Box, buf: Box) -> Result<()> { unreachable!() } @@ -25,7 +25,7 @@ pub trait SuperBlock { } const drop_inode_implemented: bool = false; - pub fn drop_inode(inode: Box) -> KernelResult { + pub fn drop_inode(inode: Box) -> Result { unreachable!() } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index bfc78a0db1e043..4bad906066b88f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -26,7 +26,7 @@ pub struct Mode(bindings::umode_t); impl Mode { /// Creates a [`Mode`] from an integer. - pub fn from_int(m: u16) -> Mode { + pub const fn from_int(m: u16) -> Mode { Mode(m) } From 1123b52961a80668f461d3b7fa036dd075050278 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 17:35:14 +0200 Subject: [PATCH 08/58] update RUST_TOOLCHAIN in `b` script to recommended nightly --- b | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b b/b index db8323e252fb7d..ba1f72a374a103 100755 --- a/b +++ b/b @@ -5,4 +5,4 @@ REPO_DIR=$(dirname $0) MOD_DIR=$(realpath $REPO_DIR/_mod_inst) BUILD_DIR=$(realpath $REPO_DIR/bs2build/) -RUSTUP_TOOLCHAIN="nightly-2021-02-20" make O="$BUILD_DIR" CC=clang LLVM=1 ARCH=x86_64 INSTALL_MOD_PATH="$MOD_DIR" $@ +RUSTUP_TOOLCHAIN="nightly-2021-05-29" make O="$BUILD_DIR" CC=clang LLVM=1 ARCH=x86_64 INSTALL_MOD_PATH="$MOD_DIR" $@ From 76fc0b7ad7a9c4e495ff6e35ceeb76249a190b5d Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 21:30:43 +0200 Subject: [PATCH 09/58] kernel crate: Use `error::from_kernel_err_ptr` instead of own method --- rust/kernel/error.rs | 20 -------------------- rust/kernel/fs.rs | 9 ++++++--- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 54fa7fbf8f6fbc..7a2819873cb8c4 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -11,10 +11,6 @@ use core::fmt; use core::num::TryFromIntError; use core::str::{self, Utf8Error}; -extern "C" { - fn rust_helper_is_err(p: *mut c_types::c_void) -> bool; -} - /// Generic integer kernel error. /// /// The kernel defines a set of integer generic error codes based on C and @@ -62,25 +58,9 @@ impl Error { self.0 } - pub fn is_err_ptr(p: *mut c_types::c_void) -> bool { - unsafe { rust_helper_is_err(p) } - } - pub fn as_err_ptr(&self) -> *mut T { self.0 as *mut _ } - - pub fn from_err_ptr(p: *mut c_types::c_void) -> Self { - Self(p as _) - } - - pub fn parse_ptr(p: *mut T) -> Result<*mut T> { - if !Self::is_err_ptr(p as _) { - Ok(p) - } else { - Err(Self::from_err_ptr(p as _)) - } - } } macro_rules! declare_error { diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index dc034ff37f8867..b008c4a9c8d845 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,8 +1,11 @@ use alloc::boxed::Box; -use core::{convert::TryFrom, mem, ptr}; +use core::ptr; use crate::ret_err_ptr; -use crate::{bindings, buffer::Buffer, c_types::*, prelude::*, str::CStr, Error, Result}; +use crate::{ + bindings, buffer::Buffer, c_types::*, error::from_kernel_err_ptr, prelude::*, str::CStr, Error, + Result, +}; pub type FileSystemType = bindings::file_system_type; pub type SuperBlock = bindings::super_block; @@ -143,7 +146,7 @@ pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { flags: c_int, data: Option<&mut Self::MountOptions>, ) -> Result<*mut bindings::dentry> { - Error::parse_ptr(unsafe { + from_kernel_err_ptr(unsafe { bindings::mount_nodev( Self::file_system_type(), flags, From 9b936aeaa59b029da8c724b029dd6ee43e0a724d Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 22:34:40 +0200 Subject: [PATCH 10/58] kernel crate: impl Dentry and some nice traits --- rust/kernel/dentry.rs | 52 +++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/rust/kernel/dentry.rs b/rust/kernel/dentry.rs index f3c8b226108c2d..9143acf1f15a0e 100644 --- a/rust/kernel/dentry.rs +++ b/rust/kernel/dentry.rs @@ -1,12 +1,13 @@ -use alloc::boxed::Box; -use core::{ - mem, - ops::{Deref, DerefMut}, -}; +use core::mem; +use core::ops::{Deref, DerefMut}; use crate::bindings; pub type Inode = bindings::inode; +extern "C" { + fn rust_helper_dget(dentry: *mut bindings::dentry); +} + #[repr(transparent)] pub struct Dentry(bindings::dentry); @@ -22,60 +23,63 @@ impl DerefMut for Dentry { &mut self.0 } } +impl AsRef for bindings::dentry { + fn as_ref(&self) -> &Dentry { + unsafe { mem::transmute(self) } + } +} +impl AsMut for bindings::dentry { + fn as_mut(&mut self) -> &mut Dentry { + unsafe { mem::transmute(self) } + } +} impl Dentry { - pub fn as_raw_inner(self: Box) -> *mut bindings::dentry { - Box::into_raw(self) as *mut _ + pub fn as_ptr_mut(&mut self) -> *mut bindings::dentry { + self.deref_mut() as *mut _ } pub fn make_root(inode: &mut Inode) -> Option<&mut Self> { - unsafe { - Some(bindings::d_make_root(inode as *mut _)) - .filter(|p| !p.is_null()) - .map(|p| mem::transmute(&mut *p)) - } + unsafe { (bindings::d_make_root(inode as *mut _) as *mut Self).as_mut() } } pub fn lookup(&mut self, query: *const bindings::qstr) -> Option<&mut Self> { - unsafe { - Some(bindings::d_lookup(&mut self.0 as *mut _, query)) - .filter(|p| !p.is_null()) - .map(|p| mem::transmute(&mut *p)) - } + unsafe { (bindings::d_lookup(self.as_ptr_mut(), query) as *mut Self).as_mut() } } pub fn get(&mut self) { - // couldn't find in bindings, lol - unimplemented!() + // Note: while the original `dget` function also allows NULL as an argument, it doesn't do + // anything with it, so only wrapping the function for non-null pointers should be okay. + unsafe { rust_helper_dget(self.as_ptr_mut()) }; } pub fn put(&mut self) { unsafe { - bindings::dput(&mut self.0 as *mut _); + bindings::dput(self.as_ptr_mut()); } } pub fn drop_dentry(&mut self) { unsafe { - bindings::d_drop(&mut self.0 as *mut _); + bindings::d_drop(self.as_ptr_mut()); } } pub fn delete_dentry(&mut self) { unsafe { - bindings::d_delete(&mut self.0 as *mut _); + bindings::d_delete(self.as_ptr_mut()); } } pub fn add(&mut self, inode: &mut Inode) { unsafe { - bindings::d_add(&mut self.0 as *mut _, inode as *mut _); + bindings::d_add(self.as_ptr_mut(), inode as *mut _); } } pub fn instantiate(&mut self, inode: &mut Inode) { unsafe { - bindings::d_instantiate(&mut self.0 as *mut _, inode as *mut _); + bindings::d_instantiate(self.as_ptr_mut(), inode as *mut _); } } } From 3e73b137997453c79bd2277e66b3b8c8234ff2d4 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 30 May 2021 22:35:37 +0200 Subject: [PATCH 11/58] bs2ramfs: Use new Dentry wrappers and fix warnings I converted some names to their intended casing and put some underscores before unused variable names. I also added some Rust style where I saw something odd. --- fs/bs2ramfs/bs2ramfs.rs | 162 ++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 88 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 411ae5de9aa75d..b7cc008627b188 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -4,15 +4,12 @@ use alloc::boxed::Box; use core::{mem, ptr}; -use kernel::{ - bindings, c_types::*, declare_fs_type, file::File, prelude::*, str::CStr, Error, Mode, -}; +use kernel::{bindings, c_types::*, dentry::Dentry, prelude::*, str::CStr, Error, Mode}; // should be renamed at some point use kernel::fs::{ - DeclaredFileSystemType, FileSystem, FileSystemBase, FileSystemType, SuperBlock, - DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, - DEFAULT_SUPER_OPS, + FileSystem, FileSystemBase, FileSystemType, SuperBlock, DEFAULT_ADDRESS_SPACE_OPERATIONS, + DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, DEFAULT_SUPER_OPS, }; type Inode = bindings::inode; @@ -22,7 +19,6 @@ const MAX_LFS_FILESIZE: c_longlong = c_longlong::MAX; const BS2RAMFS_MAGIC: u64 = 0x858458f6; // ~~one less than~~ ramfs, should not clash with anything (maybe) extern "C" { - fn rust_helper_dget(dentry: *mut bindings::dentry); fn rust_helper_mapping_set_unevictable(mapping: *mut bindings::address_space); fn rust_helper_mapping_set_gfp_mask( mapping: *mut bindings::address_space, @@ -47,9 +43,9 @@ impl FileSystemBase for BS2Ramfs { const OWNER: *mut bindings::module = ptr::null_mut(); fn mount( - fs_type: &'_ mut FileSystemType, + _fs_type: &'_ mut FileSystemType, flags: c_int, - device_name: &CStr, + _device_name: &CStr, data: Option<&mut Self::MountOptions>, ) -> Result<*mut bindings::dentry> { Self::mount_nodev(flags, data) @@ -87,22 +83,26 @@ impl Drop for BS2Ramfs { } } -struct ramfs_mount_opts { - mode: bindings::mode_t, +struct RamfsMountOpts { + pub mode: bindings::mode_t, } -struct ramfs_fs_info { - mount_opts: ramfs_mount_opts, +impl Default for RamfsMountOpts { + fn default() -> Self { + Self { mode: 0o775 } + } } -const RAMFS_DEFAULT_MODE: Mode = Mode::from_int(0o775); +struct RamfsFsInfo { + mount_opts: RamfsMountOpts, +} unsafe extern "C" fn ramfs_mmu_get_unmapped_area( - file: *mut bindings::file, - addr: c_ulong, - len: c_ulong, - pgoff: c_ulong, - flags: c_ulong, + _file: *mut bindings::file, + _addr: c_ulong, + _len: c_ulong, + _pgoff: c_ulong, + _flags: c_ulong, ) -> c_ulong { pr_emerg!( "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" @@ -111,8 +111,8 @@ unsafe extern "C" fn ramfs_mmu_get_unmapped_area( } unsafe extern "C" fn ramfs_show_options( - m: *mut bindings::seq_file, - root: *mut bindings::dentry, + _m: *mut bindings::seq_file, + _root: *mut bindings::dentry, ) -> c_int { pr_emerg!("ramfs show options, doing nothing"); 0 @@ -130,14 +130,14 @@ const RAMFS_FILE_OPS: bindings::file_operations = bindings::file_operations { ..DEFAULT_FILE_OPERATIONS }; -static ramfs_ops: bindings::super_operations = bindings::super_operations { +static RAMFS_OPS: bindings::super_operations = bindings::super_operations { statfs: Some(bindings::simple_statfs), drop_inode: Some(bindings::generic_delete_inode), show_options: Some(ramfs_show_options), ..DEFAULT_SUPER_OPS }; -static ramfs_aops: bindings::address_space_operations = bindings::address_space_operations { +static RAMFS_AOPS: bindings::address_space_operations = bindings::address_space_operations { readpage: Some(bindings::simple_readpage), write_begin: Some(bindings::simple_write_begin), write_end: Some(bindings::simple_write_end), @@ -147,7 +147,7 @@ static ramfs_aops: bindings::address_space_operations = bindings::address_space_ // impl FileOperations for BS2Ramfs // niklas: I think it's another struct, not BS2Ramfs -static ramfs_file_inode_ops: bindings::inode_operations = bindings::inode_operations { +static RAMFS_FILE_INODE_OPS: bindings::inode_operations = bindings::inode_operations { setattr: Some(bindings::simple_setattr), getattr: Some(bindings::simple_getattr), ..DEFAULT_INODE_OPERATIONS @@ -165,7 +165,7 @@ pub unsafe fn ramfs_get_inode( if let Some(inode @ &mut _) = inode.as_mut() { inode.i_ino = bindings::get_next_ino() as _; bindings::inode_init_owner(&mut bindings::init_user_ns as *mut _, inode, dir, mode as _); - (*inode.i_mapping).a_ops = &ramfs_aops; + (*inode.i_mapping).a_ops = &RAMFS_AOPS; rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); rust_helper_mapping_set_unevictable(inode.i_mapping); inode.i_atime = bindings::current_time(inode); @@ -173,11 +173,11 @@ pub unsafe fn ramfs_get_inode( inode.i_ctime = inode.i_atime; match mode & Mode::S_IFMT.as_int() as bindings::mode_t { bindings::S_IFREG => { - inode.i_op = &ramfs_file_inode_ops; + inode.i_op = &RAMFS_FILE_INODE_OPS; inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; } bindings::S_IFDIR => { - inode.i_op = &ramfs_dir_inode_ops; + inode.i_op = &RAMFS_DIR_INODE_OPS; inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; bindings::inc_nlink(inode); } @@ -195,7 +195,7 @@ pub unsafe fn ramfs_get_inode( } unsafe extern "C" fn ramfs_mknod( - ns: *mut bindings::user_namespace, + _ns: *mut bindings::user_namespace, dir: *mut Inode, dentry: *mut bindings::dentry, mode: bindings::umode_t, @@ -203,9 +203,13 @@ unsafe extern "C" fn ramfs_mknod( ) -> i32 { let inode = ramfs_get_inode((*dir).i_sb, dir, mode as _, dev); - if !inode.is_null() { - bindings::d_instantiate(dentry, inode); - rust_helper_dget(dentry); + if let Some(inode) = inode.as_mut() { + let dentry = dentry + .as_mut() + .expect("Called ramfs_mknod with NULL dentry") + .as_mut(); + dentry.instantiate(inode); + dentry.get(); (*dir).i_ctime = bindings::current_time(dir); (*dir).i_mtime = (*dir).i_ctime; 0 @@ -238,7 +242,7 @@ unsafe extern "C" fn ramfs_create( dir: *mut Inode, dentry: *mut bindings::dentry, mode: bindings::umode_t, - excl: bool, + _excl: bool, ) -> i32 { ramfs_mknod( ns, @@ -251,7 +255,7 @@ unsafe extern "C" fn ramfs_create( #[no_mangle] unsafe extern "C" fn ramfs_symlink( - ns: *mut bindings::user_namespace, + _ns: *mut bindings::user_namespace, dir: *mut Inode, dentry: *mut bindings::dentry, symname: *const c_char, @@ -263,32 +267,33 @@ unsafe extern "C" fn ramfs_symlink( (Mode::S_IFLNK | Mode::S_IRWXUGO).as_int() as _, 0, ); - pr_info!("got inode {:?}", inode); - - if inode.is_null() { - return Error::ENOSPC.to_kernel_errno(); - } - - let l = bindings::strlen(symname) + 1; - pr_info!("str has len {:?}", l); - let ret = bindings::page_symlink(inode, symname, l as _); - if ret == 0 { - pr_info!("page_symlink is ok"); - bindings::d_instantiate(dentry, inode); - pr_info!("d_instantiate is ok"); - rust_helper_dget(dentry); - pr_info!("dget is ok"); - (*dir).i_mtime = bindings::current_time(dir); - (*dir).i_ctime = (*dir).i_mtime; - pr_info!("current_time is ok"); + pr_info!("got inode ptr {:?}", inode); + if let Some(inode) = inode.as_mut() { + let l = bindings::strlen(symname) + 1; + pr_info!("str has len {:?}", l); + let ret = bindings::page_symlink(inode as *mut _, symname, l as _); + if ret == 0 { + pr_info!("page_symlink is ok"); + let dentry = dentry + .as_mut() + .expect("Called ramfs_symlink with NULL dentry") + .as_mut(); + dentry.instantiate(inode); + dentry.get(); + (*dir).i_mtime = bindings::current_time(dir); + (*dir).i_ctime = (*dir).i_mtime; + pr_info!("current_time is ok"); + } else { + bindings::iput(inode); + pr_info!("iput is ok"); + } + ret } else { - bindings::iput(inode); - pr_info!("iput is ok"); + Error::ENOSPC.to_kernel_errno() } - ret } -static ramfs_dir_inode_ops: bindings::inode_operations = bindings::inode_operations { +static RAMFS_DIR_INODE_OPS: bindings::inode_operations = bindings::inode_operations { create: Some(ramfs_create), lookup: Some(bindings::simple_lookup), link: Some(bindings::simple_link), @@ -301,33 +306,19 @@ static ramfs_dir_inode_ops: bindings::inode_operations = bindings::inode_operati ..DEFAULT_INODE_OPERATIONS }; -// #[no_mangle] -// unsafe extern "C" fn ramfs_fill_super( -// sb: *mut bindings::super_block, -// data: *mut c_void, -// silent: c_int, -// ) -> i32 { -// pr_emerg!("Reached ramfs_fill_super (not_impl)"); -// match ramfs_fill_super_impl(sb, data, silent) { -// Ok(_) => 0, -// Err(e) => e.to_kernel_errno(), -// } -// } - #[no_mangle] unsafe fn ramfs_fill_super_impl( sb: *mut bindings::super_block, _data: Option<&mut ::MountOptions>, - silent: c_int, + _silent: c_int, ) -> Result { pr_emerg!("Reached ramfs_fill_super_impl"); - let mut sb = &mut *sb; - sb.s_fs_info = ptr::null_mut(); + let mut sb = sb.as_mut().expect("ramfs_fill_super got NULL super block"); - pr_emerg!("Reached ramfs_super_impl:Boxleak"); + sb.s_fs_info = ptr::null_mut(); // freed in kill_superblock - let fsi = Box::leak(Box::try_new(ramfs_fs_info { - mount_opts: ramfs_mount_opts { mode: 0o775 }, + let fsi = Box::leak(Box::try_new(RamfsFsInfo { + mount_opts: Default::default(), })?); sb.s_fs_info = fsi as *mut _ as *mut _; @@ -335,28 +326,23 @@ unsafe fn ramfs_fill_super_impl( sb.s_blocksize = kernel::PAGE_SIZE as _; sb.s_blocksize_bits = PAGE_SHIFT as _; sb.s_magic = BS2RAMFS_MAGIC; - sb.s_op = &ramfs_ops as *const _ as *mut _; + sb.s_op = &RAMFS_OPS as *const _ as *mut _; sb.s_time_gran = 1; - pr_emerg!("SB members set"); + let inode = ramfs_get_inode( sb as *mut _, ptr::null_mut(), (Mode::S_IFDIR.as_int() as bindings::mode_t | fsi.mount_opts.mode) as _, 0, ); - pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); - // niklas: added because I saw it in ctiedt/rsramfs - if inode.is_null() { - return Err(Error::ENOMEM); - } - sb.s_root = bindings::d_make_root(inode); + // TODO: investigate if this really has to be set to NULL in case we run out of memory + sb.s_root = ptr::null_mut(); + sb.s_root = inode + .as_mut() + .and_then(Dentry::make_root) + .ok_or(Error::ENOMEM)? as *mut _ as *mut _; pr_emerg!("(rust) s_root: {:?}", sb.s_root); - - if sb.s_root.is_null() { - Err(Error::ENOMEM) - } else { - Ok(()) - } + Ok(()) } From 5a972ce5041e1a5954b30daa7ab887166534d796 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Tue, 1 Jun 2021 22:37:30 +0200 Subject: [PATCH 12/58] Update kernel.german.md --- kernel.german.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel.german.md b/kernel.german.md index f74405d54527a9..009760d550b0c0 100644 --- a/kernel.german.md +++ b/kernel.german.md @@ -8,12 +8,14 @@ Kernel holen (z.B. [`github.com/niklasmohrin/linux`](https://github.com/niklasmo Siehe [`quick-start.rst`](https://github.com/niklasmohrin/linux/blob/ramfs/Documentation/rust/quick-start.rst) für Toolchain. +Wir haben die zwei Skripte `b` und `scp_all` zusammengestellt. Insbesondere ist `b` ein Wrapper um den `make` command, der die Compiler Optionen setzt (also `rustup default` nicht verändert werden muss). Falls man die nicht benutzen möchte, hier unser vorherige Anleitung: + ```console $ mkdir -p builds/{kernel, modules} $ cd mylinuxclone $ make O=../builds/kernel defconfig # wir wollen das repo selbst nicht zum bauen benutzen $ cd ../builds/kernel -$ rustup default nightly-2021-02-20 +$ rustup default nightly-2021-05-29 $ make menuconfig # Rust Support auswählen, Rest erstmal egal $ make ARCH=x86_64 CC=clang -j12 # baut Kernel und gewählte Module ... From 43dea9031f48b759c6f51056bc321ada8c864cfe Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Tue, 1 Jun 2021 22:57:20 +0200 Subject: [PATCH 13/58] bs2ramfs: Inline ramfs_fill_super_impl into fill_super from FileSystemBase --- fs/bs2ramfs/bs2ramfs.rs | 81 +++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index b7cc008627b188..def090ddfbaefd 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -61,10 +61,44 @@ impl FileSystemBase for BS2Ramfs { fn fill_super( sb: &mut SuperBlock, - data: Option<&mut Self::MountOptions>, - silent: c_int, + _data: Option<&mut Self::MountOptions>, + _silent: c_int, ) -> Result { - unsafe { ramfs_fill_super_impl(sb, data, silent) } + pr_emerg!("Reached ramfs_fill_super_impl"); + + sb.s_fs_info = ptr::null_mut(); + // freed in kill_superblock + let fsi = Box::leak(Box::try_new(RamfsFsInfo { + mount_opts: Default::default(), + })?); + sb.s_fs_info = fsi as *mut _ as *mut _; + + sb.s_maxbytes = MAX_LFS_FILESIZE; + sb.s_blocksize = kernel::PAGE_SIZE as _; + sb.s_blocksize_bits = PAGE_SHIFT as _; + sb.s_magic = BS2RAMFS_MAGIC; + sb.s_op = &RAMFS_OPS as *const _ as *mut _; + sb.s_time_gran = 1; + pr_emerg!("SB members set"); + + unsafe { + let inode = ramfs_get_inode( + sb as *mut _, + ptr::null_mut(), + (Mode::S_IFDIR.as_int() as bindings::mode_t | fsi.mount_opts.mode) as _, + 0, + ); + pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); + // TODO: investigate if this really has to be set to NULL in case we run out of memory + sb.s_root = ptr::null_mut(); + sb.s_root = inode + .as_mut() + .and_then(Dentry::make_root) + .ok_or(Error::ENOMEM)? as *mut _ as *mut _; + } + pr_emerg!("(rust) s_root: {:?}", sb.s_root); + + Ok(()) } } kernel::declare_fs_type!(BS2Ramfs, BS2RAMFS_FS_TYPE); @@ -305,44 +339,3 @@ static RAMFS_DIR_INODE_OPS: bindings::inode_operations = bindings::inode_operati rename: Some(bindings::simple_rename), ..DEFAULT_INODE_OPERATIONS }; - -#[no_mangle] -unsafe fn ramfs_fill_super_impl( - sb: *mut bindings::super_block, - _data: Option<&mut ::MountOptions>, - _silent: c_int, -) -> Result { - pr_emerg!("Reached ramfs_fill_super_impl"); - let mut sb = sb.as_mut().expect("ramfs_fill_super got NULL super block"); - - sb.s_fs_info = ptr::null_mut(); - // freed in kill_superblock - let fsi = Box::leak(Box::try_new(RamfsFsInfo { - mount_opts: Default::default(), - })?); - sb.s_fs_info = fsi as *mut _ as *mut _; - - sb.s_maxbytes = MAX_LFS_FILESIZE; - sb.s_blocksize = kernel::PAGE_SIZE as _; - sb.s_blocksize_bits = PAGE_SHIFT as _; - sb.s_magic = BS2RAMFS_MAGIC; - sb.s_op = &RAMFS_OPS as *const _ as *mut _; - sb.s_time_gran = 1; - pr_emerg!("SB members set"); - - let inode = ramfs_get_inode( - sb as *mut _, - ptr::null_mut(), - (Mode::S_IFDIR.as_int() as bindings::mode_t | fsi.mount_opts.mode) as _, - 0, - ); - pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); - // TODO: investigate if this really has to be set to NULL in case we run out of memory - sb.s_root = ptr::null_mut(); - sb.s_root = inode - .as_mut() - .and_then(Dentry::make_root) - .ok_or(Error::ENOMEM)? as *mut _ as *mut _; - pr_emerg!("(rust) s_root: {:?}", sb.s_root); - Ok(()) -} From c0d20135b641d167385ece6387a7c1704fd8d71e Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Tue, 1 Jun 2021 23:17:50 +0200 Subject: [PATCH 14/58] kernel and bs2ramfs: implement kill_superblock_raw in terms of kill_superblock --- fs/bs2ramfs/bs2ramfs.rs | 9 ++---- rust/kernel/fs.rs | 62 +++++++++++++++-------------------------- 2 files changed, 26 insertions(+), 45 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index def090ddfbaefd..928040b1c6248a 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -51,12 +51,9 @@ impl FileSystemBase for BS2Ramfs { Self::mount_nodev(flags, data) } - // fn kill_superblock(sb: &mut SuperBlock) { - // unreachable!() - // } - unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { - let _ = Box::from_raw(mem::replace(&mut (*sb).s_fs_info, ptr::null_mut())); - bindings::kill_litter_super(sb); + fn kill_superblock(sb: &mut SuperBlock) { + let _ = unsafe { Box::from_raw(mem::replace(&mut sb.s_fs_info, ptr::null_mut())) }; + Self::kill_litter_super(sb); } fn fill_super( diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index b008c4a9c8d845..079f0d6d686070 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,10 +1,8 @@ -use alloc::boxed::Box; use core::ptr; use crate::ret_err_ptr; use crate::{ - bindings, buffer::Buffer, c_types::*, error::from_kernel_err_ptr, prelude::*, str::CStr, Error, - Result, + bindings, c_types::*, error::from_kernel_err_ptr, prelude::*, str::CStr, Error, Result, }; pub type FileSystemType = bindings::file_system_type; @@ -17,7 +15,6 @@ pub trait FileSystemBase { const FS_FLAGS: c_int; const OWNER: *mut bindings::module; - // TODO: is that a fair return type here? fn mount( fs_type: &'_ mut FileSystemType, flags: c_int, @@ -25,9 +22,7 @@ pub trait FileSystemBase { data: Option<&mut Self::MountOptions>, ) -> Result<*mut bindings::dentry>; - // fn kill_superblock(sb: &mut SuperBlock); - - // fn fill_superblock(sb: Box, data: Box, silent: bool); + fn kill_superblock(sb: &mut SuperBlock); unsafe extern "C" fn mount_raw( fs_type: *mut bindings::file_system_type, @@ -43,40 +38,12 @@ pub trait FileSystemBase { } unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { - // let sb = SuperBlock::from_raw(sb); - // self.kill_superblock(sb); - // let _ = SuperBlock::into_raw(sb); + let sb = sb + .as_mut() + .expect("FileSystemBase::kill_sb_raw got NULL super block"); + Self::kill_superblock(sb); } - // fn mount_bdev(flags: u32, dev_name: &CStr, data: Box) { - // bindings::mount_bdev( - // Self::file_system_type(), - // flags, - // CStr::into_raw(dev_name), - // MountOptions::into_raw(data), - // self.fill_super_raw - // ); - // } - - // unsafe extern "C" fn fill_super_raw(sb: *mut bindings::super_block, data: *mut c_void, silent: bool) { - // let sb = Box::from_raw(sb); - // let data = MountOptions::from_raw(data); - // self.fill_superblock(sb, data, silent); - // sb.s_magic = SuperBlock::MAGIC; - // sb.s_blocksize = SuperBlock::BLOCKSIZE; - // sb.s_blocksize_bits = SuperBlock::BLOCKSIZE_BITS; - // let s_ops = bindings::super_operations { - // alloc_inode: SuperBlock::alloc_inode_raw as *mut _, - // drop_inode: SuperBlock::drop_inode_raw as *mut _, - // statfs: SuperBlock::statfs_raw as *mut _, - // ..Default::defaults() - // }; - // sb.s_op = s_ops; - // // ... register SuperBlock (associated) dropt_node, statfs, constants - // let _ = Box::into_raw(sb); - // let _ = MountOptions::into_raw(data); - // } - fn fill_super( _sb: &mut SuperBlock, _data: Option<&mut Self::MountOptions>, @@ -156,6 +123,23 @@ pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { ) }) } + + // just moved here + // fn mount_bdev(flags: u32, dev_name: &CStr, data: Box) { + // bindings::mount_bdev( + // Self::file_system_type(), + // flags, + // CStr::into_raw(dev_name), + // MountOptions::into_raw(data), + // self.fill_super_raw + // ); + // } + + fn kill_litter_super(sb: &mut SuperBlock) { + unsafe { + bindings::kill_litter_super(sb as *mut _); + } + } } impl FileSystem for T {} From 043e0b056a60e9ef70144a25e011a744ef7b2136 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 01:29:18 +0200 Subject: [PATCH 15/58] kernel crate: Add Inode wrapper type --- rust/kernel/fs.rs | 2 + rust/kernel/fs/inode.rs | 119 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 rust/kernel/fs/inode.rs diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 079f0d6d686070..5197abc2addcb8 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,3 +1,5 @@ +pub mod inode; + use core::ptr; use crate::ret_err_ptr; diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs new file mode 100644 index 00000000000000..62fc738db49813 --- /dev/null +++ b/rust/kernel/fs/inode.rs @@ -0,0 +1,119 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, ptr}; + +use crate::bindings; +use crate::c_types::*; +use crate::fs::SuperBlock; +use crate::types::Mode; + +#[derive(PartialEq, Eq)] +pub enum UpdateATime { + Yes, + No, +} +#[derive(PartialEq, Eq)] +pub enum UpdateCTime { + Yes, + No, +} +#[derive(PartialEq, Eq)] +pub enum UpdateMTime { + Yes, + No, +} + +#[repr(transparent)] +pub struct Inode(bindings::inode); + +impl Inode { + pub fn as_ptr_mut(&mut self) -> *mut bindings::inode { + self.deref_mut() as *mut _ + } + + pub fn new(sb: &mut SuperBlock) -> Option<&mut Self> { + unsafe { + bindings::new_inode(sb as *mut _) + .as_mut() + .map(AsMut::as_mut) + } + } + + pub fn next_ino() -> u32 { + unsafe { bindings::get_next_ino() } // FIXME: why do the bindings not return c_int here? + } + + pub fn init_owner( + &mut self, + ns: &mut bindings::user_namespace, + directory: Option<&mut Inode>, + mode: Mode, + ) { + unsafe { + bindings::inode_init_owner( + ns as *mut _, + self.as_ptr_mut(), + directory + .map(Inode::as_ptr_mut) + .unwrap_or_else(ptr::null_mut), + mode.as_int(), + ); + } + } + + pub fn update_acm_time(&mut self, a: UpdateATime, c: UpdateCTime, m: UpdateMTime) { + let time = unsafe { bindings::current_time(self.as_ptr_mut()) }; + if a == UpdateATime::Yes { + self.i_atime = time; + } + if c == UpdateCTime::Yes { + self.i_ctime = time; + } + if m == UpdateMTime::Yes { + self.i_mtime = time; + } + } + + pub fn inc_nlink(&mut self) { + unsafe { + bindings::inc_nlink(self.as_ptr_mut()); + } + } + pub fn nohighmem(&mut self) { + unsafe { + bindings::inode_nohighmem(self.as_ptr_mut()); + } + } + pub fn init_special(&mut self, mode: Mode, device: bindings::dev_t) { + unsafe { + bindings::init_special_inode(self.as_ptr_mut(), mode.as_int(), device); + } + } + pub fn put(&mut self) { + unsafe { + bindings::iput(self.as_ptr_mut()); + } + } +} + +impl Deref for Inode { + type Target = bindings::inode; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Inode { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl AsRef for bindings::inode { + fn as_ref(&self) -> &Inode { + unsafe { mem::transmute(self) } + } +} +impl AsMut for bindings::inode { + fn as_mut(&mut self) -> &mut Inode { + unsafe { mem::transmute(self) } + } +} From 0ec99bb776bbd47258a29115b867468f3a44a24c Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 01:30:30 +0200 Subject: [PATCH 16/58] kernel crate: Move dentry.rs into fs and use new Inode wrapper type --- rust/kernel/fs.rs | 1 + rust/kernel/{ => fs}/dentry.rs | 8 ++++---- rust/kernel/lib.rs | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) rename rust/kernel/{ => fs}/dentry.rs (87%) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 5197abc2addcb8..f21673821454c2 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,3 +1,4 @@ +pub mod dentry; pub mod inode; use core::ptr; diff --git a/rust/kernel/dentry.rs b/rust/kernel/fs/dentry.rs similarity index 87% rename from rust/kernel/dentry.rs rename to rust/kernel/fs/dentry.rs index 9143acf1f15a0e..ee8dc7486138c9 100644 --- a/rust/kernel/dentry.rs +++ b/rust/kernel/fs/dentry.rs @@ -2,7 +2,7 @@ use core::mem; use core::ops::{Deref, DerefMut}; use crate::bindings; -pub type Inode = bindings::inode; +use crate::fs::inode::Inode; extern "C" { fn rust_helper_dget(dentry: *mut bindings::dentry); @@ -40,7 +40,7 @@ impl Dentry { } pub fn make_root(inode: &mut Inode) -> Option<&mut Self> { - unsafe { (bindings::d_make_root(inode as *mut _) as *mut Self).as_mut() } + unsafe { (bindings::d_make_root(inode.as_ptr_mut()) as *mut Self).as_mut() } } pub fn lookup(&mut self, query: *const bindings::qstr) -> Option<&mut Self> { @@ -73,13 +73,13 @@ impl Dentry { pub fn add(&mut self, inode: &mut Inode) { unsafe { - bindings::d_add(self.as_ptr_mut(), inode as *mut _); + bindings::d_add(self.as_ptr_mut(), inode.as_ptr_mut()); } } pub fn instantiate(&mut self, inode: &mut Inode) { unsafe { - bindings::d_instantiate(self.as_ptr_mut(), inode as *mut _); + bindings::d_instantiate(self.as_ptr_mut(), inode.as_ptr_mut()); } } } diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 74d035ec795091..fc56c7e0a0b0c6 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -44,7 +44,6 @@ pub mod bindings; pub mod buffer; pub mod c_types; pub mod chrdev; -pub mod dentry; #[macro_use] mod error; pub mod file; From bd13b1853fccc55934aa15a84edac45b18cc7ce2 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 01:31:03 +0200 Subject: [PATCH 17/58] kernel crate: derive PartialEq, Eq for Mode --- rust/kernel/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 4bad906066b88f..a9c10f92f074dc 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -21,7 +21,7 @@ use crate::sync::{Ref, RefCounted}; /// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h) /// /// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h) -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct Mode(bindings::umode_t); impl Mode { From 48c8ea4e7a857030382e5596ac9e28e2edfcb019 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 01:31:33 +0200 Subject: [PATCH 18/58] bs2ramfs: Use new Inode wrapper This also replaces some uses of bindings::mode_t with the Mode type from the kernel crate. There are still some things that require another indirection to be ported to Rust types, but most of the code we have now uses the new type. I think that wrapping the `i_mapping` field could be difficult to get right. --- fs/bs2ramfs/bs2ramfs.rs | 127 +++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 928040b1c6248a..e7131cc862516e 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -4,16 +4,16 @@ use alloc::boxed::Box; use core::{mem, ptr}; -use kernel::{bindings, c_types::*, dentry::Dentry, prelude::*, str::CStr, Error, Mode}; +use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; // should be renamed at some point use kernel::fs::{ + dentry::Dentry, + inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, FileSystem, FileSystemBase, FileSystemType, SuperBlock, DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, DEFAULT_SUPER_OPS, }; -type Inode = bindings::inode; - const PAGE_SHIFT: u32 = 12; // x86 (maybe) const MAX_LFS_FILESIZE: c_longlong = c_longlong::MAX; const BS2RAMFS_MAGIC: u64 = 0x858458f6; // ~~one less than~~ ramfs, should not clash with anything (maybe) @@ -79,19 +79,16 @@ impl FileSystemBase for BS2Ramfs { pr_emerg!("SB members set"); unsafe { + // TODO: investigate if this really has to be set to NULL in case we run out of memory + sb.s_root = ptr::null_mut(); let inode = ramfs_get_inode( - sb as *mut _, - ptr::null_mut(), - (Mode::S_IFDIR.as_int() as bindings::mode_t | fsi.mount_opts.mode) as _, + sb, + None, + Mode::S_IFDIR | Mode::from_int(fsi.mount_opts.mode as _), 0, ); pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); - // TODO: investigate if this really has to be set to NULL in case we run out of memory - sb.s_root = ptr::null_mut(); - sb.s_root = inode - .as_mut() - .and_then(Dentry::make_root) - .ok_or(Error::ENOMEM)? as *mut _ as *mut _; + sb.s_root = inode.and_then(Dentry::make_root).ok_or(Error::ENOMEM)? as *mut _ as *mut _; } pr_emerg!("(rust) s_root: {:?}", sb.s_root); @@ -185,92 +182,99 @@ static RAMFS_FILE_INODE_OPS: bindings::inode_operations = bindings::inode_operat }; #[no_mangle] -pub unsafe fn ramfs_get_inode( - sb: *mut bindings::super_block, - dir: *mut Inode, - mode: bindings::mode_t, +pub unsafe fn ramfs_get_inode<'a>( + sb: &'a mut bindings::super_block, + dir: Option<&'_ mut Inode>, + mode: Mode, dev: bindings::dev_t, -) -> *mut Inode { - let inode = bindings::new_inode(sb); +) -> Option<&'a mut Inode> { + Inode::new(sb).map(|inode| { + inode.i_ino = Inode::next_ino() as _; + inode.init_owner(&mut bindings::init_user_ns, dir, mode); - if let Some(inode @ &mut _) = inode.as_mut() { - inode.i_ino = bindings::get_next_ino() as _; - bindings::inode_init_owner(&mut bindings::init_user_ns as *mut _, inode, dir, mode as _); (*inode.i_mapping).a_ops = &RAMFS_AOPS; rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); rust_helper_mapping_set_unevictable(inode.i_mapping); - inode.i_atime = bindings::current_time(inode); - inode.i_mtime = inode.i_atime; - inode.i_ctime = inode.i_atime; - match mode & Mode::S_IFMT.as_int() as bindings::mode_t { - bindings::S_IFREG => { + + inode.update_acm_time(UpdateATime::Yes, UpdateCTime::Yes, UpdateMTime::Yes); + match mode & Mode::S_IFMT { + Mode::S_IFREG => { inode.i_op = &RAMFS_FILE_INODE_OPS; inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; } - bindings::S_IFDIR => { + Mode::S_IFDIR => { inode.i_op = &RAMFS_DIR_INODE_OPS; inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; - bindings::inc_nlink(inode); + inode.inc_nlink(); } - bindings::S_IFLNK => { + Mode::S_IFLNK => { inode.i_op = &bindings::page_symlink_inode_operations; - bindings::inode_nohighmem(inode); + inode.nohighmem(); } _ => { - bindings::init_special_inode(inode, mode as _, dev); + inode.init_special(mode, dev); } } - } - inode + inode + }) } unsafe extern "C" fn ramfs_mknod( _ns: *mut bindings::user_namespace, - dir: *mut Inode, + dir: *mut bindings::inode, dentry: *mut bindings::dentry, mode: bindings::umode_t, dev: bindings::dev_t, ) -> i32 { - let inode = ramfs_get_inode((*dir).i_sb, dir, mode as _, dev); - - if let Some(inode) = inode.as_mut() { + let dir = dir + .as_mut() + .expect("ramfs_mknod got NULL directory") + .as_mut(); + ramfs_get_inode( + dir.i_sb.as_mut().expect("dir has NULL super block"), + Some(dir), + Mode::from_int(mode), + dev, + ) + .map_or(Error::ENOSPC.to_kernel_errno(), move |inode| { let dentry = dentry .as_mut() .expect("Called ramfs_mknod with NULL dentry") .as_mut(); dentry.instantiate(inode); dentry.get(); - (*dir).i_ctime = bindings::current_time(dir); - (*dir).i_mtime = (*dir).i_ctime; + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); 0 - } else { - Error::ENOSPC.to_kernel_errno() - } + }) } unsafe extern "C" fn ramfs_mkdir( ns: *mut bindings::user_namespace, - dir: *mut Inode, + dir: *mut bindings::inode, dentry: *mut bindings::dentry, mode: bindings::umode_t, ) -> i32 { + let dir = dir + .as_mut() + .expect("ramfs_mkdir got NULL directory") + .as_mut(); if ramfs_mknod( ns, - dir, + dir.as_ptr_mut(), dentry, mode | Mode::S_IFDIR.as_int() as bindings::umode_t, 0, ) < 0 { - bindings::inc_nlink(dir); + dir.inc_nlink(); } 0 } unsafe extern "C" fn ramfs_create( ns: *mut bindings::user_namespace, - dir: *mut Inode, + dir: *mut bindings::inode, dentry: *mut bindings::dentry, mode: bindings::umode_t, _excl: bool, @@ -287,22 +291,26 @@ unsafe extern "C" fn ramfs_create( #[no_mangle] unsafe extern "C" fn ramfs_symlink( _ns: *mut bindings::user_namespace, - dir: *mut Inode, + dir: *mut bindings::inode, dentry: *mut bindings::dentry, symname: *const c_char, ) -> i32 { pr_info!("in symlink"); - let inode = ramfs_get_inode( - (*dir).i_sb, - dir, - (Mode::S_IFLNK | Mode::S_IRWXUGO).as_int() as _, + let dir = dir + .as_mut() + .expect("ramfs_symlink got NULL directory") + .as_mut(); + ramfs_get_inode( + dir.i_sb.as_mut().expect("dir had NULL super block"), + Some(dir), + Mode::S_IFLNK | Mode::S_IRWXUGO, 0, - ); - pr_info!("got inode ptr {:?}", inode); - if let Some(inode) = inode.as_mut() { + ) + .map_or(Error::ENOSPC.to_kernel_errno(), |inode| { + pr_info!("got inode ptr {:?}", inode.as_ptr_mut()); let l = bindings::strlen(symname) + 1; pr_info!("str has len {:?}", l); - let ret = bindings::page_symlink(inode as *mut _, symname, l as _); + let ret = bindings::page_symlink(inode.as_ptr_mut(), symname, l as _); if ret == 0 { pr_info!("page_symlink is ok"); let dentry = dentry @@ -311,17 +319,14 @@ unsafe extern "C" fn ramfs_symlink( .as_mut(); dentry.instantiate(inode); dentry.get(); - (*dir).i_mtime = bindings::current_time(dir); - (*dir).i_ctime = (*dir).i_mtime; + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); pr_info!("current_time is ok"); } else { - bindings::iput(inode); + inode.put(); pr_info!("iput is ok"); } ret - } else { - Error::ENOSPC.to_kernel_errno() - } + }) } static RAMFS_DIR_INODE_OPS: bindings::inode_operations = bindings::inode_operations { From d65b73fc43660f1f23edcada9b6379fe4197b4a7 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 18:46:55 +0200 Subject: [PATCH 19/58] kernel crate: Add `Error::parse_int` --- rust/kernel/error.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 7a2819873cb8c4..8caf60a5e3c027 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -6,8 +6,8 @@ use crate::{bindings, c_types, declare_constant_from_bindings, macros::DO_NEGATE, str::CStr}; use alloc::{alloc::AllocError, collections::TryReserveError}; -use core::convert::From; -use core::fmt; +use core::convert::{From, TryInto}; +use core::fmt::{self, Debug}; use core::num::TryFromIntError; use core::str::{self, Utf8Error}; @@ -23,6 +23,20 @@ use core::str::{self, Utf8Error}; pub struct Error(c_types::c_int); impl Error { + pub fn parse_int(value: T) -> Result + where + T: TryInto + Copy, + >::Error: Debug, + { + match value + .try_into() + .expect("Couldn't convert value given to Error::parse_int into c_int") + { + e if e.is_negative() => Err(Error::from_kernel_errno(e)), + _ => Ok(value), + } + } + /// Creates an [`Error`] from a kernel error code. /// /// It is a bug to pass an out-of-range `errno`. `EINVAL` would From 976b826e9949ca464676ad632231f1e0e41a4a72 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 18:52:07 +0200 Subject: [PATCH 20/58] kernel crate: Add `SeekFrom::into_pos_and_whence` --- rust/kernel/file_operations.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 7891a61695089f..5d987c2de922b9 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -79,6 +79,16 @@ pub enum SeekFrom { Current(i64), } +impl SeekFrom { + pub fn into_pos_and_whence(self) -> (i64, u32) { + match self { + SeekFrom::Start(off) => (off as _, bindings::SEEK_SET), + SeekFrom::End(off) => (off, bindings::SEEK_END), + SeekFrom::Current(off) => (off, bindings::SEEK_CUR), + } + } +} + unsafe extern "C" fn open_callback>( inode: *mut bindings::inode, file: *mut bindings::file, From 83bb30b9997dcfd77a8dfcd0b74fb873c153fff4 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 18:53:34 +0200 Subject: [PATCH 21/58] kernel crate: Add `fs::libfs_functions` module This also includes the first wrapper, `generic_file_llseek`. --- rust/kernel/fs.rs | 1 + rust/kernel/fs/libfs_functions.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 rust/kernel/fs/libfs_functions.rs diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index f21673821454c2..2faf99a46d8855 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,5 +1,6 @@ pub mod dentry; pub mod inode; +pub mod libfs_functions; use core::ptr; diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs new file mode 100644 index 00000000000000..fdc0fb8ccddf42 --- /dev/null +++ b/rust/kernel/fs/libfs_functions.rs @@ -0,0 +1,12 @@ +use crate::bindings; +use crate::error::Error; +use crate::file::File; +use crate::file_operations::SeekFrom; +use crate::Result; + +pub fn generic_file_llseek(file: &File, pos: SeekFrom) -> Result { + let (offset, whence) = pos.into_pos_and_whence(); + Error::parse_int( + unsafe { bindings::generic_file_llseek(file.ptr, offset as _, whence as _) } as _, + ) +} From 7eeb7dbf78cbc511afd60fd06c86cc06da184856 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 18:54:22 +0200 Subject: [PATCH 22/58] kernel crate: Add `Inode::set_file_operations` This method should be preferred over accessing the member variable directly, because it enforces an implementation of `file_operations::FileOperations`. For now, we added a `FileOpenAdapter` that doesn't return anything, because we currently don't need anything more complicated. --- rust/kernel/fs/inode.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index 62fc738db49813..72e1e92e5b0a56 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -3,6 +3,7 @@ use core::{mem, ptr}; use crate::bindings; use crate::c_types::*; +use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; use crate::fs::SuperBlock; use crate::types::Mode; @@ -93,6 +94,28 @@ impl Inode { bindings::iput(self.as_ptr_mut()); } } + + pub fn set_file_operations::Arg>>( + &mut self, + ) { + self.0.__bindgen_anon_3.i_fop = + unsafe { FileOperationsVtable::::build() }; + } +} + +pub struct NopFileOpenAdapter; + +// don't really understand what this means, but we need someone to impl it and chrdev also returns +// (), so let's stick to this for now +impl FileOpenAdapter for NopFileOpenAdapter { + type Arg = (); + + unsafe fn convert( + _inode: *mut bindings::inode, + _file: *mut bindings::file, + ) -> *const Self::Arg { + &() + } } impl Deref for Inode { From 61c0ac6ad4b377a43bc40d359228142c67f6ec25 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 2 Jun 2021 18:56:37 +0200 Subject: [PATCH 23/58] bs2ramfs: Use `Inode::set_file_operations` This commit adds the call to `Inode::set_file_operations`, the `FileOperations` implementation is not done yet though. --- fs/bs2ramfs/bs2ramfs.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index e7131cc862516e..03da2ee90f2a2f 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -4,14 +4,17 @@ use alloc::boxed::Box; use core::{mem, ptr}; +use kernel::file::File; +use kernel::file_operations::{FileOperations, SeekFrom}; use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; // should be renamed at some point use kernel::fs::{ dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, - FileSystem, FileSystemBase, FileSystemType, SuperBlock, DEFAULT_ADDRESS_SPACE_OPERATIONS, - DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, DEFAULT_SUPER_OPS, + libfs_functions, FileSystem, FileSystemBase, FileSystemType, SuperBlock, + DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, + DEFAULT_SUPER_OPS, }; const PAGE_SHIFT: u32 = 12; // x86 (maybe) @@ -146,6 +149,17 @@ unsafe extern "C" fn ramfs_show_options( 0 } +#[derive(Default)] +struct Bs2RamfsFileOps; + +impl FileOperations for Bs2RamfsFileOps { + kernel::declare_file_operations!(seek); + + fn seek(&self, file: &File, pos: SeekFrom) -> Result { + libfs_functions::generic_file_llseek(file, pos) + } +} + const RAMFS_FILE_OPS: bindings::file_operations = bindings::file_operations { read_iter: Some(bindings::generic_file_read_iter), write_iter: Some(bindings::generic_file_write_iter), @@ -200,7 +214,8 @@ pub unsafe fn ramfs_get_inode<'a>( match mode & Mode::S_IFMT { Mode::S_IFREG => { inode.i_op = &RAMFS_FILE_INODE_OPS; - inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; + inode.set_file_operations::(); + // inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; } Mode::S_IFDIR => { inode.i_op = &RAMFS_DIR_INODE_OPS; From 91fc3c421119b13fdcd87da2e3db47353a586e03 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 3 Jun 2021 16:36:06 +0200 Subject: [PATCH 24/58] kernel crate: Implement generic_read_iter and noop_fsync --- fs/bs2ramfs/bs2ramfs.rs | 14 +++++++++++-- rust/kernel/file_operations.rs | 32 +++++++++++++++++++++++++++-- rust/kernel/fs/libfs_functions.rs | 34 ++++++++++++++++++++++++++++++- rust/kernel/iov_iter.rs | 2 +- 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 03da2ee90f2a2f..0102ba5d3e4094 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -5,8 +5,10 @@ use alloc::boxed::Box; use core::{mem, ptr}; use kernel::file::File; -use kernel::file_operations::{FileOperations, SeekFrom}; +use kernel::file_operations::{FileOperations, SeekFrom, Kiocb}; +use kernel::iov_iter::IovIter; use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; +use kernel::io_buffer::{IoBufferReader, IoBufferWriter}; // should be renamed at some point use kernel::fs::{ @@ -153,7 +155,15 @@ unsafe extern "C" fn ramfs_show_options( struct Bs2RamfsFileOps; impl FileOperations for Bs2RamfsFileOps { - kernel::declare_file_operations!(seek); + kernel::declare_file_operations!(custom_read_iter, fsync, seek); + + fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + libfs_functions::generic_file_read_iter(iocb, iter) + } + + fn fsync(&self, file: &File, start: u64, end: u64, datasync: bool) -> Result { + libfs_functions::noop_fsync(file, start, end, datasync) + } fn seek(&self, file: &File, pos: SeekFrom) -> Result { libfs_functions::generic_file_llseek(file, pos) diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 5d987c2de922b9..556354db5a6bc3 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -118,6 +118,21 @@ unsafe extern "C" fn read_callback( } } +pub type Kiocb = bindings::kiocb; + +unsafe extern "C" fn custom_read_iter_callback( + iocb: *mut bindings::kiocb, + raw_iter: *mut bindings::iov_iter, +) -> isize { + from_kernel_result! { + let mut iter = IovIter::from_ptr(raw_iter); + let file = (*iocb).ki_filp; + let f = &*((*file).private_data as *const T); + let read = f.read_iter(&mut *iocb, &mut iter)?; + Ok(read as _) + } +} + unsafe extern "C" fn read_iter_callback( iocb: *mut bindings::kiocb, raw_iter: *mut bindings::iov_iter, @@ -318,7 +333,12 @@ impl> FileOperationsVtable { } else { None }, - read_iter: if T::TO_USE.read_iter { + read_iter: if T::TO_USE.custom_read_iter { + // if T::TO_USE.read_iter { + // core::compile_error!("Should not declare default and custom read_iter"); + // } + Some(custom_read_iter_callback::) + } else if T::TO_USE.read_iter { Some(read_iter_callback::) } else { None @@ -359,6 +379,9 @@ pub struct ToUse { /// The `read_iter` field of [`struct file_operations`]. pub read_iter: bool, + /// The custom implementation of the `read_iter` field of [`struct file_operations`]. + pub custom_read_iter: bool, + /// The `write` field of [`struct file_operations`]. pub write: bool, @@ -389,6 +412,7 @@ pub struct ToUse { pub const USE_NONE: ToUse = ToUse { read: false, read_iter: false, + custom_read_iter: false, write: false, write_iter: false, seek: false, @@ -558,11 +582,15 @@ pub trait FileOperations: Send + Sync + Sized { /// Reads data from this file to the caller's buffer. /// - /// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`. + /// Corresponds to the `read` and - if no custom read_iter implementation is present - `read_iter` function pointers in `struct file_operations`. fn read(&self, _file: &File, _data: &mut T, _offset: u64) -> Result { Err(Error::EINVAL) } + fn read_iter(&self, _iocb: &mut Kiocb, _iter: &mut IovIter) -> Result { + Err(Error::EINVAL) + } + /// Writes data from the caller's buffer to this file. /// /// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`. diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index fdc0fb8ccddf42..210ccbb4c5cb5b 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -1,9 +1,41 @@ use crate::bindings; use crate::error::Error; use crate::file::File; -use crate::file_operations::SeekFrom; +use crate::file_operations::{SeekFrom, Kiocb}; +use crate::iov_iter::IovIter; use crate::Result; +pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + Error::parse_int( + unsafe { bindings::generic_file_read_iter(iocb as *mut _, iter.ptr) as _ } + ) +} +// pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { +// struct kiocb * iocb, struct iov_iter * iter + +// } + +// pub fn generic_file_write_iter(iocb: &mut Kiocb, from: &mut IovIter) -> Result { +// //ssize_t generic_file_write_iter(struct kiocb * iocb, struct iov_iter * from); +// } + +// pub fn generic_file_mmap() { + +// } + +pub fn noop_fsync(file: &File, start: u64, end: u64, datasync: bool) -> Result { + let start = start as _; + let end = start as _; + let datasync = if datasync { 1 } else { 0 }; + let res = unsafe { bindings::noop_fsync(file.ptr, start, end, datasync) }; + if res == 0 { + Ok(0) + } else { + Err(Error::EINVAL) + // Err(Error::from_kernel_errno(bindings::errno)) + } +} + pub fn generic_file_llseek(file: &File, pos: SeekFrom) -> Result { let (offset, whence) = pos.into_pos_and_whence(); Error::parse_int( diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs index 4a6f63e1650c19..0b3fcdcb6d6bd3 100644 --- a/rust/kernel/iov_iter.rs +++ b/rust/kernel/iov_iter.rs @@ -31,7 +31,7 @@ extern "C" { /// /// The pointer [`IovIter::ptr`] is non-null and valid. pub struct IovIter { - ptr: *mut bindings::iov_iter, + pub(crate) ptr: *mut bindings::iov_iter, } impl IovIter { From 7c747ae4e4b553fe76d6134c30542e66d0e7ed9e Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 3 Jun 2021 20:41:56 +0200 Subject: [PATCH 25/58] kernel crate: Add pretty simple Kiocb wrapper and fix typo in noop_fsync --- fs/bs2ramfs/bs2ramfs.rs | 3 +- rust/kernel/file_operations.rs | 5 ++- rust/kernel/fs.rs | 1 + rust/kernel/fs/kiocb.rs | 52 +++++++++++++++++++++++++++++++ rust/kernel/fs/libfs_functions.rs | 7 +++-- 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 rust/kernel/fs/kiocb.rs diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 0102ba5d3e4094..79507c9bc8dcc0 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -5,7 +5,8 @@ use alloc::boxed::Box; use core::{mem, ptr}; use kernel::file::File; -use kernel::file_operations::{FileOperations, SeekFrom, Kiocb}; +use kernel::file_operations::{FileOperations, SeekFrom}; +use kernel::fs::kiocb::Kiocb; use kernel::iov_iter::IovIter; use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; use kernel::io_buffer::{IoBufferReader, IoBufferWriter}; diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 556354db5a6bc3..2478ca55d54243 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -19,6 +19,7 @@ use crate::{ sync::CondVar, types::PointerWrapper, user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter}, + fs::kiocb::Kiocb, }; /// Wraps the kernel's `struct poll_table_struct`. @@ -118,8 +119,6 @@ unsafe extern "C" fn read_callback( } } -pub type Kiocb = bindings::kiocb; - unsafe extern "C" fn custom_read_iter_callback( iocb: *mut bindings::kiocb, raw_iter: *mut bindings::iov_iter, @@ -128,7 +127,7 @@ unsafe extern "C" fn custom_read_iter_callback( let mut iter = IovIter::from_ptr(raw_iter); let file = (*iocb).ki_filp; let f = &*((*file).private_data as *const T); - let read = f.read_iter(&mut *iocb, &mut iter)?; + let read = f.read_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; Ok(read as _) } } diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 2faf99a46d8855..90343dd04d2dd7 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,6 +1,7 @@ pub mod dentry; pub mod inode; pub mod libfs_functions; +pub mod kiocb; use core::ptr; diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs new file mode 100644 index 00000000000000..9e14afc7702b93 --- /dev/null +++ b/rust/kernel/fs/kiocb.rs @@ -0,0 +1,52 @@ +use core::mem; +use core::ops::{Deref, DerefMut}; + +use crate::file::{FileRef, File}; +use crate::bindings; +use crate::Result; + +#[repr(transparent)] +pub struct Kiocb(bindings::kiocb); + +impl Deref for Kiocb { + type Target = bindings::kiocb; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Kiocb { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl AsRef for bindings::kiocb { + fn as_ref(&self) -> &Kiocb { + unsafe { mem::transmute(self) } + } +} +impl AsMut for bindings::kiocb { + fn as_mut(&mut self) -> &mut Kiocb { + unsafe { mem::transmute(self) } + } +} + +impl Kiocb { + pub fn as_ptr_mut(&mut self) -> *mut bindings::kiocb { + self.deref_mut() as *mut _ + } + + pub fn get_file(&mut self) -> File { + let file = unsafe { (*(self.as_ptr_mut())).ki_filp }; + File { ptr: file } + } + + pub fn get_offset(&mut self) -> u64 { + let offset = unsafe { (*(self.as_ptr_mut())).ki_pos }; + offset as _ + } + + pub fn set_offset(&mut self, offset: u64) { + unsafe { (*(self.as_ptr_mut())).ki_pos = offset as _; } + } +} \ No newline at end of file diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 210ccbb4c5cb5b..41e656a48469a6 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -1,13 +1,14 @@ use crate::bindings; use crate::error::Error; use crate::file::File; -use crate::file_operations::{SeekFrom, Kiocb}; +use crate::file_operations::SeekFrom; +use crate::fs::kiocb::Kiocb; use crate::iov_iter::IovIter; use crate::Result; pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { Error::parse_int( - unsafe { bindings::generic_file_read_iter(iocb as *mut _, iter.ptr) as _ } + unsafe { bindings::generic_file_read_iter(iocb.as_ptr_mut(), iter.ptr) as _ } ) } // pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { @@ -25,7 +26,7 @@ pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result Result { let start = start as _; - let end = start as _; + let end = end as _; let datasync = if datasync { 1 } else { 0 }; let res = unsafe { bindings::noop_fsync(file.ptr, start, end, datasync) }; if res == 0 { From c0cd92daa3bad6f4d0fa7ef7920aacc0de264c53 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Fri, 4 Jun 2021 18:49:52 +0200 Subject: [PATCH 26/58] kernel crate: Allow for custom `read_iter` Previously, the kernel crate implemented `read_iter` in terms of `read`. Now, the default implementation of the trait method does just that, but it can also be overridden. --- fs/bs2ramfs/bs2ramfs.rs | 2 +- rust/kernel/file_operations.rs | 42 ++++++++++------------------------ 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 79507c9bc8dcc0..17da76ff53d089 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -156,7 +156,7 @@ unsafe extern "C" fn ramfs_show_options( struct Bs2RamfsFileOps; impl FileOperations for Bs2RamfsFileOps { - kernel::declare_file_operations!(custom_read_iter, fsync, seek); + kernel::declare_file_operations!(read_iter, fsync, seek); fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { libfs_functions::generic_file_read_iter(iocb, iter) diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 2478ca55d54243..f80bade114ed94 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -14,12 +14,12 @@ use crate::{ error::{Error, Result}, file::{File, FileRef}, from_kernel_result, + fs::kiocb::Kiocb, io_buffer::{IoBufferReader, IoBufferWriter}, iov_iter::IovIter, sync::CondVar, types::PointerWrapper, user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter}, - fs::kiocb::Kiocb, }; /// Wraps the kernel's `struct poll_table_struct`. @@ -119,7 +119,7 @@ unsafe extern "C" fn read_callback( } } -unsafe extern "C" fn custom_read_iter_callback( +unsafe extern "C" fn read_iter_callback( iocb: *mut bindings::kiocb, raw_iter: *mut bindings::iov_iter, ) -> isize { @@ -132,21 +132,6 @@ unsafe extern "C" fn custom_read_iter_callback( } } -unsafe extern "C" fn read_iter_callback( - iocb: *mut bindings::kiocb, - raw_iter: *mut bindings::iov_iter, -) -> isize { - from_kernel_result! { - let mut iter = unsafe { IovIter::from_ptr(raw_iter) }; - let file = unsafe { (*iocb).ki_filp }; - let offset = unsafe { (*iocb).ki_pos }; - let f = unsafe { &*((*file).private_data as *const T) }; - let read = f.read(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?; - unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() }; - Ok(read as _) - } -} - unsafe extern "C" fn write_callback( file: *mut bindings::file, buf: *const c_types::c_char, @@ -332,12 +317,7 @@ impl> FileOperationsVtable { } else { None }, - read_iter: if T::TO_USE.custom_read_iter { - // if T::TO_USE.read_iter { - // core::compile_error!("Should not declare default and custom read_iter"); - // } - Some(custom_read_iter_callback::) - } else if T::TO_USE.read_iter { + read_iter: if T::TO_USE.read_iter { Some(read_iter_callback::) } else { None @@ -378,9 +358,6 @@ pub struct ToUse { /// The `read_iter` field of [`struct file_operations`]. pub read_iter: bool, - /// The custom implementation of the `read_iter` field of [`struct file_operations`]. - pub custom_read_iter: bool, - /// The `write` field of [`struct file_operations`]. pub write: bool, @@ -411,7 +388,6 @@ pub struct ToUse { pub const USE_NONE: ToUse = ToUse { read: false, read_iter: false, - custom_read_iter: false, write: false, write_iter: false, seek: false, @@ -581,13 +557,19 @@ pub trait FileOperations: Send + Sync + Sized { /// Reads data from this file to the caller's buffer. /// - /// Corresponds to the `read` and - if no custom read_iter implementation is present - `read_iter` function pointers in `struct file_operations`. + /// Corresponds to the `read` function pointer in `struct file_operations`. fn read(&self, _file: &File, _data: &mut T, _offset: u64) -> Result { Err(Error::EINVAL) } - fn read_iter(&self, _iocb: &mut Kiocb, _iter: &mut IovIter) -> Result { - Err(Error::EINVAL) + /// Reads data from this file to the caller's buffer. + /// + /// Corresponds to the `read_iter` function pointer in `struct file_operations`. + fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + let file = iocb.get_file(); + let offset = iocb.get_offset(); + let read = self.read(&file, iter, offset)?; + Ok(read) } /// Writes data from the caller's buffer to this file. From 573849bcf1e1e677bbe9958b40c468b2616969b3 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Sun, 6 Jun 2021 14:36:56 +0200 Subject: [PATCH 27/58] kernel crate: Add remaining libfs_functions --- fs/bs2ramfs/bs2ramfs.rs | 53 ++++++------ rust/kernel/file_operations.rs | 139 ++++++++++++++++++++++++++++-- rust/kernel/fs/inode.rs | 1 - rust/kernel/fs/kiocb.rs | 3 +- rust/kernel/fs/libfs_functions.rs | 32 ++++--- 5 files changed, 177 insertions(+), 51 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 17da76ff53d089..d5d9ec7c842d5c 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -9,7 +9,6 @@ use kernel::file_operations::{FileOperations, SeekFrom}; use kernel::fs::kiocb::Kiocb; use kernel::iov_iter::IovIter; use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; -use kernel::io_buffer::{IoBufferReader, IoBufferWriter}; // should be renamed at some point use kernel::fs::{ @@ -131,19 +130,6 @@ struct RamfsFsInfo { mount_opts: RamfsMountOpts, } -unsafe extern "C" fn ramfs_mmu_get_unmapped_area( - _file: *mut bindings::file, - _addr: c_ulong, - _len: c_ulong, - _pgoff: c_ulong, - _flags: c_ulong, -) -> c_ulong { - pr_emerg!( - "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" - ); - unimplemented!() -} - unsafe extern "C" fn ramfs_show_options( _m: *mut bindings::seq_file, _root: *mut bindings::dentry, @@ -156,32 +142,43 @@ unsafe extern "C" fn ramfs_show_options( struct Bs2RamfsFileOps; impl FileOperations for Bs2RamfsFileOps { - kernel::declare_file_operations!(read_iter, fsync, seek); + kernel::declare_file_operations!(read_iter, write_iter, mmap, fsync, splice_read, splice_write, seek, get_unmapped_area); fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { libfs_functions::generic_file_read_iter(iocb, iter) } + fn write_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + libfs_functions::generic_file_write_iter(iocb, iter) + } + + fn mmap(&self, file: &File, vma: &mut bindings::vm_area_struct) -> Result { + libfs_functions::generic_file_mmap(file, vma) + } + fn fsync(&self, file: &File, start: u64, end: u64, datasync: bool) -> Result { libfs_functions::noop_fsync(file, start, end, datasync) } + fn get_unmapped_area(&self, file: &File, addr: u64, len: u64, pgoff: u64, flags: u64) -> Result { + pr_emerg!( + "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" + ); + unimplemented!() + } + fn seek(&self, file: &File, pos: SeekFrom) -> Result { libfs_functions::generic_file_llseek(file, pos) } -} -const RAMFS_FILE_OPS: bindings::file_operations = bindings::file_operations { - read_iter: Some(bindings::generic_file_read_iter), - write_iter: Some(bindings::generic_file_write_iter), - mmap: Some(bindings::generic_file_mmap), - fsync: Some(bindings::noop_fsync), - splice_read: Some(bindings::generic_file_splice_read), - splice_write: Some(bindings::iter_file_splice_write), - llseek: Some(bindings::generic_file_llseek), - get_unmapped_area: Some(ramfs_mmu_get_unmapped_area), - ..DEFAULT_FILE_OPERATIONS -}; + fn splice_read(&self, file: &File, pos: *mut i64, pipe: &mut bindings::pipe_inode_info, len: usize, flags: u32) -> Result { + libfs_functions::generic_file_splice_read(file, pos, pipe, len, flags) + } + + fn splice_write(&self, pipe: &mut bindings::pipe_inode_info, file: &File, pos: *mut i64, len: usize, flags: u32) -> Result { + libfs_functions::iter_file_splice_write(pipe, file, pos, len, flags) + } +} static RAMFS_OPS: bindings::super_operations = bindings::super_operations { statfs: Some(bindings::simple_statfs), @@ -198,8 +195,6 @@ static RAMFS_AOPS: bindings::address_space_operations = bindings::address_space_ ..DEFAULT_ADDRESS_SPACE_OPERATIONS }; -// impl FileOperations for BS2Ramfs // niklas: I think it's another struct, not BS2Ramfs - static RAMFS_FILE_INODE_OPS: bindings::inode_operations = bindings::inode_operations { setattr: Some(bindings::simple_setattr), getattr: Some(bindings::simple_getattr), diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index f80bade114ed94..45f2ebb6e25dd2 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -154,12 +154,10 @@ unsafe extern "C" fn write_iter_callback( raw_iter: *mut bindings::iov_iter, ) -> isize { from_kernel_result! { - let mut iter = unsafe { IovIter::from_ptr(raw_iter) }; - let file = unsafe { (*iocb).ki_filp }; - let offset = unsafe { (*iocb).ki_pos }; - let f = unsafe { &*((*file).private_data as *const T) }; - let written = f.write(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?; - unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() }; + let mut iter = IovIter::from_ptr(raw_iter); + let file = (*iocb).ki_filp; + let f = &*((*file).private_data as *const T); + let written = f.write_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; Ok(written as _) } } @@ -248,6 +246,21 @@ unsafe extern "C" fn fsync_callback( } } +unsafe extern "C" fn get_unmapped_area_callback( + file: *mut bindings::file, + addr: c_types::c_ulong, + len: c_types::c_ulong, + pgoff: c_types::c_ulong, + flags: c_types::c_ulong, +) -> c_types::c_ulong { + let ret: i64 = from_kernel_result! { + let f = &*((*file).private_data as *const T); + let res = f.get_unmapped_area(&FileRef::from_ptr(file), addr, len, pgoff, flags)?; + Ok(res as _) + }; + ret as _ +} + unsafe extern "C" fn poll_callback( file: *mut bindings::file, wait: *mut bindings::poll_table_struct, @@ -261,6 +274,34 @@ unsafe extern "C" fn poll_callback( } } +unsafe extern "C" fn splice_read_callback( + file: *mut bindings::file, + ppos: *mut bindings::loff_t, + pipe: *mut bindings::pipe_inode_info, + len: c_types::c_size_t, + flags: c_types::c_uint, +) -> c_types::c_ssize_t { + from_kernel_result! { + let f = &*((*file).private_data as *const T); + let ret = f.splice_read(&FileRef::from_ptr(file), ppos, &mut *pipe, len, flags)?; + Ok(ret as _) + } +} + +unsafe extern "C" fn splice_write_callback( + pipe: *mut bindings::pipe_inode_info, + file: *mut bindings::file, + ppos: *mut bindings::loff_t, + len: c_types::c_size_t, + flags: c_types::c_uint, +) -> c_types::c_ssize_t { + from_kernel_result! { + let f = &*((*file).private_data as *const T); + let ret = f.splice_write(&mut *pipe, &FileRef::from_ptr(file), ppos, len, flags)?; + Ok(ret as _) + } +} + pub(crate) struct FileOperationsVtable(marker::PhantomData, marker::PhantomData); impl> FileOperationsVtable { @@ -300,7 +341,11 @@ impl> FileOperationsVtable { } else { None }, - get_unmapped_area: None, + get_unmapped_area: if T::TO_USE.get_unmapped_area { + Some(get_unmapped_area_callback::) + } else { + None + }, iterate: None, iterate_shared: None, iopoll: None, @@ -326,8 +371,16 @@ impl> FileOperationsVtable { sendpage: None, setlease: None, show_fdinfo: None, - splice_read: None, - splice_write: None, + splice_read: if T::TO_USE.splice_read { + Some(splice_read_callback::) + } else { + None + }, + splice_write: if T::TO_USE.splice_write { + Some(splice_write_callback::) + } else { + None + }, unlocked_ioctl: if T::TO_USE.ioctl { Some(unlocked_ioctl_callback::) } else { @@ -376,11 +429,20 @@ pub struct ToUse { /// The `fsync` field of [`struct file_operations`]. pub fsync: bool, + /// The `get_unmapped_area` field of [`struct file_operations`]. + pub get_unmapped_area: bool, + /// The `mmap` field of [`struct file_operations`]. pub mmap: bool, /// The `poll` field of [`struct file_operations`]. pub poll: bool, + + /// The `splice_read` field of [`struct file_operations`]. + pub splice_read: bool, + + /// The `splice_write` field of [`struct file_operations`]. + pub splice_write: bool, } /// A constant version where all values are to set to `false`, that is, all supported fields will @@ -394,8 +456,11 @@ pub const USE_NONE: ToUse = ToUse { ioctl: false, compat_ioctl: false, fsync: false, + get_unmapped_area: false, mmap: false, poll: false, + splice_read: false, + splice_write: false, }; /// Defines the [`FileOperations::TO_USE`] field based on a list of fields to be populated. @@ -569,6 +634,8 @@ pub trait FileOperations: Send + Sync + Sized { let file = iocb.get_file(); let offset = iocb.get_offset(); let read = self.read(&file, iter, offset)?; + let offset = iocb.get_offset(); + iocb.set_offset(offset + read as u64); Ok(read) } @@ -579,6 +646,18 @@ pub trait FileOperations: Send + Sync + Sized { Err(Error::EINVAL) } + /// Writes data from the caller's buffer to this file. + /// + /// Corresponds to the `write_iter` function pointer in `struct file_operations`. + fn write_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + let file = iocb.get_file(); + let offset = iocb.get_offset(); + let written = self.write(&file, iter, offset)?; + let offset = iocb.get_offset(); + iocb.set_offset(offset + written as u64); + Ok(written) + } + /// Changes the position of the file. /// /// Corresponds to the `llseek` function pointer in `struct file_operations`. @@ -607,6 +686,20 @@ pub trait FileOperations: Send + Sync + Sized { Err(Error::EINVAL) } + /// Unmapped area. + /// + /// Corresponds to the `get_unmapped_area` function pointer in `struct file_operations`. + fn get_unmapped_area( + &self, + _file: &File, + _addr: u64, + _len: u64, + _pgoff: u64, + _flags: u64, + ) -> Result { + Err(Error::EINVAL) + } + /// Maps areas of the caller's virtual memory with device/file memory. /// /// Corresponds to the `mmap` function pointer in `struct file_operations`. @@ -622,4 +715,32 @@ pub trait FileOperations: Send + Sync + Sized { fn poll(&self, _file: &File, _table: &PollTable) -> Result { Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM) } + + /// Splice data from file to a pipe + /// + /// Corresponds to the `splice_read` function pointer in `struct file_operations`. + fn splice_read( + &self, + _file: &File, + _pos: *mut i64, + _pipe: &mut bindings::pipe_inode_info, + _len: usize, + _flags: u32, + ) -> Result { + Err(Error::EINVAL) + } + + /// Splice data from pipe to a file + /// + /// Corresponds to the `splice_write` function pointer in `struct file_operations`. + fn splice_write( + &self, + _pipe: &mut bindings::pipe_inode_info, + _file: &File, + _pos: *mut i64, + _len: usize, + _flags: u32, + ) -> Result { + Err(Error::EINVAL) + } } diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index 72e1e92e5b0a56..0840200cdd97b3 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -2,7 +2,6 @@ use core::ops::{Deref, DerefMut}; use core::{mem, ptr}; use crate::bindings; -use crate::c_types::*; use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; use crate::fs::SuperBlock; use crate::types::Mode; diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs index 9e14afc7702b93..7d77353100b719 100644 --- a/rust/kernel/fs/kiocb.rs +++ b/rust/kernel/fs/kiocb.rs @@ -1,9 +1,8 @@ use core::mem; use core::ops::{Deref, DerefMut}; -use crate::file::{FileRef, File}; +use crate::file::File; use crate::bindings; -use crate::Result; #[repr(transparent)] pub struct Kiocb(bindings::kiocb); diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 41e656a48469a6..2aac86f5393af1 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -11,18 +11,18 @@ pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result Result { -// struct kiocb * iocb, struct iov_iter * iter -// } - -// pub fn generic_file_write_iter(iocb: &mut Kiocb, from: &mut IovIter) -> Result { -// //ssize_t generic_file_write_iter(struct kiocb * iocb, struct iov_iter * from); -// } - -// pub fn generic_file_mmap() { +pub fn generic_file_write_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { + Error::parse_int( + unsafe { bindings::generic_file_write_iter(iocb.as_ptr_mut(), iter.ptr) as _ } + ) +} -// } +pub fn generic_file_mmap(file: &File, vma: &mut bindings::vm_area_struct) -> Result { + Error::parse_int( + unsafe { bindings::generic_file_mmap(file.ptr, vma as *mut _) } + ).map(|_| ()) +} pub fn noop_fsync(file: &File, start: u64, end: u64, datasync: bool) -> Result { let start = start as _; @@ -43,3 +43,15 @@ pub fn generic_file_llseek(file: &File, pos: SeekFrom) -> Result { unsafe { bindings::generic_file_llseek(file.ptr, offset as _, whence as _) } as _, ) } + +pub fn generic_file_splice_read(file: &File, pos: *mut i64, pipe: &mut bindings::pipe_inode_info, len: usize, flags: u32) -> Result { + Error::parse_int( + unsafe { bindings::generic_file_splice_read(file.ptr, pos, pipe as *mut _, len, flags) as _ } + ) +} + +pub fn iter_file_splice_write(pipe: &mut bindings::pipe_inode_info, file: &File, pos: *mut i64, len: usize, flags: u32) -> Result { + Error::parse_int( + unsafe { bindings::iter_file_splice_write(pipe as *mut _, file.ptr, pos, len, flags) as _ } + ) +} From 2a03342eb00cf085ad92d48937f2968965dc5e86 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sun, 6 Jun 2021 16:08:20 +0200 Subject: [PATCH 28/58] rustfmt everything and put some underscores on some names --- fs/bs2ramfs/bs2ramfs.rs | 45 +++++++++++++++++++++++++------ rust/kernel/fs.rs | 2 +- rust/kernel/fs/kiocb.rs | 9 ++++--- rust/kernel/fs/libfs_functions.rs | 40 +++++++++++++++------------ 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index d5d9ec7c842d5c..4c50e5c4b6f32a 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -15,8 +15,7 @@ use kernel::fs::{ dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, libfs_functions, FileSystem, FileSystemBase, FileSystemType, SuperBlock, - DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_FILE_OPERATIONS, DEFAULT_INODE_OPERATIONS, - DEFAULT_SUPER_OPS, + DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, DEFAULT_SUPER_OPS, }; const PAGE_SHIFT: u32 = 12; // x86 (maybe) @@ -142,7 +141,16 @@ unsafe extern "C" fn ramfs_show_options( struct Bs2RamfsFileOps; impl FileOperations for Bs2RamfsFileOps { - kernel::declare_file_operations!(read_iter, write_iter, mmap, fsync, splice_read, splice_write, seek, get_unmapped_area); + kernel::declare_file_operations!( + read_iter, + write_iter, + mmap, + fsync, + splice_read, + splice_write, + seek, + get_unmapped_area + ); fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { libfs_functions::generic_file_read_iter(iocb, iter) @@ -151,16 +159,23 @@ impl FileOperations for Bs2RamfsFileOps { fn write_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { libfs_functions::generic_file_write_iter(iocb, iter) } - + fn mmap(&self, file: &File, vma: &mut bindings::vm_area_struct) -> Result { - libfs_functions::generic_file_mmap(file, vma) + libfs_functions::generic_file_mmap(file, vma) } fn fsync(&self, file: &File, start: u64, end: u64, datasync: bool) -> Result { libfs_functions::noop_fsync(file, start, end, datasync) } - fn get_unmapped_area(&self, file: &File, addr: u64, len: u64, pgoff: u64, flags: u64) -> Result { + fn get_unmapped_area( + &self, + _file: &File, + _addr: u64, + _len: u64, + _pgoff: u64, + _flags: u64, + ) -> Result { pr_emerg!( "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" ); @@ -171,11 +186,25 @@ impl FileOperations for Bs2RamfsFileOps { libfs_functions::generic_file_llseek(file, pos) } - fn splice_read(&self, file: &File, pos: *mut i64, pipe: &mut bindings::pipe_inode_info, len: usize, flags: u32) -> Result { + fn splice_read( + &self, + file: &File, + pos: *mut i64, + pipe: &mut bindings::pipe_inode_info, + len: usize, + flags: u32, + ) -> Result { libfs_functions::generic_file_splice_read(file, pos, pipe, len, flags) } - fn splice_write(&self, pipe: &mut bindings::pipe_inode_info, file: &File, pos: *mut i64, len: usize, flags: u32) -> Result { + fn splice_write( + &self, + pipe: &mut bindings::pipe_inode_info, + file: &File, + pos: *mut i64, + len: usize, + flags: u32, + ) -> Result { libfs_functions::iter_file_splice_write(pipe, file, pos, len, flags) } } diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 90343dd04d2dd7..1173b940895f85 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,7 +1,7 @@ pub mod dentry; pub mod inode; -pub mod libfs_functions; pub mod kiocb; +pub mod libfs_functions; use core::ptr; diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs index 7d77353100b719..1f12105b4eeed7 100644 --- a/rust/kernel/fs/kiocb.rs +++ b/rust/kernel/fs/kiocb.rs @@ -1,8 +1,8 @@ use core::mem; use core::ops::{Deref, DerefMut}; -use crate::file::File; use crate::bindings; +use crate::file::File; #[repr(transparent)] pub struct Kiocb(bindings::kiocb); @@ -46,6 +46,9 @@ impl Kiocb { } pub fn set_offset(&mut self, offset: u64) { - unsafe { (*(self.as_ptr_mut())).ki_pos = offset as _; } + unsafe { + (*(self.as_ptr_mut())).ki_pos = offset as _; + } } -} \ No newline at end of file +} + diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 2aac86f5393af1..3f5f01b56b5f3b 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -7,21 +7,15 @@ use crate::iov_iter::IovIter; use crate::Result; pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { - Error::parse_int( - unsafe { bindings::generic_file_read_iter(iocb.as_ptr_mut(), iter.ptr) as _ } - ) + Error::parse_int(unsafe { bindings::generic_file_read_iter(iocb.as_ptr_mut(), iter.ptr) as _ }) } pub fn generic_file_write_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { - Error::parse_int( - unsafe { bindings::generic_file_write_iter(iocb.as_ptr_mut(), iter.ptr) as _ } - ) + Error::parse_int(unsafe { bindings::generic_file_write_iter(iocb.as_ptr_mut(), iter.ptr) as _ }) } pub fn generic_file_mmap(file: &File, vma: &mut bindings::vm_area_struct) -> Result { - Error::parse_int( - unsafe { bindings::generic_file_mmap(file.ptr, vma as *mut _) } - ).map(|_| ()) + Error::parse_int(unsafe { bindings::generic_file_mmap(file.ptr, vma as *mut _) }).map(|_| ()) } pub fn noop_fsync(file: &File, start: u64, end: u64, datasync: bool) -> Result { @@ -44,14 +38,26 @@ pub fn generic_file_llseek(file: &File, pos: SeekFrom) -> Result { ) } -pub fn generic_file_splice_read(file: &File, pos: *mut i64, pipe: &mut bindings::pipe_inode_info, len: usize, flags: u32) -> Result { - Error::parse_int( - unsafe { bindings::generic_file_splice_read(file.ptr, pos, pipe as *mut _, len, flags) as _ } - ) +pub fn generic_file_splice_read( + file: &File, + pos: *mut i64, + pipe: &mut bindings::pipe_inode_info, + len: usize, + flags: u32, +) -> Result { + Error::parse_int(unsafe { + bindings::generic_file_splice_read(file.ptr, pos, pipe as *mut _, len, flags) as _ + }) } -pub fn iter_file_splice_write(pipe: &mut bindings::pipe_inode_info, file: &File, pos: *mut i64, len: usize, flags: u32) -> Result { - Error::parse_int( - unsafe { bindings::iter_file_splice_write(pipe as *mut _, file.ptr, pos, len, flags) as _ } - ) +pub fn iter_file_splice_write( + pipe: &mut bindings::pipe_inode_info, + file: &File, + pos: *mut i64, + len: usize, + flags: u32, +) -> Result { + Error::parse_int(unsafe { + bindings::iter_file_splice_write(pipe as *mut _, file.ptr, pos, len, flags) as _ + }) } From 84f2e9b71adf511b694b8f7f855bb968d41c77f2 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Sun, 6 Jun 2021 16:29:02 +0200 Subject: [PATCH 29/58] kernel crate: Add SuperOperations --- fs/bs2ramfs/bs2ramfs.rs | 103 +++-- rust/kernel/fs.rs | 17 +- rust/kernel/fs/inode.rs | 4 +- rust/kernel/fs/kiocb.rs | 1 - rust/kernel/fs/super_block.rs | 43 ++ rust/kernel/fs/super_operations.rs | 618 +++++++++++++++++++++++++++++ rust/kernel/super_block.rs | 53 --- 7 files changed, 737 insertions(+), 102 deletions(-) create mode 100644 rust/kernel/fs/super_block.rs create mode 100644 rust/kernel/fs/super_operations.rs delete mode 100644 rust/kernel/super_block.rs diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 4c50e5c4b6f32a..5741b1c8e8034a 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -7,6 +7,7 @@ use core::{mem, ptr}; use kernel::file::File; use kernel::file_operations::{FileOperations, SeekFrom}; use kernel::fs::kiocb::Kiocb; +use kernel::fs::super_operations::{Kstatfs, SeqFile, SuperOperations}; use kernel::iov_iter::IovIter; use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; @@ -14,8 +15,10 @@ use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; use kernel::fs::{ dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, - libfs_functions, FileSystem, FileSystemBase, FileSystemType, SuperBlock, - DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, DEFAULT_SUPER_OPS, + libfs_functions, + super_block::SuperBlock, + FileSystem, FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, + DEFAULT_INODE_OPERATIONS, }; const PAGE_SHIFT: u32 = 12; // x86 (maybe) @@ -55,7 +58,7 @@ impl FileSystemBase for BS2Ramfs { Self::mount_nodev(flags, data) } - fn kill_superblock(sb: &mut SuperBlock) { + fn kill_super(sb: &mut SuperBlock) { let _ = unsafe { Box::from_raw(mem::replace(&mut sb.s_fs_info, ptr::null_mut())) }; Self::kill_litter_super(sb); } @@ -67,34 +70,31 @@ impl FileSystemBase for BS2Ramfs { ) -> Result { pr_emerg!("Reached ramfs_fill_super_impl"); - sb.s_fs_info = ptr::null_mut(); - // freed in kill_superblock - let fsi = Box::leak(Box::try_new(RamfsFsInfo { - mount_opts: Default::default(), - })?); - sb.s_fs_info = fsi as *mut _ as *mut _; - - sb.s_maxbytes = MAX_LFS_FILESIZE; - sb.s_blocksize = kernel::PAGE_SIZE as _; - sb.s_blocksize_bits = PAGE_SHIFT as _; - sb.s_magic = BS2RAMFS_MAGIC; - sb.s_op = &RAMFS_OPS as *const _ as *mut _; - sb.s_time_gran = 1; - pr_emerg!("SB members set"); - + // sb.s_fs_info = ptr::null_mut(); + // freed in kill_super + // let fsi = Box::leak(Box::try_new(RamfsFsInfo { + // mount_opts: Default::default(), + // })?); + // sb.s_fs_info = fsi as *mut _ as *mut _; + // sb.s_op = &RAMFS_OPS as *const _ as *mut _; + + // sb.s_magic = ; + let ops = Bs2RamfsSuperOps::default(); + // ops.fill(sb); unsafe { // TODO: investigate if this really has to be set to NULL in case we run out of memory sb.s_root = ptr::null_mut(); - let inode = ramfs_get_inode( - sb, - None, - Mode::S_IFDIR | Mode::from_int(fsi.mount_opts.mode as _), - 0, - ); + let inode = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0); pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); sb.s_root = inode.and_then(Dentry::make_root).ok_or(Error::ENOMEM)? as *mut _ as *mut _; } pr_emerg!("(rust) s_root: {:?}", sb.s_root); + sb.set_super_operations(ops); + sb.s_maxbytes = MAX_LFS_FILESIZE; + sb.s_blocksize = kernel::PAGE_SIZE as _; + sb.s_blocksize_bits = PAGE_SHIFT as _; + sb.s_time_gran = 1; + pr_emerg!("SB members set"); Ok(()) } @@ -116,19 +116,17 @@ impl Drop for BS2Ramfs { } struct RamfsMountOpts { - pub mode: bindings::mode_t, + pub mode: Mode, } impl Default for RamfsMountOpts { fn default() -> Self { - Self { mode: 0o775 } + Self { + mode: Mode::from_int(0o775), + } } } -struct RamfsFsInfo { - mount_opts: RamfsMountOpts, -} - unsafe extern "C" fn ramfs_show_options( _m: *mut bindings::seq_file, _root: *mut bindings::dentry, @@ -209,12 +207,33 @@ impl FileOperations for Bs2RamfsFileOps { } } -static RAMFS_OPS: bindings::super_operations = bindings::super_operations { - statfs: Some(bindings::simple_statfs), - drop_inode: Some(bindings::generic_delete_inode), - show_options: Some(ramfs_show_options), - ..DEFAULT_SUPER_OPS -}; +// static RAMFS_OPS: bindings::super_operations = bindings::super_operations { +// statfs: Some(bindings::simple_statfs), +// drop_inode: Some(bindings::generic_delete_inode), +// show_options: Some(ramfs_show_options), +// ..DEFAULT_SUPER_OPS +// }; + +#[derive(Default)] +struct Bs2RamfsSuperOps { + mount_opts: RamfsMountOpts, +} + +impl SuperOperations for Bs2RamfsSuperOps { + kernel::declare_super_operations!(statfs, drop_inode, show_options); + + fn drop_inode(&self, _inode: &Inode) -> Result { + Err(Error::EINVAL) + } + + fn statfs(&self, _root: &Dentry, _buf: &Kstatfs) -> Result { + Err(Error::EINVAL) + } + + fn show_options(&self, _s: &SeqFile, _root: &Dentry) -> Result { + Err(Error::EINVAL) + } +} static RAMFS_AOPS: bindings::address_space_operations = bindings::address_space_operations { readpage: Some(bindings::simple_readpage), @@ -232,7 +251,7 @@ static RAMFS_FILE_INODE_OPS: bindings::inode_operations = bindings::inode_operat #[no_mangle] pub unsafe fn ramfs_get_inode<'a>( - sb: &'a mut bindings::super_block, + sb: &'a mut SuperBlock, dir: Option<&'_ mut Inode>, mode: Mode, dev: bindings::dev_t, @@ -282,7 +301,10 @@ unsafe extern "C" fn ramfs_mknod( .expect("ramfs_mknod got NULL directory") .as_mut(); ramfs_get_inode( - dir.i_sb.as_mut().expect("dir has NULL super block"), + dir.i_sb + .as_mut() + .expect("dir has NULL super block") + .as_mut(), Some(dir), Mode::from_int(mode), dev, @@ -351,7 +373,10 @@ unsafe extern "C" fn ramfs_symlink( .expect("ramfs_symlink got NULL directory") .as_mut(); ramfs_get_inode( - dir.i_sb.as_mut().expect("dir had NULL super block"), + dir.i_sb + .as_mut() + .expect("dir had NULL super block") + .as_mut(), Some(dir), Mode::S_IFLNK | Mode::S_IRWXUGO, 0, diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 1173b940895f85..f8eaf2a9ff1bfb 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -2,16 +2,18 @@ pub mod dentry; pub mod inode; pub mod kiocb; pub mod libfs_functions; +pub mod super_block; +pub mod super_operations; use core::ptr; use crate::ret_err_ptr; use crate::{ - bindings, c_types::*, error::from_kernel_err_ptr, prelude::*, str::CStr, Error, Result, + bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, prelude::*, + str::CStr, Error, Result, }; pub type FileSystemType = bindings::file_system_type; -pub type SuperBlock = bindings::super_block; pub trait FileSystemBase { type MountOptions = c_void; @@ -27,7 +29,7 @@ pub trait FileSystemBase { data: Option<&mut Self::MountOptions>, ) -> Result<*mut bindings::dentry>; - fn kill_superblock(sb: &mut SuperBlock); + fn kill_super(sb: &mut SuperBlock); unsafe extern "C" fn mount_raw( fs_type: *mut bindings::file_system_type, @@ -45,8 +47,9 @@ pub trait FileSystemBase { unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { let sb = sb .as_mut() - .expect("FileSystemBase::kill_sb_raw got NULL super block"); - Self::kill_superblock(sb); + .expect("FileSystemBase::kill_sb_raw got NULL super block") + .as_mut(); + Self::kill_super(sb); } fn fill_super( @@ -64,7 +67,7 @@ pub trait FileSystemBase { silent: c_int, ) -> c_int { pr_emerg!("in fill_super_raw"); - let sb = &mut *sb; + let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); let data = (data as *mut Self::MountOptions).as_mut(); Self::fill_super(sb, data, silent) .map(|_| 0) @@ -142,7 +145,7 @@ pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { fn kill_litter_super(sb: &mut SuperBlock) { unsafe { - bindings::kill_litter_super(sb as *mut _); + bindings::kill_litter_super(sb.as_ptr_mut()); } } } diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index 0840200cdd97b3..afbe66d2a6d141 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -3,7 +3,7 @@ use core::{mem, ptr}; use crate::bindings; use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; -use crate::fs::SuperBlock; +use crate::fs::super_block::SuperBlock; use crate::types::Mode; #[derive(PartialEq, Eq)] @@ -32,7 +32,7 @@ impl Inode { pub fn new(sb: &mut SuperBlock) -> Option<&mut Self> { unsafe { - bindings::new_inode(sb as *mut _) + bindings::new_inode(sb.as_ptr_mut()) .as_mut() .map(AsMut::as_mut) } diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs index 1f12105b4eeed7..fb17ba46b295c4 100644 --- a/rust/kernel/fs/kiocb.rs +++ b/rust/kernel/fs/kiocb.rs @@ -51,4 +51,3 @@ impl Kiocb { } } } - diff --git a/rust/kernel/fs/super_block.rs b/rust/kernel/fs/super_block.rs new file mode 100644 index 00000000000000..526630e620f5b7 --- /dev/null +++ b/rust/kernel/fs/super_block.rs @@ -0,0 +1,43 @@ +use alloc::boxed::Box; +use core::mem; +use core::ops::{Deref, DerefMut}; + +use crate::bindings; +use crate::fs::super_operations::{SuperOperations, SuperOperationsVtable}; + +#[repr(transparent)] +pub struct SuperBlock(bindings::super_block); + +impl SuperBlock { + pub fn as_ptr_mut(&mut self) -> *mut bindings::super_block { + self.deref_mut() as *mut _ + } + + pub fn set_super_operations(&mut self, ops: OPS) { + self.s_op = unsafe { SuperOperationsVtable::::build() }; + self.s_fs_info = Box::leak(Box::new(ops)) as *mut _ as *mut _; + } +} + +impl Deref for SuperBlock { + type Target = bindings::super_block; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SuperBlock { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl AsRef for bindings::super_block { + fn as_ref(&self) -> &SuperBlock { + unsafe { mem::transmute(self) } + } +} +impl AsMut for bindings::super_block { + fn as_mut(&mut self) -> &mut SuperBlock { + unsafe { mem::transmute(self) } + } +} diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs new file mode 100644 index 00000000000000..70cbaeabaff7aa --- /dev/null +++ b/rust/kernel/fs/super_operations.rs @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Super operations. +//! +//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h) + +use core::marker; + +use crate::{ + bindings, c_types, + error::{Error, Result}, + from_kernel_result, + fs::dentry::Dentry, + fs::inode::Inode, +}; + +pub type SeqFile = bindings::seq_file; +pub type Kstatfs = bindings::kstatfs; + +// unsafe extern "C" fn alloc_inode_callback( +// sb: *mut bindings::super_block, +// ) -> *mut bindings::inode { +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = s_ops.alloc_inode(&SuperBlock::from_ptr(sb)); // TODO SuperBlock, Inode +// inode.map(|i| Inode::into_ptr(inode)) +// } + +// unsafe extern "C" fn destroy_inode_callback( +// inode: *mut bindings::inode, +// ) { +// let sb = (*inode).i_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = Inode::from_ptr(inode); +// s_ops.destroy_inode(inode); +// } + +// unsafe extern "C" fn free_inode_callback( +// inode: *mut bindings::inode, +// ) { +// let sb = (*inode).i_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = Inode::from_ptr(inode); +// s_ops.free_inode(inode); +// } + +// unsafe extern "C" fn dirty_inode_callback( +// inode: *mut bindings::inode, +// flags: c_types::c_int, +// ) { +// let sb = (*inode).i_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = Inode::from_ptr(inode); +// s_ops.dirty_inode(inode, flags); +// } + +// unsafe extern "C" fn write_inode_callback( +// inode: *mut bindings::inode, +// wbc: *mut bindings::writeback_control, // TODO +// ) -> c_types::c_int { +// let sb = (*inode).i_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = Inode::from_ptr(inode); +// let wbc = WritebackControl::from_ptr(wbc); +// from_kernel_result! { +// s_ops.write_inode(inode, wbc)?; +// Ok(0) +// } +// } + +unsafe extern "C" fn drop_inode_callback( + inode: *mut bindings::inode, +) -> c_types::c_int { + let sb = (*inode).i_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + let inode = inode.as_mut().expect("drop_inode got null inode").as_mut(); + from_kernel_result! { + s_ops.drop_inode(inode)?; + Ok(0) + } +} + +// unsafe extern "C" fn evict_inode_callback( +// inode: *mut bindings::inode, +// ) { +// let sb = (*inode).i_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// let inode = Inode::from_ptr(inode); +// s_ops.evict_inode(inode); +// } + +// unsafe extern "C" fn put_super_callback( +// sb: *mut bindings::super_block, +// ) { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.put_super(&SuperBlock::from_ptr(sb)); +// } + +// unsafe extern "C" fn sync_fs_callback( +// sb: *mut bindings::super_block, +// wait: c_types::c_int, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.sync_fs(&SuperBlock::from_ptr(sb), wait)?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn freeze_super_callback( +// sb: *mut bindings::super_block, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.sync_fs(&SuperBlock::from_ptr(sb))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn freeze_fs_callback( +// sb: *mut bindings::super_block, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.freeze_fs(&SuperBlock::from_ptr(sb))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn thaw_super_callback( +// sb: *mut bindings::super_block, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.thaw_super(&SuperBlock::from_ptr(sb))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn unfreeze_fs_callback( +// sb: *mut bindings::super_block, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.unfreeze_fs(&SuperBlock::from_ptr(sb))?; +// Ok(0) +// } +// } + +unsafe extern "C" fn statfs_callback( + root: *mut bindings::dentry, + buf: *mut bindings::kstatfs, +) -> c_types::c_int { + from_kernel_result! { + let sb = (*root).d_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + s_ops.statfs(root.as_mut().expect("Statfs got null dentry").as_mut(), &mut *buf)?; + Ok(0) + } +} + +// unsafe extern "C" fn remount_fs_callback( +// sb: *mut bindings::super_block, +// flags: *mut c_types::c_int, +// data: *mut c_types::c_char, +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.remount_fs( +// &SuperBlock::from_ptr(sb), +// flags, +// &CStr::from_ptr(data), // TODO +// )?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn umount_begin_callback( +// sb: *mut bindings::super_block, +// ) { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.umount_begin(&SuperBlock::from_ptr(sb)); +// } + +unsafe extern "C" fn show_options_callback( + s: *mut bindings::seq_file, + root: *mut bindings::dentry, +) -> c_types::c_int { + from_kernel_result! { + let sb = (*root).d_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + s_ops.show_options(&mut *s, root.as_mut().expect("show_options got null dentry").as_mut())?; + Ok(0) + } +} + +// unsafe extern "C" fn show_devname_callback( +// s: *mut bindings::seq_file, +// root: *mut bindings::dentry, +// ) -> c_types::c_int { +// from_kernel_result! { +// let sb = (*root).d_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.show_devname(&SeqFile::from_ptr(s), &Dentry::from_ptr(root))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn show_path_callback( +// s: *mut bindings::seq_file, +// root: *mut bindings::dentry, +// ) -> c_types::c_int { +// from_kernel_result! { +// let sb = (*root).d_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.show_path(&SeqFile::from_ptr(s), &Dentry::from_ptr(root))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn show_stats_callback( +// s: *mut bindings::seq_file, +// root: *mut bindings::dentry, +// ) -> c_types::c_int { +// from_kernel_result! { +// let sb = (*root).d_sb as *const bindings::super_block; +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.show_stats(&SeqFile::from_ptr(s), &Dentry::from_ptr(root))?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn bdev_try_to_free_page_callback( +// sb: *mut bindings::super_block, +// page: *mut bindings::page, // TODO +// wait: bindings::gfp_t, // TODO +// ) -> c_types::c_int { +// from_kernel_result! { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.show_stats(&SuperBlock::from_ptr(sb), &Page::from_ptr(page), wait)?; +// Ok(0) +// } +// } + +// unsafe extern "C" fn nr_cached_objects_callback( +// sb: *mut bindings::super_block, +// sc: *mut bindings::shrink_control, // TODO +// ) -> c_types::c_long { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.nr_cached_objects(&SuperBlock::from_ptr(sb), &ShrinkControl::from_ptr(sc)) +// } + +// unsafe extern "C" fn free_cached_objects_callback( +// sb: *mut bindings::super_block, +// sc: *mut bindings::shrink_control, // TODO +// ) -> c_types::c_long { +// let s_ops = &*((*sb).s_fs_info as *const T); +// s_ops.free_cached_objects(&SuperBlock::from_ptr(sb), &ShrinkControl::from_ptr(sc)) +// } + +pub(crate) struct SuperOperationsVtable(marker::PhantomData); + +impl SuperOperationsVtable { + const VTABLE: bindings::super_operations = bindings::super_operations { + // alloc_inode: T::TO_USE.alloc_inode { + // Some(alloc_inode_callback::) + // } else { + // None + // }, + // destroy_inode: if T::TO_USE.destroy_inode { + // Some(destroy_inode_callback::) + // } else { + // None + // }, + // free_inode: if T::TO_USE.free_inode { + // Some(free_inode_callback::) + // } else { + // None + // }, + // dirty_inode: if T::TO_USE.dirty_inode { + // Some(dirty_inode_callback::) + // } else { + // None + // }, + // write_inode: if T::TO_USE.write_inode { + // Some(write_inode_callback::) + // } else { + // None + // }, + drop_inode: if T::TO_USE.drop_inode { + Some(drop_inode_callback::) + } else { + None + }, + // evict_inode: if T::TO_USE.evict_inode { + // Some(evict_inode_callback::) + // } else { + // None + // }, + // put_super: if T::TO_USE.put_super { + // Some(put_super_callback::) + // } else { + // None + // }, + // sync_fs: if T::TO_USE.sync_fs { + // Some(sync_fs_callback::) + // } else { + // None + // }, + // freeze_super: if T::TO_USE.freeze_super { + // Some(freeze_super_callback::) + // } else { + // None + // }, + // freeze_fs: if T::TO_USE.freeze_fs { + // Some(freeze_fs_callback::) + // } else { + // None + // }, + // thaw_super: if T::TO_USE.thaw_super { + // Some(thaw_super_callback::) + // } else { + // None + // }, + // unfreeze_fs: if T::TO_USE.unfreeze_fs { + // Some(unfreeze_fs_callback::) + // } else { + // None + // }, + statfs: if T::TO_USE.statfs { + Some(statfs_callback::) + } else { + None + }, + // remount_fs: if T::TO_USE.remount_fs { + // Some(remount_fs_callback::) + // } else { + // None + // }, + // umount_begin: if T::TO_USE.umount_begin { + // Some(umount_begin_callback::) + // } else { + // None + // }, + show_options: if T::TO_USE.show_options { + Some(show_options_callback::) + } else { + None + }, + // show_devname: if T::TO_USE.show_devname { + // Some(show_devname_callback::) + // } else { + // None + // }, + // show_path: if T::TO_USE.show_path { + // Some(show_path_callback::) + // } else { + // None + // }, + // show_stats: if T::TO_USE.show_stats { + // Some(show_stats_callback::) + // } else { + // None + // }, + // bdev_try_to_free_page: if T::TO_USE.bdev_try_to_free_page { + // Some(bdev_try_to_free_page_callback::) + // } else { + // None + // }, + // nr_cached_objects: if T::TO_USE.nr_cached_objects { + // Some(nr_cached_objects_callback::) + // } else { + // None + // }, + // free_cached_objects: if T::TO_USE.free_cached_objects { + // Some(free_cached_objects_callback::) + // } else { + // None + // }, + alloc_inode: None, + destroy_inode: None, + free_inode: None, + dirty_inode: None, + write_inode: None, + evict_inode: None, + put_super: None, + sync_fs: None, + freeze_super: None, + freeze_fs: None, + thaw_super: None, + unfreeze_fs: None, + remount_fs: None, + umount_begin: None, + show_devname: None, + show_path: None, + show_stats: None, + bdev_try_to_free_page: None, + nr_cached_objects: None, + free_cached_objects: None, + get_dquots: None, + quota_read: None, + quota_write: None, + }; + + /// Builds an instance of [`struct super_operations`]. + /// + /// # Safety + /// + /// The caller must ensure that the adapter is compatible with the way the device is registered. + pub(crate) const unsafe fn build() -> &'static bindings::super_operations { + &Self::VTABLE + } +} + +/// Represents which fields of [`struct super_block_operations`] should be populated with pointers. +pub struct ToUse { + /// The `alloc_inode` field of [`struct super_operations`]. + pub alloc_inode: bool, + + /// The `destroy_inode` field of [`struct super_operations`]. + pub destroy_inode: bool, + + /// The `free_inode` field of [`struct super_operations`]. + pub free_inode: bool, + + /// The `dirty_inode` field of [`struct super_operations`]. + pub dirty_inode: bool, + + /// The `write_inode` field of [`struct super_operations`]. + pub write_inode: bool, + + /// The `drop_inode` field of [`struct super_operations`]. + pub drop_inode: bool, + + /// The `evict_inode` field of [`struct super_operations`]. + pub evict_inode: bool, + + /// The `put_super` field of [`struct super_operations`]. + pub put_super: bool, + + /// The `sync_fs` field of [`struct super_operations`]. + pub sync_fs: bool, + + /// The `freeze_super` field of [`struct super_operations`]. + pub freeze_super: bool, + + /// The `freeze_fs` field of [`struct super_operations`]. + pub freeze_fs: bool, + + /// The `thaw_super` field of [`struct super_operations`]. + pub thaw_super: bool, + + /// The `unfreeze_fs` field of [`struct super_operations`]. + pub unfreeze_fs: bool, + + /// The `statfs` field of [`struct super_operations`]. + pub statfs: bool, + + /// The `remount_fs` field of [`struct super_operations`]. + pub remount_fs: bool, + + /// The `umount_begin` field of [`struct super_operations`]. + pub umount_begin: bool, + + /// The `show_options` field of [`struct super_operations`]. + pub show_options: bool, + + /// The `show_devname` field of [`struct super_operations`]. + pub show_devname: bool, + + /// the `show_path` field of [`struct super_operations`]. + pub show_path: bool, + + /// the `show_stats` field of [`struct super_operations`]. + pub show_stats: bool, + + /// the `bdev_try_to_free_page` field of [`struct super_operations`]. + pub bdev_try_to_free_page: bool, + + /// the `nr_cached_objects` field of [`struct super_operations`]. + pub nr_cached_objects: bool, + + /// the `free_cached_objects` field of [`struct super_operations`]. + pub free_cached_objects: bool, +} + +/// A constant version where all values are to set to `false`, that is, all supported fields will +/// be set to null pointers. +pub const USE_NONE: ToUse = ToUse { + alloc_inode: false, + destroy_inode: false, + free_inode: false, + dirty_inode: false, + write_inode: false, + drop_inode: false, + evict_inode: false, + put_super: false, + sync_fs: false, + freeze_super: false, + freeze_fs: false, + thaw_super: false, + unfreeze_fs: false, + statfs: false, + remount_fs: false, + umount_begin: false, + show_options: false, + show_devname: false, + show_path: false, + show_stats: false, + bdev_try_to_free_page: false, + nr_cached_objects: false, + free_cached_objects: false, +}; + +#[macro_export] +macro_rules! declare_super_operations { + () => { + const TO_USE: $crate::fs::super_operations::ToUse = $crate::fs::super_operations::USE_NONE; + }; + ($($i:ident),+) => { + const TO_USE: kernel::fs::super_operations::ToUse = + $crate::fs::super_operations::ToUse { + $($i: true),+ , + ..$crate::fs::super_operations::USE_NONE + }; + }; +} + +/// Corresponds to the kernel's `struct super_operations`. +/// +/// You implement this trait whenever you would create a `struct super_operations`. +/// +/// File descriptors may be used from multiple threads/processes concurrently, so your type must be +/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the +/// thread that decrements that associated file's refcount to zero. +pub trait SuperOperations: Send + Sync + Sized + Default { + /// The methods to use to populate [`struct super_operations`]. + const TO_USE: ToUse; + + // fn alloc_inode(&self, _sb: &SuperBlock) -> Option { + // None + // } + + // fn destroy_inode(&self, _inode: &Inode) {} + + // fn free_inode(&self, _inode: &Inode) {} + + // fn dirty_inode(&self, _inode: &Inode, _flags: i32) {} + + // fn write_inode(&self, _inode: &Inode, _wbc: &WritebackControl) -> Result { + // Err(Error::EINVAL) + // } + + fn drop_inode(&self, _inode: &Inode) -> Result { + Err(Error::EINVAL) + } + + // fn evict_inode(&self, _inode: &Inode) {} + + // fn put_super(&self, _sb: &SuperBlock) {} + + // fn sync_fs(&self, _sb: &SuperBlock, wait: i32) -> Result { + // Err(Error::EINVAL) + // } + + // fn freeze_super(&self, _sb: &SuperBlock) -> Result { + // Err(Error::EINVAL) + // } + + // fn freeze_fs(&self, _sb: &SuperBlock) -> Result { + // Err(Error::EINVAL) + // } + + // fn thaw_super(&self, _sb: &SuperBlock) -> Result { + // Err(Error::EINVAL) + // } + + // fn unfreeze_fs(&self, _sb: &SuperBlock) -> Result { + // Err(Error::EINVAL) + // } + + fn statfs(&self, _root: &Dentry, _buf: &Kstatfs) -> Result { + Err(Error::EINVAL) + } + + // fn remount_fs(&self, _sb: &SuperBlock, _flags: i32, _data: &CStr) -> Result { + // Err(Error::EINVAL) + // } + + // fn umount_begin(&self, _sb: &SuperBlock) {} + + fn show_options(&self, _s: &SeqFile, _root: &Dentry) -> Result { + Err(Error::EINVAL) + } + + // fn show_devname(&self, _s: &SeqFile, _root: &Dentry) -> Result { + // Err(Error::EINVAL) + // } + + // fn show_path(&self, _s: &SeqFile, _root: &Dentry) -> Result { + // Err(Error::EINVAL) + // } + + // fn show_stats(&self, _s: &SeqFile, _root: &Dentry) -> Result { + // Err(Error::EINVAL) + // } + + // fn bdev_try_to_free_page(&self, _sb: &SuperBlock, _page: &Page, _wait: GfpT) -> Result { + // Err(Error::EINVAL) + // } + + // fn nr_cached_objects(&self, _sb: &SuperBlock, _sc: &ShrinkControl) -> i64 { + // 0 + // } + + // fn free_cached_objects(&self, _sb: &SuperBlock, _sc: &ShrinkControl) -> i64 { + // 0 + // } +} diff --git a/rust/kernel/super_block.rs b/rust/kernel/super_block.rs deleted file mode 100644 index e694bbd18d9d07..00000000000000 --- a/rust/kernel/super_block.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::bindings; - -pub trait SuperBlock { - type Inode; - - const MAGIC: u64; - const BLOCKSIZE: u64; - const BLOCKSIZE_BITS: u8; - - pub fn as_inner(&mut self) -> &mut bindings::super_block; - pub fn from_inner(sb: &mut bindings::super_block) -> &mut Self; - - const statfs_implemented: bool = false; // TODO add a derive macro to auto-generate these - pub fn statfs(&mut self, dentry: Box, buf: Box) -> Result<()> { - unreachable!() - } - - unsafe extern "C" fn statfs_raw(dentry: *mut bindings::dentry, buf: *mut bindings::kstatfs) -> i32 { - let dentry = Dentry::from_raw(*dentry); - let buf = KStatsfs::from_raw(*buf); - let res = Self::statsfs(dentry, buf); - let _ = Dentry::into_raw(dentry); - let _ = KStatsfs::into_raw(buf); - res - } - - const drop_inode_implemented: bool = false; - pub fn drop_inode(inode: Box) -> Result { - unreachable!() - } - - unsafe extern "C" fn drop_inode_raw(inode: *mut bindings::inode) -> i32 { - let inode = Inode::from_raw(*inode); - let res = Self::drop_inode(inode); - let _ = Inode::into_raw(inode); - res - } - - const alloc_inode_implemented: bool = false; - pub fn alloc_inode(&mut self) -> Box { - unreachable!() - } - - unsafe extern "C" fn alloc_inode(sb: *mut bindings::super_block) -> *mut bindings::inode { - let inode = Inode::from_raw(*inode); - let res = Self::from_inner(sb).alloc_inode(inode); - let _ = Inode::into_raw(inode); - res - } - - // TODO add all the lots of other methods - -} From 398ea6b30d5d3a812a2aa4b9cf360a277164aa10 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Tue, 8 Jun 2021 15:22:57 +0200 Subject: [PATCH 30/58] Add missing libfs functions. Now everything works fine again. --- fs/bs2ramfs/bs2ramfs.rs | 20 +++++++------------- rust/kernel/fs/libfs_functions.rs | 12 ++++++++++++ rust/kernel/fs/super_operations.rs | 6 +++--- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 5741b1c8e8034a..ad0c3fd2aace50 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -207,13 +207,6 @@ impl FileOperations for Bs2RamfsFileOps { } } -// static RAMFS_OPS: bindings::super_operations = bindings::super_operations { -// statfs: Some(bindings::simple_statfs), -// drop_inode: Some(bindings::generic_delete_inode), -// show_options: Some(ramfs_show_options), -// ..DEFAULT_SUPER_OPS -// }; - #[derive(Default)] struct Bs2RamfsSuperOps { mount_opts: RamfsMountOpts, @@ -222,16 +215,17 @@ struct Bs2RamfsSuperOps { impl SuperOperations for Bs2RamfsSuperOps { kernel::declare_super_operations!(statfs, drop_inode, show_options); - fn drop_inode(&self, _inode: &Inode) -> Result { - Err(Error::EINVAL) + fn drop_inode(&self, inode: &mut Inode) -> Result { + libfs_functions::generic_delete_inode(inode) } - fn statfs(&self, _root: &Dentry, _buf: &Kstatfs) -> Result { - Err(Error::EINVAL) + fn statfs(&self, root: &mut Dentry, buf: &mut Kstatfs) -> Result { + libfs_functions::simple_statfs(root, buf) } - fn show_options(&self, _s: &SeqFile, _root: &Dentry) -> Result { - Err(Error::EINVAL) + fn show_options(&self, _s: &mut SeqFile, _root: &mut Dentry) -> Result { + pr_emerg!("ramfs show options, doing nothing"); + Ok(()) } } diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 3f5f01b56b5f3b..879b6ee8496024 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -2,7 +2,10 @@ use crate::bindings; use crate::error::Error; use crate::file::File; use crate::file_operations::SeekFrom; +use crate::fs::dentry::Dentry; +use crate::fs::inode::Inode; use crate::fs::kiocb::Kiocb; +use crate::fs::super_operations::Kstatfs; use crate::iov_iter::IovIter; use crate::Result; @@ -61,3 +64,12 @@ pub fn iter_file_splice_write( bindings::iter_file_splice_write(pipe as *mut _, file.ptr, pos, len, flags) as _ }) } + +pub fn generic_delete_inode(inode: &mut Inode) -> Result { + Error::parse_int(unsafe { bindings::generic_delete_inode(inode.as_ptr_mut()) }).map(|_| ()) +} + +pub fn simple_statfs(root: &mut Dentry, buf: &mut Kstatfs) -> Result { + Error::parse_int(unsafe { bindings::simple_statfs(root.as_ptr_mut(), buf as *mut _) }) + .map(|_| ()) +} diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs index 70cbaeabaff7aa..bbb8661e1fd1c9 100644 --- a/rust/kernel/fs/super_operations.rs +++ b/rust/kernel/fs/super_operations.rs @@ -550,7 +550,7 @@ pub trait SuperOperations: Send + Sync + Sized + Default { // Err(Error::EINVAL) // } - fn drop_inode(&self, _inode: &Inode) -> Result { + fn drop_inode(&self, _inode: &mut Inode) -> Result { Err(Error::EINVAL) } @@ -578,7 +578,7 @@ pub trait SuperOperations: Send + Sync + Sized + Default { // Err(Error::EINVAL) // } - fn statfs(&self, _root: &Dentry, _buf: &Kstatfs) -> Result { + fn statfs(&self, _root: &mut Dentry, _buf: &mut Kstatfs) -> Result { Err(Error::EINVAL) } @@ -588,7 +588,7 @@ pub trait SuperOperations: Send + Sync + Sized + Default { // fn umount_begin(&self, _sb: &SuperBlock) {} - fn show_options(&self, _s: &SeqFile, _root: &Dentry) -> Result { + fn show_options(&self, _s: &mut SeqFile, _root: &mut Dentry) -> Result { Err(Error::EINVAL) } From 47aba8525ef43b5a050956d53aef655adc368d4a Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 9 Jun 2021 14:33:18 +0200 Subject: [PATCH 31/58] bs2ramfs: make "super" branch merge ready --- fs/bs2ramfs/bs2ramfs.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index ad0c3fd2aace50..8751426cb078da 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -70,17 +70,8 @@ impl FileSystemBase for BS2Ramfs { ) -> Result { pr_emerg!("Reached ramfs_fill_super_impl"); - // sb.s_fs_info = ptr::null_mut(); - // freed in kill_super - // let fsi = Box::leak(Box::try_new(RamfsFsInfo { - // mount_opts: Default::default(), - // })?); - // sb.s_fs_info = fsi as *mut _ as *mut _; - // sb.s_op = &RAMFS_OPS as *const _ as *mut _; - - // sb.s_magic = ; + sb.s_magic = BS2RAMFS_MAGIC; let ops = Bs2RamfsSuperOps::default(); - // ops.fill(sb); unsafe { // TODO: investigate if this really has to be set to NULL in case we run out of memory sb.s_root = ptr::null_mut(); @@ -263,7 +254,6 @@ pub unsafe fn ramfs_get_inode<'a>( Mode::S_IFREG => { inode.i_op = &RAMFS_FILE_INODE_OPS; inode.set_file_operations::(); - // inode.__bindgen_anon_3.i_fop = &RAMFS_FILE_OPS as *const _ as *mut _; } Mode::S_IFDIR => { inode.i_op = &RAMFS_DIR_INODE_OPS; From ad7473a0248102f4e57bbaf59eb8d0ed94d50c0f Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 9 Jun 2021 15:04:01 +0200 Subject: [PATCH 32/58] kernel crate: Remove `FileSystem` trait The functions provided by the traits are now free functions in `libfs_functions` instead. --- fs/bs2ramfs/bs2ramfs.rs | 11 +++---- rust/kernel/fs.rs | 54 ------------------------------- rust/kernel/fs/libfs_functions.rs | 33 +++++++++++++++++++ 3 files changed, 38 insertions(+), 60 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 8751426cb078da..65f91004bae40a 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -17,8 +17,7 @@ use kernel::fs::{ inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, libfs_functions, super_block::SuperBlock, - FileSystem, FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, - DEFAULT_INODE_OPERATIONS, + FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, }; const PAGE_SHIFT: u32 = 12; // x86 (maybe) @@ -55,12 +54,12 @@ impl FileSystemBase for BS2Ramfs { _device_name: &CStr, data: Option<&mut Self::MountOptions>, ) -> Result<*mut bindings::dentry> { - Self::mount_nodev(flags, data) + libfs_functions::mount_nodev::(flags, data) } fn kill_super(sb: &mut SuperBlock) { let _ = unsafe { Box::from_raw(mem::replace(&mut sb.s_fs_info, ptr::null_mut())) }; - Self::kill_litter_super(sb); + libfs_functions::kill_litter_super(sb); } fn fill_super( @@ -95,13 +94,13 @@ kernel::declare_fs_type!(BS2Ramfs, BS2RAMFS_FS_TYPE); impl KernelModule for BS2Ramfs { fn init() -> Result { pr_emerg!("bs2 ramfs in action"); - Self::register().map(move |_| Self) + libfs_functions::register_filesystem::().map(move |_| Self) } } impl Drop for BS2Ramfs { fn drop(&mut self) { - let _ = Self::unregister(); + let _ = libfs_functions::unregister_filesystem::(); pr_info!("bs2 ramfs out of action"); } } diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index f8eaf2a9ff1bfb..b9c36526a7d00e 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -98,60 +98,6 @@ macro_rules! declare_fs_type { }; } -pub trait FileSystem: FileSystemBase + DeclaredFileSystemType { - fn register() -> Result { - let err = unsafe { bindings::register_filesystem(Self::file_system_type()) }; - if err == 0 { - Ok(()) - } else { - Err(Error::from_kernel_errno(err)) - } - } - - fn unregister() -> Result { - let err = unsafe { bindings::unregister_filesystem(Self::file_system_type()) }; - if err == 0 { - Ok(()) - } else { - Err(Error::from_kernel_errno(err)) - } - } - - fn mount_nodev( - flags: c_int, - data: Option<&mut Self::MountOptions>, - ) -> Result<*mut bindings::dentry> { - from_kernel_err_ptr(unsafe { - bindings::mount_nodev( - Self::file_system_type(), - flags, - data.map(|p| p as *mut _ as *mut _) - .unwrap_or_else(ptr::null_mut), - Some(Self::fill_super_raw), - ) - }) - } - - // just moved here - // fn mount_bdev(flags: u32, dev_name: &CStr, data: Box) { - // bindings::mount_bdev( - // Self::file_system_type(), - // flags, - // CStr::into_raw(dev_name), - // MountOptions::into_raw(data), - // self.fill_super_raw - // ); - // } - - fn kill_litter_super(sb: &mut SuperBlock) { - unsafe { - bindings::kill_litter_super(sb.as_ptr_mut()); - } - } -} - -impl FileSystem for T {} - pub const DEFAULT_SUPER_OPS: bindings::super_operations = bindings::super_operations { statfs: None, drop_inode: None, diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 879b6ee8496024..2adbb3fd6279e0 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -1,13 +1,18 @@ use crate::bindings; +use crate::c_types::*; use crate::error::Error; use crate::file::File; use crate::file_operations::SeekFrom; use crate::fs::dentry::Dentry; +use crate::fs::from_kernel_err_ptr; use crate::fs::inode::Inode; use crate::fs::kiocb::Kiocb; +use crate::fs::super_block::SuperBlock; use crate::fs::super_operations::Kstatfs; +use crate::fs::DeclaredFileSystemType; use crate::iov_iter::IovIter; use crate::Result; +use core::ptr; pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { Error::parse_int(unsafe { bindings::generic_file_read_iter(iocb.as_ptr_mut(), iter.ptr) as _ }) @@ -73,3 +78,31 @@ pub fn simple_statfs(root: &mut Dentry, buf: &mut Kstatfs) -> Result { Error::parse_int(unsafe { bindings::simple_statfs(root.as_ptr_mut(), buf as *mut _) }) .map(|_| ()) } + +pub fn register_filesystem() -> Result { + Error::parse_int(unsafe { bindings::register_filesystem(T::file_system_type()) }).map(|_| ()) +} +pub fn unregister_filesystem() -> Result { + Error::parse_int(unsafe { bindings::unregister_filesystem(T::file_system_type()) }).map(|_| ()) +} + +pub fn mount_nodev( + flags: c_int, + data: Option<&mut T::MountOptions>, +) -> Result<*mut bindings::dentry> { + from_kernel_err_ptr(unsafe { + bindings::mount_nodev( + T::file_system_type(), + flags, + data.map(|p| p as *mut _ as *mut _) + .unwrap_or_else(ptr::null_mut), + Some(T::fill_super_raw), + ) + }) +} + +pub fn kill_litter_super(sb: &mut SuperBlock) { + unsafe { + bindings::kill_litter_super(sb.as_ptr_mut()); + } +} From 49ad5021a579b601a35e7565d46f92b49ff6ef0c Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 9 Jun 2021 15:12:31 +0200 Subject: [PATCH 33/58] kernel crate and bs2ramfs: Clean imports --- fs/bs2ramfs/bs2ramfs.rs | 32 +++++++++++++++++-------------- rust/kernel/fs.rs | 3 +-- rust/kernel/fs/libfs_functions.rs | 28 +++++++++++++-------------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 65f91004bae40a..5996ad74cf107d 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -4,20 +4,24 @@ use alloc::boxed::Box; use core::{mem, ptr}; -use kernel::file::File; -use kernel::file_operations::{FileOperations, SeekFrom}; -use kernel::fs::kiocb::Kiocb; -use kernel::fs::super_operations::{Kstatfs, SeqFile, SuperOperations}; -use kernel::iov_iter::IovIter; -use kernel::{bindings, c_types::*, prelude::*, str::CStr, Error, Mode}; - -// should be renamed at some point -use kernel::fs::{ - dentry::Dentry, - inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, - libfs_functions, - super_block::SuperBlock, - FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, +use kernel::{ + bindings, + c_types::*, + file::File, + file_operations::{FileOperations, SeekFrom}, + fs::{ + dentry::Dentry, + inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, + kiocb::Kiocb, + libfs_functions, + super_block::SuperBlock, + super_operations::{Kstatfs, SeqFile, SuperOperations}, + FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, + }, + iov_iter::IovIter, + prelude::*, + str::CStr, + Error, Mode, }; const PAGE_SHIFT: u32 = 12; // x86 (maybe) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index b9c36526a7d00e..e62baad9258960 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -7,10 +7,9 @@ pub mod super_operations; use core::ptr; -use crate::ret_err_ptr; use crate::{ bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, prelude::*, - str::CStr, Error, Result, + ret_err_ptr, str::CStr, Result, }; pub type FileSystemType = bindings::file_system_type; diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 2adbb3fd6279e0..64f3272e583c91 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -1,19 +1,19 @@ -use crate::bindings; -use crate::c_types::*; -use crate::error::Error; -use crate::file::File; -use crate::file_operations::SeekFrom; -use crate::fs::dentry::Dentry; -use crate::fs::from_kernel_err_ptr; -use crate::fs::inode::Inode; -use crate::fs::kiocb::Kiocb; -use crate::fs::super_block::SuperBlock; -use crate::fs::super_operations::Kstatfs; -use crate::fs::DeclaredFileSystemType; -use crate::iov_iter::IovIter; -use crate::Result; use core::ptr; +use crate::{ + bindings, + c_types::*, + error::Error, + file::File, + file_operations::SeekFrom, + fs::{ + dentry::Dentry, from_kernel_err_ptr, inode::Inode, kiocb::Kiocb, super_block::SuperBlock, + super_operations::Kstatfs, DeclaredFileSystemType, + }, + iov_iter::IovIter, + Result, +}; + pub fn generic_file_read_iter(iocb: &mut Kiocb, iter: &mut IovIter) -> Result { Error::parse_int(unsafe { bindings::generic_file_read_iter(iocb.as_ptr_mut(), iter.ptr) as _ }) } From 303d67d4cb2bd26bcfff99dc2309406696d8bc83 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 9 Jun 2021 17:42:41 +0200 Subject: [PATCH 34/58] bs2ramfs: use `and_then` like it is intended --- fs/bs2ramfs/bs2ramfs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 5996ad74cf107d..d509f647b5df1e 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -78,9 +78,9 @@ impl FileSystemBase for BS2Ramfs { unsafe { // TODO: investigate if this really has to be set to NULL in case we run out of memory sb.s_root = ptr::null_mut(); - let inode = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0); - pr_emerg!("Completed ramfs_fill_super_impl::get_inode"); - sb.s_root = inode.and_then(Dentry::make_root).ok_or(Error::ENOMEM)? as *mut _ as *mut _; + sb.s_root = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0) + .and_then(Dentry::make_root) + .ok_or(Error::ENOMEM)? as *mut _ as *mut _; } pr_emerg!("(rust) s_root: {:?}", sb.s_root); sb.set_super_operations(ops); From 75b740a5168fd8475b3923fc198c59a2365b2096 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 9 Jun 2021 17:45:26 +0200 Subject: [PATCH 35/58] kernel crate: use callback pattern instead of methods --- rust/kernel/fs.rs | 86 ++++++++++++++++--------------- rust/kernel/fs/libfs_functions.rs | 17 +++++- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index e62baad9258960..2222083bbaf7aa 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -8,8 +8,8 @@ pub mod super_operations; use core::ptr; use crate::{ - bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, prelude::*, - ret_err_ptr, str::CStr, Result, + bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, ret_err_ptr, + str::CStr, Result, }; pub type FileSystemType = bindings::file_system_type; @@ -30,48 +30,50 @@ pub trait FileSystemBase { fn kill_super(sb: &mut SuperBlock); - unsafe extern "C" fn mount_raw( - fs_type: *mut bindings::file_system_type, - flags: c_int, - device_name: *const c_char, - data: *mut c_void, - ) -> *mut bindings::dentry { - pr_emerg!("in mount_raw"); - let fs_type = &mut *fs_type; - let device_name = CStr::from_char_ptr(device_name); - let data = (data as *mut Self::MountOptions).as_mut(); - ret_err_ptr!(Self::mount(fs_type, flags, device_name, data)) - } - - unsafe extern "C" fn kill_sb_raw(sb: *mut bindings::super_block) { - let sb = sb - .as_mut() - .expect("FileSystemBase::kill_sb_raw got NULL super block") - .as_mut(); - Self::kill_super(sb); - } - fn fill_super( _sb: &mut SuperBlock, _data: Option<&mut Self::MountOptions>, _silent: c_int, - ) -> Result { - pr_emerg!("Using default FileSystem::fill_super"); - Ok(()) - } - - unsafe extern "C" fn fill_super_raw( - sb: *mut bindings::super_block, - data: *mut c_void, - silent: c_int, - ) -> c_int { - pr_emerg!("in fill_super_raw"); - let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); - let data = (data as *mut Self::MountOptions).as_mut(); - Self::fill_super(sb, data, silent) - .map(|_| 0) - .unwrap_or_else(|e| e.to_kernel_errno()) - } + ) -> Result; +} + +// Doesn't work because we need mutable access to an associated item +// pub struct FileSystemTypeVTable(PhantomData); +// impl FileSystemTypeVTable { +// const VTABLE: bindings::file_system_type = bindings::file_system_type { +// name: T::NAME.as_char_ptr() as *const _, +// fs_flags: T::FS_FLAGS, +// mount: Some(mount_callback::), +// kill_sb: Some(kill_superblock_callback::), +// owner: T::OWNER, +// ..DEFAULT_FS_TYPE +// }; + +// pub const fn build() -> &'static bindings::file_system_type { +// &Self::VTABLE +// } +// } + +pub unsafe extern "C" fn mount_callback( + fs_type: *mut bindings::file_system_type, + flags: c_int, + device_name: *const c_char, + data: *mut c_void, +) -> *mut bindings::dentry { + let fs_type = &mut *fs_type; + let device_name = CStr::from_char_ptr(device_name); + let data = (data as *mut T::MountOptions).as_mut(); + ret_err_ptr!(T::mount(fs_type, flags, device_name, data)) +} + +pub unsafe extern "C" fn kill_superblock_callback( + sb: *mut bindings::super_block, +) { + let sb = sb + .as_mut() + .expect("kill_superblock got NULL super block") + .as_mut(); + T::kill_super(sb); } pub trait DeclaredFileSystemType: FileSystemBase { @@ -84,9 +86,9 @@ macro_rules! declare_fs_type { static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { name: <$T as $crate::fs::FileSystemBase>::NAME.as_char_ptr() as *const _, fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, - mount: Some(<$T as $crate::fs::FileSystemBase>::mount_raw), - kill_sb: Some(<$T as $crate::fs::FileSystemBase>::kill_sb_raw), owner: <$T as $crate::fs::FileSystemBase>::OWNER, + mount: Some($crate::fs::mount_callback::<$T>), + kill_sb: Some($crate::fs::kill_superblock_callback::<$T>), ..$crate::fs::DEFAULT_FS_TYPE }; impl $crate::fs::DeclaredFileSystemType for $T { diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 64f3272e583c91..8b2dddc598c7b8 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -8,7 +8,7 @@ use crate::{ file_operations::SeekFrom, fs::{ dentry::Dentry, from_kernel_err_ptr, inode::Inode, kiocb::Kiocb, super_block::SuperBlock, - super_operations::Kstatfs, DeclaredFileSystemType, + super_operations::Kstatfs, DeclaredFileSystemType, FileSystemBase, }, iov_iter::IovIter, Result, @@ -82,6 +82,7 @@ pub fn simple_statfs(root: &mut Dentry, buf: &mut Kstatfs) -> Result { pub fn register_filesystem() -> Result { Error::parse_int(unsafe { bindings::register_filesystem(T::file_system_type()) }).map(|_| ()) } + pub fn unregister_filesystem() -> Result { Error::parse_int(unsafe { bindings::unregister_filesystem(T::file_system_type()) }).map(|_| ()) } @@ -96,11 +97,23 @@ pub fn mount_nodev( flags, data.map(|p| p as *mut _ as *mut _) .unwrap_or_else(ptr::null_mut), - Some(T::fill_super_raw), + Some(fill_super_callback::), ) }) } +unsafe extern "C" fn fill_super_callback( + sb: *mut bindings::super_block, + data: *mut c_void, + silent: c_int, +) -> c_int { + let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); + let data = (data as *mut T::MountOptions).as_mut(); + T::fill_super(sb, data, silent) + .map(|_| 0) + .unwrap_or_else(|e| e.to_kernel_errno()) +} + pub fn kill_litter_super(sb: &mut SuperBlock) { unsafe { bindings::kill_litter_super(sb.as_ptr_mut()); From 4051a099354d9cf1adc9bc269916ba80a93b416a Mon Sep 17 00:00:00 2001 From: Tamino Bauknecht Date: Thu, 10 Jun 2021 22:48:50 +0200 Subject: [PATCH 36/58] kernel crate: Add InodeOperations Co-authored-by: Niklas Mohrin --- rust/kernel/fs.rs | 1 + rust/kernel/fs/inode.rs | 11 +- rust/kernel/fs/inode_operations.rs | 455 +++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 +- rust/kernel/types.rs | 11 +- 5 files changed, 475 insertions(+), 5 deletions(-) create mode 100644 rust/kernel/fs/inode_operations.rs diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 2222083bbaf7aa..0d5b84cb67321b 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,5 +1,6 @@ pub mod dentry; pub mod inode; +pub mod inode_operations; pub mod kiocb; pub mod libfs_functions; pub mod super_block; diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index afbe66d2a6d141..ceee34328668d7 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -1,10 +1,12 @@ +use alloc::boxed::Box; use core::ops::{Deref, DerefMut}; use core::{mem, ptr}; use crate::bindings; use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; +use crate::fs::inode_operations::{InodeOperations, InodeOperationsVtable}; use crate::fs::super_block::SuperBlock; -use crate::types::Mode; +use crate::types::{Dev, Mode}; #[derive(PartialEq, Eq)] pub enum UpdateATime { @@ -83,7 +85,7 @@ impl Inode { bindings::inode_nohighmem(self.as_ptr_mut()); } } - pub fn init_special(&mut self, mode: Mode, device: bindings::dev_t) { + pub fn init_special(&mut self, mode: Mode, device: Dev) { unsafe { bindings::init_special_inode(self.as_ptr_mut(), mode.as_int(), device); } @@ -100,6 +102,11 @@ impl Inode { self.0.__bindgen_anon_3.i_fop = unsafe { FileOperationsVtable::::build() }; } + + pub fn set_inode_operations(&mut self, ops: OPS) { + self.0.i_op = unsafe { InodeOperationsVtable::::build() }; + self.0.i_private = Box::leak(Box::new(ops)) as *mut _ as *mut _; + } } pub struct NopFileOpenAdapter; diff --git a/rust/kernel/fs/inode_operations.rs b/rust/kernel/fs/inode_operations.rs new file mode 100644 index 00000000000000..c367a4515da56e --- /dev/null +++ b/rust/kernel/fs/inode_operations.rs @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Inode operations. +//! +//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h) + +use core::marker; + +use crate::{ + bindings, c_types, + error::{Error, Result}, + from_kernel_result, + fs::{dentry::Dentry, inode::Inode}, + str::CStr, + types::{Dev, Iattr, Kstat, Mode, ModeInt, Path, UserNamespace}, +}; + +/// Corresponds to the kernel's `struct inode_operations`. +/// +/// You implement this trait whenever you would create a `struct inode_operations`. +/// +/// File descriptors may be used from multiple threads/processes concurrently, so your type must be +/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the +/// thread that decrements that associated file's refcount to zero. +pub trait InodeOperations: Send + Sync + Sized + Default { + /// The methods to use to populate [`struct inode_operations`]. + const TO_USE: ToUse; + + fn getattr( + &self, + _mnt_userns: &mut UserNamespace, + _path: &Path, + _stat: &mut Kstat, + _request_mask: u32, + _query_flags: u32, + ) -> Result { + Err(Error::EINVAL) + } + + fn setattr( + &self, + _mnt_userns: &mut UserNamespace, + _dentry: &mut Dentry, + _iattr: &mut Iattr, + ) -> Result { + Err(Error::EINVAL) + } + + fn create( + &self, + _mnt_userns: &mut UserNamespace, + _dir: &mut Inode, + _dentry: &mut Dentry, + _mode: Mode, + _excl: bool, + ) -> Result { + Err(Error::EINVAL) + } + fn lookup( + &self, + _dir: &mut Inode, + _dentry: &mut Dentry, + _flags: c_types::c_uint, + ) -> Result<*mut Dentry> { + Err(Error::EINVAL) + } + fn link(&self, _old_dentry: &mut Dentry, _dir: &mut Inode, _dentry: &mut Dentry) -> Result { + Err(Error::EINVAL) + } + fn unlink(&self, _dir: &mut Inode, _dentry: &mut Dentry) -> Result { + Err(Error::EINVAL) + } + fn symlink( + &self, + _mnt_userns: &mut UserNamespace, + _dir: &mut Inode, + _dentry: &mut Dentry, + _symname: &'static CStr, + ) -> Result { + Err(Error::EINVAL) + } + fn mkdir( + &self, + _mnt_userns: &mut UserNamespace, + _dir: &mut Inode, + _dentry: &mut Dentry, + _mode: Mode, + ) -> Result { + Err(Error::EINVAL) + } + fn rmdir(&self, _dir: &mut Inode, _dentry: &mut Dentry) -> Result { + Err(Error::EINVAL) + } + fn mknod( + &self, + _mnt_userns: &mut UserNamespace, + _dir: &mut Inode, + _dentry: &mut Dentry, + _mode: Mode, + _dev: Dev, + ) -> Result { + Err(Error::EINVAL) + } + fn rename( + &self, + _mnt_userns: &mut UserNamespace, + _old_dir: &mut Inode, + _old_dentry: &mut Dentry, + _new_dir: &mut Inode, + _new_dentry: &mut Dentry, + _flags: c_types::c_uint, + ) -> Result { + Err(Error::EINVAL) + } +} +unsafe extern "C" fn setattr_callback( + mnt_userns: *mut bindings::user_namespace, + dentry: *mut bindings::dentry, + iattr: *mut bindings::iattr, +) -> c_types::c_int { + let dentry = dentry.as_mut().expect("setattr got null dentry").as_mut(); + let inode = dentry.d_inode; // use d_inode method instead? + let i_ops = &*((*inode).i_private as *const T); + from_kernel_result! { + i_ops.setattr(&mut (*mnt_userns), dentry, &mut (*iattr)).map(|()| 0) + } +} + +unsafe extern "C" fn getattr_callback( + mnt_userns: *mut bindings::user_namespace, + path: *const bindings::path, + stat: *mut bindings::kstat, + request_mask: u32, + query_flags: u32, +) -> c_types::c_int { + let dentry = (*path).dentry; + let inode = (*dentry).d_inode; // use d_inode method instead? + let i_ops = &*((*inode).i_private as *const T); + from_kernel_result! { + i_ops.getattr(&mut (*mnt_userns), &(*path), &mut (*stat), request_mask, query_flags).map(|()| 0) + } +} + +unsafe extern "C" fn create_callback( + mnt_userns: *mut bindings::user_namespace, + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, + mode: ModeInt, + excl: bool, +) -> c_types::c_int { + let dir = dir.as_mut().expect("create got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("create got null dentry").as_mut(); + from_kernel_result! { + i_ops.create(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), excl).map(|()| 0) + } +} +unsafe extern "C" fn lookup_callback( + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, + flags: c_types::c_uint, +) -> *mut bindings::dentry { + let dir = dir.as_mut().expect("lookup got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("lookup got null dentry").as_mut(); + ret_err_ptr!(i_ops.lookup(dir, dentry, flags).map(|p| p as *mut _)) +} +unsafe extern "C" fn link_callback( + old_dentry: *mut bindings::dentry, + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, +) -> c_types::c_int { + let dir = dir.as_mut().expect("link got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let old_dentry = old_dentry + .as_mut() + .expect("link got null old_dentry") + .as_mut(); + let dentry = dentry.as_mut().expect("link got null dentry").as_mut(); + from_kernel_result! { + i_ops.link(old_dentry, dir, dentry).map(|()| 0) + } +} +unsafe extern "C" fn unlink_callback( + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, +) -> c_types::c_int { + let dir = dir.as_mut().expect("unlink got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("unlink got null dentry").as_mut(); + from_kernel_result! { + i_ops.unlink(dir, dentry).map(|()| 0) + } +} +unsafe extern "C" fn symlink_callback( + mnt_userns: *mut bindings::user_namespace, + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, + symname: *const c_types::c_char, +) -> c_types::c_int { + let dir = dir.as_mut().expect("symlink got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("symlink got null dentry").as_mut(); + from_kernel_result! { + i_ops.symlink(&mut (*mnt_userns), dir, dentry, CStr::from_char_ptr(symname)).map(|()| 0) + } +} +unsafe extern "C" fn mkdir_callback( + mnt_userns: *mut bindings::user_namespace, + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, + mode: ModeInt, +) -> c_types::c_int { + let dir = dir.as_mut().expect("mkdir got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("mkdir got null dentry").as_mut(); + from_kernel_result! { + i_ops.mkdir(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode)).map(|()| 0) // todo: mode_t is u32 but u16 in Mode? + } +} +unsafe extern "C" fn rmdir_callback( + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, +) -> c_types::c_int { + let dir = dir.as_mut().expect("rmdir got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("rmdir got null dentry").as_mut(); + from_kernel_result! { + i_ops.rmdir(dir, dentry).map(|()| 0) + } +} +unsafe extern "C" fn mknod_callback( + mnt_userns: *mut bindings::user_namespace, + dir: *mut bindings::inode, + dentry: *mut bindings::dentry, + mode: ModeInt, + dev: bindings::dev_t, +) -> c_types::c_int { + let dir = dir.as_mut().expect("mknod got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("mknod got null dentry").as_mut(); + from_kernel_result! { + i_ops.mknod(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), dev).map(|()| 0) + } +} +unsafe extern "C" fn rename_callback( + mnt_userns: *mut bindings::user_namespace, + old_dir: *mut bindings::inode, + old_dentry: *mut bindings::dentry, + new_dir: *mut bindings::inode, + new_dentry: *mut bindings::dentry, + flags: c_types::c_uint, +) -> c_types::c_int { + let old_dir = old_dir.as_mut().expect("rename got null dir").as_mut(); + let i_ops = &*(old_dir.i_private as *const T); + let old_dentry = old_dentry + .as_mut() + .expect("rename got null dentry") + .as_mut(); + let new_dir = new_dir.as_mut().expect("rename got null dir").as_mut(); + let new_dentry = new_dentry + .as_mut() + .expect("rename got null dentry") + .as_mut(); + from_kernel_result! { + i_ops.rename(&mut (*mnt_userns), old_dir, old_dentry, new_dir, new_dentry, flags).map(|()| 0) + } +} + +pub(crate) struct InodeOperationsVtable(marker::PhantomData); + +impl InodeOperationsVtable { + const VTABLE: bindings::inode_operations = bindings::inode_operations { + getattr: if T::TO_USE.getattr { + Some(getattr_callback::) + } else { + None + }, + setattr: if T::TO_USE.setattr { + Some(setattr_callback::) + } else { + None + }, + lookup: if T::TO_USE.lookup { + Some(lookup_callback::) + } else { + None + }, + get_link: None, + permission: None, + get_acl: None, + readlink: None, + create: if T::TO_USE.create { + Some(create_callback::) + } else { + None + }, + link: if T::TO_USE.link { + Some(link_callback::) + } else { + None + }, + unlink: if T::TO_USE.unlink { + Some(unlink_callback::) + } else { + None + }, + symlink: if T::TO_USE.symlink { + Some(symlink_callback::) + } else { + None + }, + mkdir: if T::TO_USE.mkdir { + Some(mkdir_callback::) + } else { + None + }, + rmdir: if T::TO_USE.rmdir { + Some(rmdir_callback::) + } else { + None + }, + mknod: if T::TO_USE.mknod { + Some(mknod_callback::) + } else { + None + }, + rename: if T::TO_USE.rename { + Some(rename_callback::) + } else { + None + }, + listxattr: None, + fiemap: None, + update_time: None, + atomic_open: None, + tmpfile: None, + set_acl: None, + }; + + /// Builds an instance of [`struct inode_operations`]. + /// + /// # Safety + /// + /// The caller must ensure that the adapter is compatible with the way the device is registered. + pub(crate) const unsafe fn build() -> &'static bindings::inode_operations { + &Self::VTABLE + } +} + +/// Represents which fields of [`struct inode_block_operations`] should be populated with pointers. +pub struct ToUse { + /// The `lookup` field of [`struct inode_operations`]. + pub lookup: bool, + + /// The `get_link` field of [`struct inode_operations`]. + pub get_link: bool, + + /// The `permission` field of [`struct inode_operations`]. + pub permission: bool, + + /// The `get_acl` field of [`struct inode_operations`]. + pub get_acl: bool, + + /// The `readlink` field of [`struct inode_operations`]. + pub readlink: bool, + + /// The `create` field of [`struct inode_operations`]. + pub create: bool, + + /// The `link` field of [`struct inode_operations`]. + pub link: bool, + + /// The `unlink` field of [`struct inode_operations`]. + pub unlink: bool, + + /// The `symlink` field of [`struct inode_operations`]. + pub symlink: bool, + + /// The `mkdir` field of [`struct inode_operations`]. + pub mkdir: bool, + + /// The `rmdir` field of [`struct inode_operations`]. + pub rmdir: bool, + + /// The `mknod` field of [`struct inode_operations`]. + pub mknod: bool, + + /// The `rename` field of [`struct inode_operations`]. + pub rename: bool, + + /// The `listxattr` field of [`struct inode_operations`]. + pub listxattr: bool, + + /// The `fiemap` field of [`struct inode_operations`]. + pub fiemap: bool, + + /// The `update_time` field of [`struct inode_operations`]. + pub update_time: bool, + + /// The `atomic_open` field of [`struct inode_operations`]. + pub atomic_open: bool, + + /// The `tmpfile` field of [`struct inode_operations`]. + pub tmpfile: bool, + + /// The `set_acl` field of [`struct inode_operations`]. + pub set_acl: bool, + + /// The `getattr` field of [`struct inode_operations`]. + pub getattr: bool, + + /// The `setattr` field of [`struct inode_operations`]. + pub setattr: bool, +} + +/// A constant version where all values are to set to `false`, that is, all supported fields will +/// be set to null pointers. +pub const USE_NONE: ToUse = ToUse { + lookup: false, + get_link: false, + permission: false, + get_acl: false, + readlink: false, + create: false, + link: false, + unlink: false, + symlink: false, + mkdir: false, + rmdir: false, + mknod: false, + rename: false, + listxattr: false, + fiemap: false, + update_time: false, + atomic_open: false, + tmpfile: false, + set_acl: false, + getattr: false, + setattr: false, +}; + +#[macro_export] +macro_rules! declare_inode_operations { + () => { + const TO_USE: $crate::fs::inode_operations::ToUse = $crate::fs::inode_operations::USE_NONE; + }; + ($($i:ident),+) => { + const TO_USE: kernel::fs::inode_operations::ToUse = + $crate::fs::inode_operations::ToUse { + $($i: true),+ , + ..$crate::fs::inode_operations::USE_NONE + }; + }; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index fc56c7e0a0b0c6..2813bd2793193d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -76,7 +76,7 @@ pub mod iov_iter; mod macros; pub mod of; pub mod platdev; -mod types; +pub mod types; pub mod user_ptr; #[doc(hidden)] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index a9c10f92f074dc..92f512755400bc 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -16,6 +16,12 @@ use crate::c_types; use crate::declare_constant_from_bindings; use crate::sync::{Ref, RefCounted}; +pub type UserNamespace = bindings::user_namespace; +pub type Iattr = bindings::iattr; +pub type Path = bindings::path; +pub type Kstat = bindings::kstat; +pub type Dev = bindings::dev_t; + /// Permissions. /// /// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h) @@ -23,15 +29,16 @@ use crate::sync::{Ref, RefCounted}; /// C header: [`include/linux/stat.h`](../../../../include/linux/stat.h) #[derive(Clone, Copy, PartialEq, Eq)] pub struct Mode(bindings::umode_t); +pub type ModeInt = u16; impl Mode { /// Creates a [`Mode`] from an integer. - pub const fn from_int(m: u16) -> Mode { + pub const fn from_int(m: ModeInt) -> Mode { Mode(m) } /// Returns the mode as an integer. - pub fn as_int(&self) -> u16 { + pub fn as_int(&self) -> ModeInt { self.0 } } From 87fca86bebf381d64ec67f7791847bdc88e66f46 Mon Sep 17 00:00:00 2001 From: Tamino Bauknecht Date: Thu, 10 Jun 2021 22:51:11 +0200 Subject: [PATCH 37/58] kernel crate: Add libfs functions for inode operations --- rust/kernel/fs/libfs_functions.rs | 92 +++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 8b2dddc598c7b8..c9abeb7fe181cb 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -11,6 +11,8 @@ use crate::{ super_operations::Kstatfs, DeclaredFileSystemType, FileSystemBase, }, iov_iter::IovIter, + str::CStr, + types::{Iattr, Kstat, Path, UserNamespace}, Result, }; @@ -79,6 +81,96 @@ pub fn simple_statfs(root: &mut Dentry, buf: &mut Kstatfs) -> Result { .map(|_| ()) } +pub fn simple_setattr( + mnt_userns: &mut UserNamespace, + dentry: &mut Dentry, + iattr: &mut Iattr, +) -> Result { + Error::parse_int(unsafe { + bindings::simple_setattr(mnt_userns as *mut _, dentry.as_ptr_mut(), iattr as *mut _) + }) + .map(|_| ()) +} + +pub fn simple_getattr( + mnt_userns: &mut UserNamespace, + path: &Path, + stat: &mut Kstat, + request_mask: u32, + query_flags: u32, +) -> Result { + Error::parse_int(unsafe { + bindings::simple_getattr( + mnt_userns as *mut _, + path as *const _, + stat as *mut _, + request_mask, + query_flags, + ) + }) + .map(|_| ()) +} + +pub fn simple_lookup(dir: &mut Inode, dentry: &mut Dentry, flags: c_uint) -> Result<*mut Dentry> { + // todo: return type ptr vs ref? + from_kernel_err_ptr(unsafe { + bindings::simple_lookup(dir.as_ptr_mut(), dentry.as_ptr_mut(), flags) as *mut _ + }) +} + +pub fn simple_link(old_dentry: &mut Dentry, dir: &mut Inode, dentry: &mut Dentry) -> Result { + Error::parse_int(unsafe { + bindings::simple_link( + old_dentry.as_ptr_mut(), + dir.as_ptr_mut(), + dentry.as_ptr_mut(), + ) + }) + .map(|_| ()) +} + +pub fn simple_unlink(dir: &mut Inode, dentry: &mut Dentry) -> Result { + Error::parse_int(unsafe { bindings::simple_unlink(dir.as_ptr_mut(), dentry.as_ptr_mut()) }) + .map(|_| ()) +} + +pub fn simple_rmdir(dir: &mut Inode, dentry: &mut Dentry) -> Result { + Error::parse_int(unsafe { bindings::simple_rmdir(dir.as_ptr_mut(), dentry.as_ptr_mut()) }) + .map(|_| ()) +} + +pub fn simple_rename( + mnt_userns: &mut UserNamespace, + old_dir: &mut Inode, + old_dentry: &mut Dentry, + new_dir: &mut Inode, + new_dentry: &mut Dentry, + flags: c_uint, +) -> Result { + Error::parse_int(unsafe { + bindings::simple_rename( + mnt_userns as *mut _, + old_dir.as_ptr_mut(), + old_dentry.as_ptr_mut(), + new_dir.as_ptr_mut(), + new_dentry.as_ptr_mut(), + flags, + ) + }) + .map(|_| ()) +} + +pub fn page_symlink(inode: &mut Inode, symname: &'static CStr) -> Result { + Error::parse_int(unsafe { + bindings::page_symlink( + inode.as_ptr_mut(), + symname.as_ptr() as _, + symname.len_with_nul() as _, + ) + }) + .map(|_| ()) +} + pub fn register_filesystem() -> Result { Error::parse_int(unsafe { bindings::register_filesystem(T::file_system_type()) }).map(|_| ()) } From 9bdd0de411c44334af4251b79a7b63fdb4210584 Mon Sep 17 00:00:00 2001 From: Tamino Bauknecht Date: Thu, 10 Jun 2021 22:51:33 +0200 Subject: [PATCH 38/58] bs2ramfs: Use InodeOperations --- fs/bs2ramfs/bs2ramfs.rs | 310 ++++++++++++++++++++-------------------- 1 file changed, 158 insertions(+), 152 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index d509f647b5df1e..179afe45f9366f 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -12,15 +12,17 @@ use kernel::{ fs::{ dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, + inode_operations::InodeOperations, kiocb::Kiocb, libfs_functions, super_block::SuperBlock, super_operations::{Kstatfs, SeqFile, SuperOperations}, - FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, DEFAULT_INODE_OPERATIONS, + FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, }, iov_iter::IovIter, prelude::*, str::CStr, + types::{Dev, Iattr, Kstat, Path, UserNamespace}, Error, Mode, }; @@ -121,14 +123,6 @@ impl Default for RamfsMountOpts { } } -unsafe extern "C" fn ramfs_show_options( - _m: *mut bindings::seq_file, - _root: *mut bindings::dentry, -) -> c_int { - pr_emerg!("ramfs show options, doing nothing"); - 0 -} - #[derive(Default)] struct Bs2RamfsFileOps; @@ -231,14 +225,148 @@ static RAMFS_AOPS: bindings::address_space_operations = bindings::address_space_ ..DEFAULT_ADDRESS_SPACE_OPERATIONS }; -static RAMFS_FILE_INODE_OPS: bindings::inode_operations = bindings::inode_operations { - setattr: Some(bindings::simple_setattr), - getattr: Some(bindings::simple_getattr), - ..DEFAULT_INODE_OPERATIONS -}; +#[derive(Default)] +struct Bs2RamfsFileInodeOps; + +impl InodeOperations for Bs2RamfsFileInodeOps { + kernel::declare_inode_operations!(setattr, getattr); + + fn setattr( + &self, + mnt_userns: &mut UserNamespace, + dentry: &mut Dentry, + iattr: &mut Iattr, + ) -> Result { + libfs_functions::simple_setattr(mnt_userns, dentry, iattr) + } + + fn getattr( + &self, + mnt_userns: &mut UserNamespace, + path: &Path, + stat: &mut Kstat, + request_mask: u32, + query_flags: u32, + ) -> Result { + libfs_functions::simple_getattr(mnt_userns, path, stat, request_mask, query_flags) + } +} + +#[derive(Default)] +struct Bs2RamfsDirInodeOps; + +impl InodeOperations for Bs2RamfsDirInodeOps { + kernel::declare_inode_operations!( + create, lookup, link, unlink, symlink, mkdir, rmdir, mknod, rename + ); + + fn create( + &self, + mnt_userns: &mut UserNamespace, + dir: &mut Inode, + dentry: &mut Dentry, + mode: Mode, + _excl: bool, + ) -> Result { + pr_emerg!("enter create"); + self.mknod(mnt_userns, dir, dentry, mode | Mode::S_IFREG, 0) + } + + fn lookup(&self, dir: &mut Inode, dentry: &mut Dentry, flags: c_uint) -> Result<*mut Dentry> { + pr_emerg!("enter lookup"); + libfs_functions::simple_lookup(dir, dentry, flags) // niklas: This returns 0, but it does so on main too, so it's not the problem + } + + fn link(&self, old_dentry: &mut Dentry, dir: &mut Inode, dentry: &mut Dentry) -> Result { + libfs_functions::simple_link(old_dentry, dir, dentry) + } + + fn unlink(&self, dir: &mut Inode, dentry: &mut Dentry) -> Result { + libfs_functions::simple_unlink(dir, dentry) + } + + fn symlink( + &self, + _mnt_userns: &mut UserNamespace, + dir: &mut Inode, + dentry: &mut Dentry, + symname: &'static CStr, + ) -> Result { + let inode = ramfs_get_inode( + unsafe { dir.i_sb.as_mut().unwrap().as_mut() }, + Some(dir), + Mode::S_IFLNK | Mode::S_IRWXUGO, + 0, + ) + .ok_or(Error::ENOSPC)?; + + if let Err(e) = libfs_functions::page_symlink(inode, symname) { + inode.put(); + return Err(e); + } + + dentry.instantiate(inode); + dentry.get(); + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); + Ok(()) + } + + fn mkdir( + &self, + mnt_userns: &mut UserNamespace, + dir: &mut Inode, + dentry: &mut Dentry, + mode: Mode, + ) -> Result { + pr_emerg!("enter mkdir"); + if let Err(_) = self.mknod(mnt_userns, dir, dentry, mode | Mode::S_IFDIR, 0) { + pr_emerg!("mkdir: inc_nlink"); + dir.inc_nlink(); + } + Ok(()) + } -#[no_mangle] -pub unsafe fn ramfs_get_inode<'a>( + fn rmdir(&self, dir: &mut Inode, dentry: &mut Dentry) -> Result { + libfs_functions::simple_rmdir(dir, dentry) + } + + fn mknod( + &self, + _mnt_userns: &mut UserNamespace, + dir: &mut Inode, + dentry: &mut Dentry, + mode: Mode, + dev: Dev, + ) -> Result { + // todo: write some kind of wrapper + ramfs_get_inode( + unsafe { dir.i_sb.as_mut().unwrap().as_mut() }, + Some(dir), + mode, + dev, + ) + .ok_or(Error::ENOSPC) + .map(|inode| { + dentry.instantiate(inode); + dentry.get(); + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); + () + }) + } + fn rename( + &self, + mnt_userns: &mut UserNamespace, + old_dir: &mut Inode, + old_dentry: &mut Dentry, + new_dir: &mut Inode, + new_dentry: &mut Dentry, + flags: c_uint, + ) -> Result { + libfs_functions::simple_rename(mnt_userns, old_dir, old_dentry, new_dir, new_dentry, flags) + } +} + +pub fn ramfs_get_inode<'a>( sb: &'a mut SuperBlock, dir: Option<&'_ mut Inode>, mode: Mode, @@ -246,25 +374,31 @@ pub unsafe fn ramfs_get_inode<'a>( ) -> Option<&'a mut Inode> { Inode::new(sb).map(|inode| { inode.i_ino = Inode::next_ino() as _; - inode.init_owner(&mut bindings::init_user_ns, dir, mode); + inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); - (*inode.i_mapping).a_ops = &RAMFS_AOPS; - rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); - rust_helper_mapping_set_unevictable(inode.i_mapping); + unsafe { (*inode.i_mapping).a_ops = &RAMFS_AOPS }; + unsafe { + rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); + } + unsafe { + rust_helper_mapping_set_unevictable(inode.i_mapping); + } inode.update_acm_time(UpdateATime::Yes, UpdateCTime::Yes, UpdateMTime::Yes); match mode & Mode::S_IFMT { Mode::S_IFREG => { - inode.i_op = &RAMFS_FILE_INODE_OPS; + inode.set_inode_operations(Bs2RamfsFileInodeOps); inode.set_file_operations::(); } Mode::S_IFDIR => { - inode.i_op = &RAMFS_DIR_INODE_OPS; - inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; + inode.set_inode_operations(Bs2RamfsDirInodeOps); + unsafe { inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations }; // todo: write wrapper function + // inode.i_op = &RAMFS_DIR_INODE_OPS; + // inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; inode.inc_nlink(); } Mode::S_IFLNK => { - inode.i_op = &bindings::page_symlink_inode_operations; + unsafe { inode.i_op = &bindings::page_symlink_inode_operations }; inode.nohighmem(); } _ => { @@ -275,131 +409,3 @@ pub unsafe fn ramfs_get_inode<'a>( inode }) } - -unsafe extern "C" fn ramfs_mknod( - _ns: *mut bindings::user_namespace, - dir: *mut bindings::inode, - dentry: *mut bindings::dentry, - mode: bindings::umode_t, - dev: bindings::dev_t, -) -> i32 { - let dir = dir - .as_mut() - .expect("ramfs_mknod got NULL directory") - .as_mut(); - ramfs_get_inode( - dir.i_sb - .as_mut() - .expect("dir has NULL super block") - .as_mut(), - Some(dir), - Mode::from_int(mode), - dev, - ) - .map_or(Error::ENOSPC.to_kernel_errno(), move |inode| { - let dentry = dentry - .as_mut() - .expect("Called ramfs_mknod with NULL dentry") - .as_mut(); - dentry.instantiate(inode); - dentry.get(); - dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); - 0 - }) -} - -unsafe extern "C" fn ramfs_mkdir( - ns: *mut bindings::user_namespace, - dir: *mut bindings::inode, - dentry: *mut bindings::dentry, - mode: bindings::umode_t, -) -> i32 { - let dir = dir - .as_mut() - .expect("ramfs_mkdir got NULL directory") - .as_mut(); - if ramfs_mknod( - ns, - dir.as_ptr_mut(), - dentry, - mode | Mode::S_IFDIR.as_int() as bindings::umode_t, - 0, - ) < 0 - { - dir.inc_nlink(); - } - 0 -} - -unsafe extern "C" fn ramfs_create( - ns: *mut bindings::user_namespace, - dir: *mut bindings::inode, - dentry: *mut bindings::dentry, - mode: bindings::umode_t, - _excl: bool, -) -> i32 { - ramfs_mknod( - ns, - dir, - dentry, - mode | Mode::S_IFREG.as_int() as bindings::umode_t, - 0, - ) -} - -#[no_mangle] -unsafe extern "C" fn ramfs_symlink( - _ns: *mut bindings::user_namespace, - dir: *mut bindings::inode, - dentry: *mut bindings::dentry, - symname: *const c_char, -) -> i32 { - pr_info!("in symlink"); - let dir = dir - .as_mut() - .expect("ramfs_symlink got NULL directory") - .as_mut(); - ramfs_get_inode( - dir.i_sb - .as_mut() - .expect("dir had NULL super block") - .as_mut(), - Some(dir), - Mode::S_IFLNK | Mode::S_IRWXUGO, - 0, - ) - .map_or(Error::ENOSPC.to_kernel_errno(), |inode| { - pr_info!("got inode ptr {:?}", inode.as_ptr_mut()); - let l = bindings::strlen(symname) + 1; - pr_info!("str has len {:?}", l); - let ret = bindings::page_symlink(inode.as_ptr_mut(), symname, l as _); - if ret == 0 { - pr_info!("page_symlink is ok"); - let dentry = dentry - .as_mut() - .expect("Called ramfs_symlink with NULL dentry") - .as_mut(); - dentry.instantiate(inode); - dentry.get(); - dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); - pr_info!("current_time is ok"); - } else { - inode.put(); - pr_info!("iput is ok"); - } - ret - }) -} - -static RAMFS_DIR_INODE_OPS: bindings::inode_operations = bindings::inode_operations { - create: Some(ramfs_create), - lookup: Some(bindings::simple_lookup), - link: Some(bindings::simple_link), - unlink: Some(bindings::simple_unlink), - symlink: Some(ramfs_symlink), - mkdir: Some(ramfs_mkdir), - rmdir: Some(bindings::simple_rmdir), - mknod: Some(ramfs_mknod), - rename: Some(bindings::simple_rename), - ..DEFAULT_INODE_OPERATIONS -}; From 7c014e1d3e2c6d8c3444d48bc46c9c2e934fd2b2 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Thu, 10 Jun 2021 22:52:28 +0200 Subject: [PATCH 39/58] kernel crate: move and delete things in fs.rs --- rust/kernel/fs.rs | 140 +++++++++------------------------------------- 1 file changed, 26 insertions(+), 114 deletions(-) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 0d5b84cb67321b..dce5e8eb78f278 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -32,12 +32,35 @@ pub trait FileSystemBase { fn kill_super(sb: &mut SuperBlock); fn fill_super( - _sb: &mut SuperBlock, - _data: Option<&mut Self::MountOptions>, - _silent: c_int, + sb: &mut SuperBlock, + data: Option<&mut Self::MountOptions>, + silent: c_int, ) -> Result; } +pub trait DeclaredFileSystemType: FileSystemBase { + fn file_system_type() -> *mut bindings::file_system_type; +} + +#[macro_export] +macro_rules! declare_fs_type { + ($T:ty, $S:ident) => { + static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { + name: <$T as $crate::fs::FileSystemBase>::NAME.as_char_ptr() as *const _, + fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, + owner: <$T as $crate::fs::FileSystemBase>::OWNER, + mount: Some($crate::fs::mount_callback::<$T>), + kill_sb: Some($crate::fs::kill_superblock_callback::<$T>), + ..$crate::fs::DEFAULT_FS_TYPE + }; + impl $crate::fs::DeclaredFileSystemType for $T { + fn file_system_type() -> *mut $crate::bindings::file_system_type { + unsafe { &mut $S as *mut _ } + } + } + }; +} + // Doesn't work because we need mutable access to an associated item // pub struct FileSystemTypeVTable(PhantomData); // impl FileSystemTypeVTable { @@ -77,58 +100,6 @@ pub unsafe extern "C" fn kill_superblock_callback( T::kill_super(sb); } -pub trait DeclaredFileSystemType: FileSystemBase { - fn file_system_type() -> *mut bindings::file_system_type; -} - -#[macro_export] -macro_rules! declare_fs_type { - ($T:ty, $S:ident) => { - static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { - name: <$T as $crate::fs::FileSystemBase>::NAME.as_char_ptr() as *const _, - fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, - owner: <$T as $crate::fs::FileSystemBase>::OWNER, - mount: Some($crate::fs::mount_callback::<$T>), - kill_sb: Some($crate::fs::kill_superblock_callback::<$T>), - ..$crate::fs::DEFAULT_FS_TYPE - }; - impl $crate::fs::DeclaredFileSystemType for $T { - fn file_system_type() -> *mut $crate::bindings::file_system_type { - unsafe { &mut $S as *mut _ } - } - } - }; -} - -pub const DEFAULT_SUPER_OPS: bindings::super_operations = bindings::super_operations { - statfs: None, - drop_inode: None, - show_options: None, - alloc_inode: None, - destroy_inode: None, - dirty_inode: None, - write_inode: None, - evict_inode: None, - put_super: None, - sync_fs: None, - freeze_super: None, - freeze_fs: None, - thaw_super: None, - unfreeze_fs: None, - remount_fs: None, - umount_begin: None, - show_devname: None, - show_path: None, - show_stats: None, - quota_read: None, - free_inode: None, - quota_write: None, - get_dquots: None, - bdev_try_to_free_page: None, - nr_cached_objects: None, - free_cached_objects: None, -}; - pub const DEFAULT_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations = bindings::address_space_operations { readpage: None, @@ -155,30 +126,6 @@ pub const DEFAULT_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations = swap_deactivate: None, }; -pub const DEFAULT_INODE_OPERATIONS: bindings::inode_operations = bindings::inode_operations { - create: None, - lookup: None, - link: None, - unlink: None, - symlink: None, - mkdir: None, - rmdir: None, - mknod: None, - rename: None, - listxattr: None, - fiemap: None, - update_time: None, - tmpfile: None, - set_acl: None, - get_link: None, - permission: None, - get_acl: None, - readlink: None, - setattr: None, - getattr: None, - atomic_open: None, -}; - pub const DEFAULT_FS_TYPE: bindings::file_system_type = bindings::file_system_type { name: ptr::null(), fs_flags: 0, @@ -199,38 +146,3 @@ pub const DEFAULT_FS_TYPE: bindings::file_system_type = bindings::file_system_ty i_mutex_key: bindings::lock_class_key {}, i_mutex_dir_key: bindings::lock_class_key {}, }; - -pub const DEFAULT_FILE_OPERATIONS: bindings::file_operations = bindings::file_operations { - owner: ptr::null_mut(), - llseek: None, - read: None, - write: None, - read_iter: None, - write_iter: None, - iopoll: None, - iterate: None, - iterate_shared: None, - poll: None, - unlocked_ioctl: None, - compat_ioctl: None, - mmap: None, - mmap_supported_flags: 0, - open: None, - flush: None, - release: None, - fsync: None, - fasync: None, - lock: None, - sendpage: None, - get_unmapped_area: None, - check_flags: None, - flock: None, - splice_write: None, - splice_read: None, - setlease: None, - fallocate: None, - show_fdinfo: None, - copy_file_range: None, - remap_file_range: None, - fadvise: None, -}; From 7bb81e757f882a7ebf92d552634a667379b1751c Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Thu, 10 Jun 2021 23:32:30 +0200 Subject: [PATCH 40/58] changes needed after compiler settings changed with rebase --- rust/kernel/file_operations.rs | 46 +++++---- rust/kernel/fs.rs | 22 ++-- rust/kernel/fs/inode_operations.rs | 156 +++++++++++++++++------------ rust/kernel/fs/libfs_functions.rs | 12 ++- rust/kernel/fs/super_operations.rs | 34 ++++--- 5 files changed, 157 insertions(+), 113 deletions(-) diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 45f2ebb6e25dd2..e080d657d47e30 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -124,11 +124,13 @@ unsafe extern "C" fn read_iter_callback( raw_iter: *mut bindings::iov_iter, ) -> isize { from_kernel_result! { - let mut iter = IovIter::from_ptr(raw_iter); - let file = (*iocb).ki_filp; - let f = &*((*file).private_data as *const T); - let read = f.read_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; - Ok(read as _) + unsafe { + let mut iter = IovIter::from_ptr(raw_iter); + let file = (*iocb).ki_filp; + let f = &*((*file).private_data as *const T); + let read = f.read_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; + Ok(read as _) + } } } @@ -154,11 +156,13 @@ unsafe extern "C" fn write_iter_callback( raw_iter: *mut bindings::iov_iter, ) -> isize { from_kernel_result! { - let mut iter = IovIter::from_ptr(raw_iter); - let file = (*iocb).ki_filp; - let f = &*((*file).private_data as *const T); - let written = f.write_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; - Ok(written as _) + unsafe { + let mut iter = IovIter::from_ptr(raw_iter); + let file = (*iocb).ki_filp; + let f = &*((*file).private_data as *const T); + let written = f.write_iter(iocb.as_mut().unwrap().as_mut(), &mut iter)?; + Ok(written as _) + } } } @@ -254,8 +258,8 @@ unsafe extern "C" fn get_unmapped_area_callback( flags: c_types::c_ulong, ) -> c_types::c_ulong { let ret: i64 = from_kernel_result! { - let f = &*((*file).private_data as *const T); - let res = f.get_unmapped_area(&FileRef::from_ptr(file), addr, len, pgoff, flags)?; + let f = unsafe { &*((*file).private_data as *const T) }; + let res = f.get_unmapped_area(unsafe { &FileRef::from_ptr(file) }, addr, len, pgoff, flags)?; Ok(res as _) }; ret as _ @@ -282,9 +286,11 @@ unsafe extern "C" fn splice_read_callback( flags: c_types::c_uint, ) -> c_types::c_ssize_t { from_kernel_result! { - let f = &*((*file).private_data as *const T); - let ret = f.splice_read(&FileRef::from_ptr(file), ppos, &mut *pipe, len, flags)?; - Ok(ret as _) + unsafe { + let f = &*((*file).private_data as *const T); + let ret = f.splice_read(&FileRef::from_ptr(file), ppos, &mut *pipe, len, flags)?; + Ok(ret as _) + } } } @@ -295,10 +301,12 @@ unsafe extern "C" fn splice_write_callback( len: c_types::c_size_t, flags: c_types::c_uint, ) -> c_types::c_ssize_t { - from_kernel_result! { - let f = &*((*file).private_data as *const T); - let ret = f.splice_write(&mut *pipe, &FileRef::from_ptr(file), ppos, len, flags)?; - Ok(ret as _) + unsafe { + from_kernel_result! { + let f = &*((*file).private_data as *const T); + let ret = f.splice_write(&mut *pipe, &FileRef::from_ptr(file), ppos, len, flags)?; + Ok(ret as _) + } } } diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index dce5e8eb78f278..8f172c4f030944 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -84,20 +84,24 @@ pub unsafe extern "C" fn mount_callback( device_name: *const c_char, data: *mut c_void, ) -> *mut bindings::dentry { - let fs_type = &mut *fs_type; - let device_name = CStr::from_char_ptr(device_name); - let data = (data as *mut T::MountOptions).as_mut(); - ret_err_ptr!(T::mount(fs_type, flags, device_name, data)) + unsafe { + let fs_type = &mut *fs_type; + let device_name = CStr::from_char_ptr(device_name); + let data = (data as *mut T::MountOptions).as_mut(); + ret_err_ptr!(T::mount(fs_type, flags, device_name, data)) + } } pub unsafe extern "C" fn kill_superblock_callback( sb: *mut bindings::super_block, ) { - let sb = sb - .as_mut() - .expect("kill_superblock got NULL super block") - .as_mut(); - T::kill_super(sb); + unsafe { + let sb = sb + .as_mut() + .expect("kill_superblock got NULL super block") + .as_mut(); + T::kill_super(sb); + } } pub const DEFAULT_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations = diff --git a/rust/kernel/fs/inode_operations.rs b/rust/kernel/fs/inode_operations.rs index c367a4515da56e..c38244c43e5f2f 100644 --- a/rust/kernel/fs/inode_operations.rs +++ b/rust/kernel/fs/inode_operations.rs @@ -118,11 +118,13 @@ unsafe extern "C" fn setattr_callback( dentry: *mut bindings::dentry, iattr: *mut bindings::iattr, ) -> c_types::c_int { - let dentry = dentry.as_mut().expect("setattr got null dentry").as_mut(); - let inode = dentry.d_inode; // use d_inode method instead? - let i_ops = &*((*inode).i_private as *const T); - from_kernel_result! { - i_ops.setattr(&mut (*mnt_userns), dentry, &mut (*iattr)).map(|()| 0) + unsafe { + let dentry = dentry.as_mut().expect("setattr got null dentry").as_mut(); + let inode = dentry.d_inode; // use d_inode method instead? + let i_ops = &*((*inode).i_private as *const T); + from_kernel_result! { + i_ops.setattr(&mut (*mnt_userns), dentry, &mut (*iattr)).map(|()| 0) + } } } @@ -133,11 +135,13 @@ unsafe extern "C" fn getattr_callback( request_mask: u32, query_flags: u32, ) -> c_types::c_int { - let dentry = (*path).dentry; - let inode = (*dentry).d_inode; // use d_inode method instead? - let i_ops = &*((*inode).i_private as *const T); - from_kernel_result! { - i_ops.getattr(&mut (*mnt_userns), &(*path), &mut (*stat), request_mask, query_flags).map(|()| 0) + unsafe { + let dentry = (*path).dentry; + let inode = (*dentry).d_inode; // use d_inode method instead? + let i_ops = &*((*inode).i_private as *const T); + from_kernel_result! { + i_ops.getattr(&mut (*mnt_userns), &(*path), &mut (*stat), request_mask, query_flags).map(|()| 0) + } } } @@ -148,11 +152,13 @@ unsafe extern "C" fn create_callback( mode: ModeInt, excl: bool, ) -> c_types::c_int { - let dir = dir.as_mut().expect("create got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("create got null dentry").as_mut(); - from_kernel_result! { - i_ops.create(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), excl).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("create got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("create got null dentry").as_mut(); + from_kernel_result! { + i_ops.create(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), excl).map(|()| 0) + } } } unsafe extern "C" fn lookup_callback( @@ -160,36 +166,42 @@ unsafe extern "C" fn lookup_callback( dentry: *mut bindings::dentry, flags: c_types::c_uint, ) -> *mut bindings::dentry { - let dir = dir.as_mut().expect("lookup got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("lookup got null dentry").as_mut(); - ret_err_ptr!(i_ops.lookup(dir, dentry, flags).map(|p| p as *mut _)) + unsafe { + let dir = dir.as_mut().expect("lookup got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("lookup got null dentry").as_mut(); + ret_err_ptr!(i_ops.lookup(dir, dentry, flags).map(|p| p as *mut _)) + } } unsafe extern "C" fn link_callback( old_dentry: *mut bindings::dentry, dir: *mut bindings::inode, dentry: *mut bindings::dentry, ) -> c_types::c_int { - let dir = dir.as_mut().expect("link got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let old_dentry = old_dentry - .as_mut() - .expect("link got null old_dentry") - .as_mut(); - let dentry = dentry.as_mut().expect("link got null dentry").as_mut(); - from_kernel_result! { - i_ops.link(old_dentry, dir, dentry).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("link got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let old_dentry = old_dentry + .as_mut() + .expect("link got null old_dentry") + .as_mut(); + let dentry = dentry.as_mut().expect("link got null dentry").as_mut(); + from_kernel_result! { + i_ops.link(old_dentry, dir, dentry).map(|()| 0) + } } } unsafe extern "C" fn unlink_callback( dir: *mut bindings::inode, dentry: *mut bindings::dentry, ) -> c_types::c_int { - let dir = dir.as_mut().expect("unlink got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("unlink got null dentry").as_mut(); - from_kernel_result! { - i_ops.unlink(dir, dentry).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("unlink got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("unlink got null dentry").as_mut(); + from_kernel_result! { + i_ops.unlink(dir, dentry).map(|()| 0) + } } } unsafe extern "C" fn symlink_callback( @@ -198,11 +210,13 @@ unsafe extern "C" fn symlink_callback( dentry: *mut bindings::dentry, symname: *const c_types::c_char, ) -> c_types::c_int { - let dir = dir.as_mut().expect("symlink got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("symlink got null dentry").as_mut(); - from_kernel_result! { - i_ops.symlink(&mut (*mnt_userns), dir, dentry, CStr::from_char_ptr(symname)).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("symlink got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("symlink got null dentry").as_mut(); + from_kernel_result! { + i_ops.symlink(&mut (*mnt_userns), dir, dentry, CStr::from_char_ptr(symname)).map(|()| 0) + } } } unsafe extern "C" fn mkdir_callback( @@ -211,22 +225,26 @@ unsafe extern "C" fn mkdir_callback( dentry: *mut bindings::dentry, mode: ModeInt, ) -> c_types::c_int { - let dir = dir.as_mut().expect("mkdir got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("mkdir got null dentry").as_mut(); - from_kernel_result! { - i_ops.mkdir(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode)).map(|()| 0) // todo: mode_t is u32 but u16 in Mode? + unsafe { + let dir = dir.as_mut().expect("mkdir got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("mkdir got null dentry").as_mut(); + from_kernel_result! { + i_ops.mkdir(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode)).map(|()| 0) // todo: mode_t is u32 but u16 in Mode? + } } } unsafe extern "C" fn rmdir_callback( dir: *mut bindings::inode, dentry: *mut bindings::dentry, ) -> c_types::c_int { - let dir = dir.as_mut().expect("rmdir got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("rmdir got null dentry").as_mut(); - from_kernel_result! { - i_ops.rmdir(dir, dentry).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("rmdir got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("rmdir got null dentry").as_mut(); + from_kernel_result! { + i_ops.rmdir(dir, dentry).map(|()| 0) + } } } unsafe extern "C" fn mknod_callback( @@ -236,11 +254,13 @@ unsafe extern "C" fn mknod_callback( mode: ModeInt, dev: bindings::dev_t, ) -> c_types::c_int { - let dir = dir.as_mut().expect("mknod got null dir").as_mut(); - let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("mknod got null dentry").as_mut(); - from_kernel_result! { - i_ops.mknod(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), dev).map(|()| 0) + unsafe { + let dir = dir.as_mut().expect("mknod got null dir").as_mut(); + let i_ops = &*(dir.i_private as *const T); + let dentry = dentry.as_mut().expect("mknod got null dentry").as_mut(); + from_kernel_result! { + i_ops.mknod(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), dev).map(|()| 0) + } } } unsafe extern "C" fn rename_callback( @@ -251,19 +271,21 @@ unsafe extern "C" fn rename_callback( new_dentry: *mut bindings::dentry, flags: c_types::c_uint, ) -> c_types::c_int { - let old_dir = old_dir.as_mut().expect("rename got null dir").as_mut(); - let i_ops = &*(old_dir.i_private as *const T); - let old_dentry = old_dentry - .as_mut() - .expect("rename got null dentry") - .as_mut(); - let new_dir = new_dir.as_mut().expect("rename got null dir").as_mut(); - let new_dentry = new_dentry - .as_mut() - .expect("rename got null dentry") - .as_mut(); - from_kernel_result! { - i_ops.rename(&mut (*mnt_userns), old_dir, old_dentry, new_dir, new_dentry, flags).map(|()| 0) + unsafe { + let old_dir = old_dir.as_mut().expect("rename got null dir").as_mut(); + let i_ops = &*(old_dir.i_private as *const T); + let old_dentry = old_dentry + .as_mut() + .expect("rename got null dentry") + .as_mut(); + let new_dir = new_dir.as_mut().expect("rename got null dir").as_mut(); + let new_dentry = new_dentry + .as_mut() + .expect("rename got null dentry") + .as_mut(); + from_kernel_result! { + i_ops.rename(&mut (*mnt_userns), old_dir, old_dentry, new_dir, new_dentry, flags).map(|()| 0) + } } } @@ -336,6 +358,8 @@ impl InodeOperationsVtable { atomic_open: None, tmpfile: None, set_acl: None, + fileattr_get: None, + fileattr_set: None, }; /// Builds an instance of [`struct inode_operations`]. diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index c9abeb7fe181cb..c4703c70244c89 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -199,11 +199,13 @@ unsafe extern "C" fn fill_super_callback( data: *mut c_void, silent: c_int, ) -> c_int { - let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); - let data = (data as *mut T::MountOptions).as_mut(); - T::fill_super(sb, data, silent) - .map(|_| 0) - .unwrap_or_else(|e| e.to_kernel_errno()) + unsafe { + let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); + let data = (data as *mut T::MountOptions).as_mut(); + T::fill_super(sb, data, silent) + .map(|_| 0) + .unwrap_or_else(|e| e.to_kernel_errno()) + } } pub fn kill_litter_super(sb: &mut SuperBlock) { diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs index bbb8661e1fd1c9..d3b0e949a02702 100644 --- a/rust/kernel/fs/super_operations.rs +++ b/rust/kernel/fs/super_operations.rs @@ -70,12 +70,14 @@ pub type Kstatfs = bindings::kstatfs; unsafe extern "C" fn drop_inode_callback( inode: *mut bindings::inode, ) -> c_types::c_int { - let sb = (*inode).i_sb as *const bindings::super_block; - let s_ops = &*((*sb).s_fs_info as *const T); - let inode = inode.as_mut().expect("drop_inode got null inode").as_mut(); - from_kernel_result! { - s_ops.drop_inode(inode)?; - Ok(0) + unsafe { + let sb = (*inode).i_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + let inode = inode.as_mut().expect("drop_inode got null inode").as_mut(); + from_kernel_result! { + s_ops.drop_inode(inode)?; + Ok(0) + } } } @@ -151,10 +153,12 @@ unsafe extern "C" fn statfs_callback( buf: *mut bindings::kstatfs, ) -> c_types::c_int { from_kernel_result! { - let sb = (*root).d_sb as *const bindings::super_block; - let s_ops = &*((*sb).s_fs_info as *const T); - s_ops.statfs(root.as_mut().expect("Statfs got null dentry").as_mut(), &mut *buf)?; - Ok(0) + unsafe { + let sb = (*root).d_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + s_ops.statfs(root.as_mut().expect("Statfs got null dentry").as_mut(), &mut *buf)?; + Ok(0) + } } } @@ -186,10 +190,12 @@ unsafe extern "C" fn show_options_callback( root: *mut bindings::dentry, ) -> c_types::c_int { from_kernel_result! { - let sb = (*root).d_sb as *const bindings::super_block; - let s_ops = &*((*sb).s_fs_info as *const T); - s_ops.show_options(&mut *s, root.as_mut().expect("show_options got null dentry").as_mut())?; - Ok(0) + unsafe { + let sb = (*root).d_sb as *const bindings::super_block; + let s_ops = &*((*sb).s_fs_info as *const T); + s_ops.show_options(&mut *s, root.as_mut().expect("show_options got null dentry").as_mut())?; + Ok(0) + } } } From 93db68accfa4766aab684fd6e526d36f25e11f32 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sat, 12 Jun 2021 18:55:31 +0200 Subject: [PATCH 41/58] Update README.md --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cff65b5e0fd827..8709a7f55af1cc 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ -# Rust for Linux +# Some Modules for Rust for Linux -The goal of this project is to add support for the Rust language to the Linux kernel. This repository contains the work that will be eventually submitted for review to the LKML. +This repository contains the [Rust-for-Linux/linux](https://github.com/Rust-for-Linux/linux) kernel with some additions. -Feel free to [contribute](https://github.com/Rust-for-Linux/linux/contribute)! To start, take a look at [`Documentation/rust`](https://github.com/Rust-for-Linux/linux/tree/rust/Documentation/rust). +- `fs/bs2ramfs` +- various additions to the kernel crate -General discussions, announcements, questions, etc. take place on the mailing list at rust-for-linux@vger.kernel.org ([subscribe](mailto:majordomo@vger.kernel.org?body=subscribe%20rust-for-linux), [instructions](http://vger.kernel.org/majordomo-info.html), [archive](https://lore.kernel.org/rust-for-linux/)). For chat, help, quick questions, informal discussion, etc. you may want to join our Zulip at https://rust-for-linux.zulipchat.com ([request an invitation](https://lore.kernel.org/rust-for-linux/CANiq72kW07hWjuc+dyvYH9NxyXoHsQLCtgvtR+8LT-VaoN1J_w@mail.gmail.com/T/)). +For the actual work on the kernel, please refer to [Rust-for-Linux/linux](https://github.com/Rust-for-Linux/linux) and the instructions there. -All contributors to this effort are understood to have agreed to the Linux kernel development process as explained in the different files under [`Documentation/process`](https://www.kernel.org/doc/html/latest/process/index.html). +# Contributors - +This project is part of the [Operating Systems 2 (german)](https://osm.hpi.de/bs2/2021/) lecture at HPI, Potsdam. Our working group consists of + +- [Benedikt Weber](https://github.com/bewee) +- [Niklas Mohrin](https://github.com/niklasmohrin) +- [Nils Lißner](https://github.com/TheGrayStone) +- [Tamino Bauknecht](https://github.com/taminob) From 24b27187560b2d33a743c95930c9bc276d2f9694 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Fri, 11 Jun 2021 21:36:58 +0200 Subject: [PATCH 42/58] kernel crate: Adds `ExpectK` trait --- rust/kernel/print.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 07cfbcb653a510..f23b04713d9a74 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -7,7 +7,7 @@ //! Reference: use core::cmp; -use core::fmt; +use core::fmt::{self, Debug}; use crate::bindings; use crate::c_types::{c_char, c_void}; @@ -410,3 +410,37 @@ macro_rules! pr_cont ( $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*) ) ); + +/// Extension trait for the `expect` method on `Option` and `Result` that prints an error message +/// with `printk` before panicking. +pub trait ExpectK { + fn expectk(self, msg: &str) -> T; +} + +impl ExpectK for Option { + fn expectk(self, msg: &str) -> T { + match self { + Some(val) => val, + None => { + pr_emerg!("Called expectk on a None value: {}", msg); + panic!(); + } + } + } +} + +impl ExpectK for Result { + fn expectk(self, msg: &str) -> T { + match self { + Ok(val) => val, + Err(err) => { + pr_emerg!( + "Called expectk on a Err value: {}\nThe value was {:?}", + msg, + err + ); + panic!(); + } + } + } +} From 820536f329d476f147fab259bf9bb2b92ee00654 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Fri, 11 Jun 2021 21:37:44 +0200 Subject: [PATCH 43/58] kernel crate: Use `expectk` instead of `expect` --- rust/kernel/fs.rs | 6 ++-- rust/kernel/fs/inode_operations.rs | 45 +++++++++++++++--------------- rust/kernel/fs/libfs_functions.rs | 3 +- rust/kernel/fs/super_operations.rs | 7 +++-- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 8f172c4f030944..7e7467ec9ffe51 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -9,8 +9,8 @@ pub mod super_operations; use core::ptr; use crate::{ - bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, ret_err_ptr, - str::CStr, Result, + bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, print::ExpectK, + ret_err_ptr, str::CStr, Result, }; pub type FileSystemType = bindings::file_system_type; @@ -98,7 +98,7 @@ pub unsafe extern "C" fn kill_superblock_callback( unsafe { let sb = sb .as_mut() - .expect("kill_superblock got NULL super block") + .expectk("kill_superblock got NULL super block") .as_mut(); T::kill_super(sb); } diff --git a/rust/kernel/fs/inode_operations.rs b/rust/kernel/fs/inode_operations.rs index c38244c43e5f2f..c74faa28991ea1 100644 --- a/rust/kernel/fs/inode_operations.rs +++ b/rust/kernel/fs/inode_operations.rs @@ -13,6 +13,7 @@ use crate::{ fs::{dentry::Dentry, inode::Inode}, str::CStr, types::{Dev, Iattr, Kstat, Mode, ModeInt, Path, UserNamespace}, + print::ExpectK, }; /// Corresponds to the kernel's `struct inode_operations`. @@ -119,7 +120,7 @@ unsafe extern "C" fn setattr_callback( iattr: *mut bindings::iattr, ) -> c_types::c_int { unsafe { - let dentry = dentry.as_mut().expect("setattr got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("setattr got null dentry").as_mut(); let inode = dentry.d_inode; // use d_inode method instead? let i_ops = &*((*inode).i_private as *const T); from_kernel_result! { @@ -153,9 +154,9 @@ unsafe extern "C" fn create_callback( excl: bool, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("create got null dir").as_mut(); + let dir = dir.as_mut().expectk("create got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("create got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("create got null dentry").as_mut(); from_kernel_result! { i_ops.create(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), excl).map(|()| 0) } @@ -167,9 +168,9 @@ unsafe extern "C" fn lookup_callback( flags: c_types::c_uint, ) -> *mut bindings::dentry { unsafe { - let dir = dir.as_mut().expect("lookup got null dir").as_mut(); + let dir = dir.as_mut().expectk("lookup got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("lookup got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("lookup got null dentry").as_mut(); ret_err_ptr!(i_ops.lookup(dir, dentry, flags).map(|p| p as *mut _)) } } @@ -179,13 +180,13 @@ unsafe extern "C" fn link_callback( dentry: *mut bindings::dentry, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("link got null dir").as_mut(); + let dir = dir.as_mut().expectk("link got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); let old_dentry = old_dentry .as_mut() - .expect("link got null old_dentry") + .expectk("link got null old_dentry") .as_mut(); - let dentry = dentry.as_mut().expect("link got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("link got null dentry").as_mut(); from_kernel_result! { i_ops.link(old_dentry, dir, dentry).map(|()| 0) } @@ -196,9 +197,9 @@ unsafe extern "C" fn unlink_callback( dentry: *mut bindings::dentry, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("unlink got null dir").as_mut(); + let dir = dir.as_mut().expectk("unlink got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("unlink got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("unlink got null dentry").as_mut(); from_kernel_result! { i_ops.unlink(dir, dentry).map(|()| 0) } @@ -211,9 +212,9 @@ unsafe extern "C" fn symlink_callback( symname: *const c_types::c_char, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("symlink got null dir").as_mut(); + let dir = dir.as_mut().expectk("symlink got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("symlink got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("symlink got null dentry").as_mut(); from_kernel_result! { i_ops.symlink(&mut (*mnt_userns), dir, dentry, CStr::from_char_ptr(symname)).map(|()| 0) } @@ -226,9 +227,9 @@ unsafe extern "C" fn mkdir_callback( mode: ModeInt, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("mkdir got null dir").as_mut(); + let dir = dir.as_mut().expectk("mkdir got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("mkdir got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("mkdir got null dentry").as_mut(); from_kernel_result! { i_ops.mkdir(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode)).map(|()| 0) // todo: mode_t is u32 but u16 in Mode? } @@ -239,9 +240,9 @@ unsafe extern "C" fn rmdir_callback( dentry: *mut bindings::dentry, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("rmdir got null dir").as_mut(); + let dir = dir.as_mut().expectk("rmdir got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("rmdir got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("rmdir got null dentry").as_mut(); from_kernel_result! { i_ops.rmdir(dir, dentry).map(|()| 0) } @@ -255,9 +256,9 @@ unsafe extern "C" fn mknod_callback( dev: bindings::dev_t, ) -> c_types::c_int { unsafe { - let dir = dir.as_mut().expect("mknod got null dir").as_mut(); + let dir = dir.as_mut().expectk("mknod got null dir").as_mut(); let i_ops = &*(dir.i_private as *const T); - let dentry = dentry.as_mut().expect("mknod got null dentry").as_mut(); + let dentry = dentry.as_mut().expectk("mknod got null dentry").as_mut(); from_kernel_result! { i_ops.mknod(&mut (*mnt_userns), dir, dentry, Mode::from_int(mode), dev).map(|()| 0) } @@ -272,16 +273,16 @@ unsafe extern "C" fn rename_callback( flags: c_types::c_uint, ) -> c_types::c_int { unsafe { - let old_dir = old_dir.as_mut().expect("rename got null dir").as_mut(); + let old_dir = old_dir.as_mut().expectk("rename got null dir").as_mut(); let i_ops = &*(old_dir.i_private as *const T); let old_dentry = old_dentry .as_mut() - .expect("rename got null dentry") + .expectk("rename got null dentry") .as_mut(); - let new_dir = new_dir.as_mut().expect("rename got null dir").as_mut(); + let new_dir = new_dir.as_mut().expectk("rename got null dir").as_mut(); let new_dentry = new_dentry .as_mut() - .expect("rename got null dentry") + .expectk("rename got null dentry") .as_mut(); from_kernel_result! { i_ops.rename(&mut (*mnt_userns), old_dir, old_dentry, new_dir, new_dentry, flags).map(|()| 0) diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index c4703c70244c89..a90c31e9f32077 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -11,6 +11,7 @@ use crate::{ super_operations::Kstatfs, DeclaredFileSystemType, FileSystemBase, }, iov_iter::IovIter, + print::ExpectK, str::CStr, types::{Iattr, Kstat, Path, UserNamespace}, Result, @@ -200,7 +201,7 @@ unsafe extern "C" fn fill_super_callback( silent: c_int, ) -> c_int { unsafe { - let sb = sb.as_mut().expect("SuperBlock was null").as_mut(); + let sb = sb.as_mut().expectk("SuperBlock was null").as_mut(); let data = (data as *mut T::MountOptions).as_mut(); T::fill_super(sb, data, silent) .map(|_| 0) diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs index d3b0e949a02702..d105d4bc58a4f7 100644 --- a/rust/kernel/fs/super_operations.rs +++ b/rust/kernel/fs/super_operations.rs @@ -12,6 +12,7 @@ use crate::{ from_kernel_result, fs::dentry::Dentry, fs::inode::Inode, + print::ExpectK, }; pub type SeqFile = bindings::seq_file; @@ -73,7 +74,7 @@ unsafe extern "C" fn drop_inode_callback( unsafe { let sb = (*inode).i_sb as *const bindings::super_block; let s_ops = &*((*sb).s_fs_info as *const T); - let inode = inode.as_mut().expect("drop_inode got null inode").as_mut(); + let inode = inode.as_mut().expectk("drop_inode got null inode").as_mut(); from_kernel_result! { s_ops.drop_inode(inode)?; Ok(0) @@ -156,7 +157,7 @@ unsafe extern "C" fn statfs_callback( unsafe { let sb = (*root).d_sb as *const bindings::super_block; let s_ops = &*((*sb).s_fs_info as *const T); - s_ops.statfs(root.as_mut().expect("Statfs got null dentry").as_mut(), &mut *buf)?; + s_ops.statfs(root.as_mut().expectk("Statfs got null dentry").as_mut(), &mut *buf)?; Ok(0) } } @@ -193,7 +194,7 @@ unsafe extern "C" fn show_options_callback( unsafe { let sb = (*root).d_sb as *const bindings::super_block; let s_ops = &*((*sb).s_fs_info as *const T); - s_ops.show_options(&mut *s, root.as_mut().expect("show_options got null dentry").as_mut())?; + s_ops.show_options(&mut *s, root.as_mut().expectk("show_options got null dentry").as_mut())?; Ok(0) } } From ecc51d48a861af841086aec0c75ac79c24e5d8ad Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sat, 12 Jun 2021 21:19:28 +0200 Subject: [PATCH 44/58] kernel crate: add ability to use predefined vtables from kernel This moves the shared behavior of the `build` method from the file operations vtable into its own trait, so that other types can also implement it. Namely, we added the unit struct `SimpleDirOperations` that returns a ref to the C global. This could be expanded, I can see a general `trait BuildVtable` and a macro like declare_c_vtable!( SimpleDirOperations, bindings::file_operations, bindings::simple_dir_operations, ); that expands to struct SimpleDirOperations; impl BuildVtable for SimpleDirOperations { fn build() -> &'static bindings::file_operations { &bindings::simple_dir_operations } } so that we can easily make these constants accessible. The downside is, that the interface for the caller is more abstract / complicated, since the vtable struct has to be constructed on the calling site .set_file_operations::>(); We could however aid with some helper methods .set_file_ops_from_trait::(); // ... fn set_file_ops_from_trait, A: FileOpenAdapter = NopFileOpenAdapter>() { ... } Implementing the `BuildVtable` trait for all implementors of `FileOperations` is not possible, because there might be multiple types `A` that satisfy the requirements, thus making a definite choice impossible. --- fs/bs2ramfs/bs2ramfs.rs | 26 ++++++++++------------- rust/kernel/chrdev.rs | 3 ++- rust/kernel/file_operations.rs | 31 +++++++++++++++++++++------- rust/kernel/fs.rs | 32 ++++++++++++++--------------- rust/kernel/fs/inode.rs | 33 ++++++++---------------------- rust/kernel/fs/inode_operations.rs | 20 ++++++++++-------- rust/kernel/fs/libfs_functions.rs | 11 ++++++++++ rust/kernel/miscdev.rs | 3 ++- 8 files changed, 85 insertions(+), 74 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 179afe45f9366f..815dd7300e9033 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -14,7 +14,7 @@ use kernel::{ inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, inode_operations::InodeOperations, kiocb::Kiocb, - libfs_functions, + libfs_functions::{self, PageSymlinkInodeOperations, SimpleDirOperations}, super_block::SuperBlock, super_operations::{Kstatfs, SeqFile, SuperOperations}, FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, @@ -77,14 +77,14 @@ impl FileSystemBase for BS2Ramfs { sb.s_magic = BS2RAMFS_MAGIC; let ops = Bs2RamfsSuperOps::default(); - unsafe { - // TODO: investigate if this really has to be set to NULL in case we run out of memory - sb.s_root = ptr::null_mut(); - sb.s_root = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0) - .and_then(Dentry::make_root) - .ok_or(Error::ENOMEM)? as *mut _ as *mut _; - } + + // TODO: investigate if this really has to be set to NULL in case we run out of memory + sb.s_root = ptr::null_mut(); + sb.s_root = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0) + .and_then(Dentry::make_root) + .ok_or(Error::ENOMEM)? as *mut _ as *mut _; pr_emerg!("(rust) s_root: {:?}", sb.s_root); + sb.set_super_operations(ops); sb.s_maxbytes = MAX_LFS_FILESIZE; sb.s_blocksize = kernel::PAGE_SIZE as _; @@ -376,11 +376,9 @@ pub fn ramfs_get_inode<'a>( inode.i_ino = Inode::next_ino() as _; inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); - unsafe { (*inode.i_mapping).a_ops = &RAMFS_AOPS }; unsafe { + (*inode.i_mapping).a_ops = &RAMFS_AOPS; rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); - } - unsafe { rust_helper_mapping_set_unevictable(inode.i_mapping); } @@ -392,13 +390,11 @@ pub fn ramfs_get_inode<'a>( } Mode::S_IFDIR => { inode.set_inode_operations(Bs2RamfsDirInodeOps); - unsafe { inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations }; // todo: write wrapper function - // inode.i_op = &RAMFS_DIR_INODE_OPS; - // inode.__bindgen_anon_3.i_fop = &bindings::simple_dir_operations; + inode.set_file_operations::(); inode.inc_nlink(); } Mode::S_IFLNK => { - unsafe { inode.i_op = &bindings::page_symlink_inode_operations }; + inode.set_inode_operations(PageSymlinkInodeOperations); inode.nohighmem(); } _ => { diff --git a/rust/kernel/chrdev.rs b/rust/kernel/chrdev.rs index 631405920c29c7..41b620f6b85cc4 100644 --- a/rust/kernel/chrdev.rs +++ b/rust/kernel/chrdev.rs @@ -17,6 +17,7 @@ use crate::bindings; use crate::c_types; use crate::error::{Error, Result}; use crate::file_operations; +use crate::fs::BuildVtable; use crate::str::CStr; /// Character device. @@ -168,7 +169,7 @@ impl Registration<{ N }> { // SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any // registration. - let fops = unsafe { file_operations::FileOperationsVtable::::build() }; + let fops = unsafe { file_operations::FileOperationsVtable::::build_vtable() }; let mut cdev = Cdev::alloc(fops, &this.this_module)?; cdev.add(inner.dev + inner.used as bindings::dev_t, 1)?; inner.cdevs[inner.used].replace(cdev); diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index e080d657d47e30..63a3e71ea750e8 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -14,7 +14,7 @@ use crate::{ error::{Error, Result}, file::{File, FileRef}, from_kernel_result, - fs::kiocb::Kiocb, + fs::{kiocb::Kiocb, BuildVtable}, io_buffer::{IoBufferReader, IoBufferWriter}, iov_iter::IovIter, sync::CondVar, @@ -400,13 +400,12 @@ impl> FileOperationsVtable { None }, }; +} - /// Builds an instance of [`struct file_operations`]. - /// - /// # Safety - /// - /// The caller must ensure that the adapter is compatible with the way the device is registered. - pub(crate) const unsafe fn build() -> &'static bindings::file_operations { +impl> BuildVtable + for FileOperationsVtable +{ + fn build_vtable() -> &'static bindings::file_operations { &Self::VTABLE } } @@ -587,6 +586,18 @@ pub trait FileOpenAdapter { -> *const Self::Arg; } +pub struct NopFileOpenAdapter; +impl FileOpenAdapter for NopFileOpenAdapter { + type Arg = (); + + unsafe fn convert( + _inode: *mut bindings::inode, + _file: *mut bindings::file, + ) -> *const Self::Arg { + &() + } +} + /// Trait for implementers of kernel files. /// /// In addition to the methods in [`FileOperations`], implementers must also provide @@ -606,6 +617,12 @@ impl> + Default> FileOpener<()> for T { } } +impl> BuildVtable for T { + fn build_vtable() -> &'static bindings::file_operations { + FileOperationsVtable::::build_vtable() + } +} + /// Corresponds to the kernel's `struct file_operations`. /// /// You implement this trait whenever you would create a `struct file_operations`. diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 7e7467ec9ffe51..78731a3bbaed00 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -13,6 +13,21 @@ use crate::{ ret_err_ptr, str::CStr, Result, }; +pub trait BuildVtable { + fn build_vtable() -> &'static T; +} +#[macro_export] +macro_rules! declare_c_vtable { + ($O:ident, $T:ty, $val:expr $(,)?) => { + pub struct $O; + impl $crate::fs::BuildVtable<$T> for $O { + fn build_vtable() -> &'static $T { + unsafe { &($val) } + } + } + }; +} + pub type FileSystemType = bindings::file_system_type; pub trait FileSystemBase { @@ -61,23 +76,6 @@ macro_rules! declare_fs_type { }; } -// Doesn't work because we need mutable access to an associated item -// pub struct FileSystemTypeVTable(PhantomData); -// impl FileSystemTypeVTable { -// const VTABLE: bindings::file_system_type = bindings::file_system_type { -// name: T::NAME.as_char_ptr() as *const _, -// fs_flags: T::FS_FLAGS, -// mount: Some(mount_callback::), -// kill_sb: Some(kill_superblock_callback::), -// owner: T::OWNER, -// ..DEFAULT_FS_TYPE -// }; - -// pub const fn build() -> &'static bindings::file_system_type { -// &Self::VTABLE -// } -// } - pub unsafe extern "C" fn mount_callback( fs_type: *mut bindings::file_system_type, flags: c_int, diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index ceee34328668d7..19e5d999f2ffa2 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -3,9 +3,8 @@ use core::ops::{Deref, DerefMut}; use core::{mem, ptr}; use crate::bindings; -use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; -use crate::fs::inode_operations::{InodeOperations, InodeOperationsVtable}; use crate::fs::super_block::SuperBlock; +use crate::fs::BuildVtable; use crate::types::{Dev, Mode}; #[derive(PartialEq, Eq)] @@ -96,31 +95,15 @@ impl Inode { } } - pub fn set_file_operations::Arg>>( - &mut self, - ) { - self.0.__bindgen_anon_3.i_fop = - unsafe { FileOperationsVtable::::build() }; - } - - pub fn set_inode_operations(&mut self, ops: OPS) { - self.0.i_op = unsafe { InodeOperationsVtable::::build() }; - self.0.i_private = Box::leak(Box::new(ops)) as *mut _ as *mut _; + pub fn set_file_operations>(&mut self) { + self.__bindgen_anon_3.i_fop = V::build_vtable(); } -} - -pub struct NopFileOpenAdapter; - -// don't really understand what this means, but we need someone to impl it and chrdev also returns -// (), so let's stick to this for now -impl FileOpenAdapter for NopFileOpenAdapter { - type Arg = (); - unsafe fn convert( - _inode: *mut bindings::inode, - _file: *mut bindings::file, - ) -> *const Self::Arg { - &() + pub fn set_inode_operations>(&mut self, ops: Ops) { + self.i_op = Ops::build_vtable(); + // TODO: Box::try_new + // => probably shouzldn't allocate in this method anyways, revisit signature + self.i_private = Box::into_raw(Box::new(ops)).cast(); } } diff --git a/rust/kernel/fs/inode_operations.rs b/rust/kernel/fs/inode_operations.rs index c74faa28991ea1..8e190462ac141a 100644 --- a/rust/kernel/fs/inode_operations.rs +++ b/rust/kernel/fs/inode_operations.rs @@ -10,10 +10,10 @@ use crate::{ bindings, c_types, error::{Error, Result}, from_kernel_result, - fs::{dentry::Dentry, inode::Inode}, + fs::{dentry::Dentry, inode::Inode, BuildVtable}, + print::ExpectK, str::CStr, types::{Dev, Iattr, Kstat, Mode, ModeInt, Path, UserNamespace}, - print::ExpectK, }; /// Corresponds to the kernel's `struct inode_operations`. @@ -114,6 +114,7 @@ pub trait InodeOperations: Send + Sync + Sized + Default { Err(Error::EINVAL) } } + unsafe extern "C" fn setattr_callback( mnt_userns: *mut bindings::user_namespace, dentry: *mut bindings::dentry, @@ -362,17 +363,20 @@ impl InodeOperationsVtable { fileattr_get: None, fileattr_set: None, }; +} - /// Builds an instance of [`struct inode_operations`]. - /// - /// # Safety - /// - /// The caller must ensure that the adapter is compatible with the way the device is registered. - pub(crate) const unsafe fn build() -> &'static bindings::inode_operations { +impl BuildVtable for InodeOperationsVtable { + fn build_vtable() -> &'static bindings::inode_operations { &Self::VTABLE } } +impl BuildVtable for T { + fn build_vtable() -> &'static bindings::inode_operations { + InodeOperationsVtable::::build_vtable() + } +} + /// Represents which fields of [`struct inode_block_operations`] should be populated with pointers. pub struct ToUse { /// The `lookup` field of [`struct inode_operations`]. diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index a90c31e9f32077..7518e8eb105e7d 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -214,3 +214,14 @@ pub fn kill_litter_super(sb: &mut SuperBlock) { bindings::kill_litter_super(sb.as_ptr_mut()); } } + +crate::declare_c_vtable!( + SimpleDirOperations, + bindings::file_operations, + bindings::simple_dir_operations, +); +crate::declare_c_vtable!( + PageSymlinkInodeOperations, + bindings::inode_operations, + bindings::page_symlink_inode_operations, +); diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs index e4d94d7416efce..2874d806a1073e 100644 --- a/rust/kernel/miscdev.rs +++ b/rust/kernel/miscdev.rs @@ -9,6 +9,7 @@ use crate::bindings; use crate::error::{Error, Result}; use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable}; +use crate::fs::BuildVtable; use crate::str::CStr; use alloc::boxed::Box; use core::marker::PhantomPinned; @@ -68,7 +69,7 @@ impl Registration { } // SAFETY: The adapter is compatible with `misc_register`. - this.mdev.fops = unsafe { FileOperationsVtable::::build() }; + this.mdev.fops = unsafe { FileOperationsVtable::::build_vtable() }; this.mdev.name = name.as_char_ptr(); this.mdev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32); From 656aacdc374193072890dbc95bb8a2ce079bcedf Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Wed, 16 Jun 2021 14:02:08 +0200 Subject: [PATCH 45/58] kernel crate: Add `AddressSpaceOperations` --- fs/bs2ramfs/bs2ramfs.rs | 56 +++++- rust/kernel/fs.rs | 27 +-- rust/kernel/fs/address_space_operations.rs | 217 +++++++++++++++++++++ rust/kernel/fs/inode.rs | 11 ++ rust/kernel/fs/libfs_functions.rs | 57 +++++- rust/kernel/types.rs | 2 + 6 files changed, 333 insertions(+), 37 deletions(-) create mode 100644 rust/kernel/fs/address_space_operations.rs diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 815dd7300e9033..f96528cfb3b63b 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -10,6 +10,7 @@ use kernel::{ file::File, file_operations::{FileOperations, SeekFrom}, fs::{ + address_space_operations::AddressSpaceOperations, dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, inode_operations::InodeOperations, @@ -17,12 +18,12 @@ use kernel::{ libfs_functions::{self, PageSymlinkInodeOperations, SimpleDirOperations}, super_block::SuperBlock, super_operations::{Kstatfs, SeqFile, SuperOperations}, - FileSystemBase, FileSystemType, DEFAULT_ADDRESS_SPACE_OPERATIONS, + FileSystemBase, FileSystemType, }, iov_iter::IovIter, prelude::*, str::CStr, - types::{Dev, Iattr, Kstat, Path, UserNamespace}, + types::{AddressSpace, Dev, Iattr, Kstat, Page, Path, UserNamespace}, Error, Mode, }; @@ -217,13 +218,46 @@ impl SuperOperations for Bs2RamfsSuperOps { } } -static RAMFS_AOPS: bindings::address_space_operations = bindings::address_space_operations { - readpage: Some(bindings::simple_readpage), - write_begin: Some(bindings::simple_write_begin), - write_end: Some(bindings::simple_write_end), - set_page_dirty: Some(bindings::__set_page_dirty_nobuffers), - ..DEFAULT_ADDRESS_SPACE_OPERATIONS -}; +#[derive(Default)] +struct Bs2RamfsAOps; + +impl AddressSpaceOperations for Bs2RamfsAOps { + kernel::declare_address_space_operations!(readpage, write_begin, write_end, set_page_dirty); + + fn readpage(&self, file: &File, page: &mut Page) -> Result { + libfs_functions::simple_readpage(file, page) + } + + fn write_begin( + &self, + file: Option<&File>, + mapping: &mut AddressSpace, + pos: bindings::loff_t, + len: u32, + flags: u32, + pagep: *mut *mut Page, + fsdata: *mut *mut c_void, + ) -> Result { + libfs_functions::simple_write_begin(file, mapping, pos, len, flags, pagep, fsdata) + } + + fn write_end( + &self, + file: Option<&File>, + mapping: &mut AddressSpace, + pos: bindings::loff_t, + len: u32, + copied: u32, + page: &mut Page, + fsdata: *mut c_void, + ) -> Result { + libfs_functions::simple_write_end(file, mapping, pos, len, copied, page, fsdata) + } + + fn set_page_dirty(&self, page: &mut Page) -> Result { + libfs_functions::__set_page_dirty_nobuffers(page) + } +} #[derive(Default)] struct Bs2RamfsFileInodeOps; @@ -376,8 +410,10 @@ pub fn ramfs_get_inode<'a>( inode.i_ino = Inode::next_ino() as _; inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); + inode.set_address_space_operations(Bs2RamfsAOps); + + // I think these should be functions on the AddressSpace, i.e. sth like inode.get_address_space().set_gfp_mask(...) unsafe { - (*inode.i_mapping).a_ops = &RAMFS_AOPS; rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); rust_helper_mapping_set_unevictable(inode.i_mapping); } diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 78731a3bbaed00..6e418e7d598684 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,3 +1,4 @@ +pub mod address_space_operations; pub mod dentry; pub mod inode; pub mod inode_operations; @@ -102,32 +103,6 @@ pub unsafe extern "C" fn kill_superblock_callback( } } -pub const DEFAULT_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations = - bindings::address_space_operations { - readpage: None, - readahead: None, - write_begin: None, - write_end: None, - set_page_dirty: None, - writepage: None, - writepages: None, - readpages: None, - bmap: None, - invalidatepage: None, - releasepage: None, - freepage: None, - direct_IO: None, - migratepage: None, - isolate_page: None, - putback_page: None, - launder_page: None, - is_partially_uptodate: None, - is_dirty_writeback: None, - error_remove_page: None, - swap_activate: None, - swap_deactivate: None, - }; - pub const DEFAULT_FS_TYPE: bindings::file_system_type = bindings::file_system_type { name: ptr::null(), fs_flags: 0, diff --git a/rust/kernel/fs/address_space_operations.rs b/rust/kernel/fs/address_space_operations.rs new file mode 100644 index 00000000000000..a42dc028bbd692 --- /dev/null +++ b/rust/kernel/fs/address_space_operations.rs @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! AddressSpace operations. +//! +//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h) + +use core::marker; + +use crate::{ + bindings, c_types, + error::{Error, Result}, + file::{File, FileRef}, + from_kernel_result, + fs::BuildVtable, + types::{AddressSpace, Page}, +}; + +/// Corresponds to the kernel's `struct adress_space_operations`. +/// +/// You implement this trait whenever you would create a `struct adress_space_operations`. +/// +/// File descriptors may be used from multiple threads/processes concurrently, so your type must be +/// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the +/// thread that decrements that associated file's refcount to zero. +pub trait AddressSpaceOperations: Send + Sync + Sized + Default { + /// The methods to use to populate [`struct adress_space_operations`]. + const TO_USE: ToUse; + + fn readpage(&self, _file: &File, _page: &mut Page) -> Result { + Err(Error::EINVAL) + } + + fn write_begin( + &self, + _file: Option<&File>, + _mapping: &mut AddressSpace, + _pos: bindings::loff_t, + _len: u32, + _flags: u32, + _pagep: *mut *mut Page, + _fsdata: *mut *mut c_types::c_void, + ) -> Result { + Err(Error::EINVAL) + } + + fn write_end( + &self, + _file: Option<&File>, + _mapping: &mut AddressSpace, + _pos: bindings::loff_t, + _len: u32, + _copied: u32, + _page: &mut Page, + _fsdata: *mut c_types::c_void, + ) -> Result { + Err(Error::EINVAL) + } + + fn set_page_dirty(&self, _page: &mut Page) -> Result { + Err(Error::EINVAL) + } +} + +unsafe extern "C" fn readpage_callback( + file: *mut bindings::file, + page: *mut bindings::page, +) -> c_types::c_int { + unsafe { + let address_space = (*file).f_mapping; + let a_ops = &*((*address_space).private_data as *const T); + from_kernel_result! { + a_ops.readpage(&FileRef::from_ptr(file), &mut (*page)).map(|()| 0) + } + } +} + +unsafe extern "C" fn write_begin_callback( + file: *mut bindings::file, + mapping: *mut bindings::address_space, + pos: bindings::loff_t, + len: c_types::c_uint, + flags: c_types::c_uint, + pagep: *mut *mut Page, + fsdata: *mut *mut c_types::c_void, +) -> c_types::c_int { + unsafe { + let a_ops = &*((*mapping).private_data as *const T); + let file = (!file.is_null()).then(|| FileRef::from_ptr(file)); + from_kernel_result! { + a_ops.write_begin(file.as_deref(), &mut (*mapping), pos, len, flags, pagep, fsdata).map(|()| 0) + } + } +} + +unsafe extern "C" fn write_end_callback( + file: *mut bindings::file, + mapping: *mut bindings::address_space, + pos: bindings::loff_t, + len: c_types::c_uint, + copied: c_types::c_uint, + page: *mut bindings::page, + fsdata: *mut c_types::c_void, +) -> c_types::c_int { + unsafe { + let a_ops = &*((*mapping).private_data as *const T); + let file = (!file.is_null()).then(|| FileRef::from_ptr(file)); + from_kernel_result! { + a_ops.write_end(file.as_deref(), &mut (*mapping), pos, len, copied, &mut (*page), fsdata).map(|x| x as i32) + } + } +} + +unsafe extern "C" fn set_page_dirty_callback( + page: *mut bindings::page, +) -> c_types::c_int { + unsafe { + let address_space = (*page).__bindgen_anon_1.__bindgen_anon_1.mapping; + let a_ops = &*((*address_space).private_data as *const T); + from_kernel_result! { + a_ops.set_page_dirty(&mut (*page)).map(|x| x as i32) + } + } +} + +pub(crate) struct AddressSpaceOperationsVtable(marker::PhantomData); + +impl AddressSpaceOperationsVtable { + const VTABLE: bindings::address_space_operations = bindings::address_space_operations { + readpage: if T::TO_USE.readpage { + Some(readpage_callback::) + } else { + None + }, + write_begin: if T::TO_USE.write_begin { + Some(write_begin_callback::) + } else { + None + }, + write_end: if T::TO_USE.write_end { + Some(write_end_callback::) + } else { + None + }, + set_page_dirty: if T::TO_USE.set_page_dirty { + Some(set_page_dirty_callback::) + } else { + None + }, + writepage: None, + writepages: None, + readpages: None, + readahead: None, + bmap: None, + invalidatepage: None, + releasepage: None, + freepage: None, + direct_IO: None, + migratepage: None, + isolate_page: None, + putback_page: None, + launder_page: None, + is_partially_uptodate: None, + is_dirty_writeback: None, + error_remove_page: None, + swap_activate: None, + swap_deactivate: None, + }; +} + +impl BuildVtable + for AddressSpaceOperationsVtable +{ + fn build_vtable() -> &'static bindings::address_space_operations { + &Self::VTABLE + } +} + +impl BuildVtable for T { + fn build_vtable() -> &'static bindings::address_space_operations { + AddressSpaceOperationsVtable::::build_vtable() + } +} + +/// Represents which fields of [`struct address_space_operation`] should be populated with pointers. +pub struct ToUse { + /// The `readpage` field of [`struct address_space_operation`]. + pub readpage: bool, + /// The `write_begin` field of [`struct address_space_operation`]. + pub write_begin: bool, + /// The `write_begin` field of [`struct address_space_operation`]. + pub write_end: bool, + /// The `set_page_dirty` field of [`struct address_space_operation`]. + pub set_page_dirty: bool, +} + +/// A constant version where all values are to set to `false`, that is, all supported fields will +/// be set to null pointers. +pub const USE_NONE: ToUse = ToUse { + readpage: false, + write_begin: false, + write_end: false, + set_page_dirty: false, +}; + +#[macro_export] +macro_rules! declare_address_space_operations { + () => { + const TO_USE: $crate::fs::address_space_operations::ToUse = $crate::fs::address_space_operations::USE_NONE; + }; + ($($i:ident),+) => { + const TO_USE: kernel::fs::address_space_operations::ToUse = + $crate::fs::address_space_operations::ToUse { + $($i: true),+ , + ..$crate::fs::address_space_operations::USE_NONE + }; + }; +} diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index 19e5d999f2ffa2..c06b84fce9a5ba 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -105,6 +105,17 @@ impl Inode { // => probably shouzldn't allocate in this method anyways, revisit signature self.i_private = Box::into_raw(Box::new(ops)).cast(); } + + // I think Inode should rather have a method get_address_space, and the AddressSpace should then provide set_address_space_operations + pub fn set_address_space_operations>( + &mut self, + ops: Ops, + ) { + unsafe { + (*self.i_mapping).a_ops = Ops::build_vtable(); + (*self.i_mapping).private_data = Box::into_raw(Box::new(ops)).cast(); + } + } } impl Deref for Inode { diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index 7518e8eb105e7d..caf0d7d518c205 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -13,7 +13,7 @@ use crate::{ iov_iter::IovIter, print::ExpectK, str::CStr, - types::{Iattr, Kstat, Path, UserNamespace}, + types::{AddressSpace, Iattr, Kstat, Page, Path, UserNamespace}, Result, }; @@ -215,6 +215,61 @@ pub fn kill_litter_super(sb: &mut SuperBlock) { } } +pub fn simple_readpage(file: &File, page: &mut Page) -> Result { + Error::parse_int(unsafe { bindings::simple_readpage(file.ptr, page as *mut _) }).map(|_| ()) +} + +pub fn simple_write_begin( + file: Option<&File>, + mapping: &mut AddressSpace, + pos: bindings::loff_t, + len: u32, + flags: u32, + pagep: *mut *mut Page, + fsdata: *mut *mut c_void, +) -> Result { + Error::parse_int(unsafe { + bindings::simple_write_begin( + file.map(|f| f.ptr).unwrap_or(ptr::null_mut()), + mapping as *mut _, + pos, + len, + flags, + pagep, + fsdata, + ) + }) + .map(|_| ()) +} + +pub fn simple_write_end( + file: Option<&File>, + mapping: &mut AddressSpace, + pos: bindings::loff_t, + len: u32, + copied: u32, + page: &mut Page, + fsdata: *mut c_void, +) -> Result { + Error::parse_int(unsafe { + bindings::simple_write_end( + file.map(|f| f.ptr).unwrap_or(ptr::null_mut()), + mapping as *mut _, + pos, + len, + copied, + page, + fsdata, + ) + }) + .map(|x| x as u32) +} + +pub fn __set_page_dirty_nobuffers(page: &mut Page) -> Result { + Error::parse_int(unsafe { bindings::__set_page_dirty_nobuffers(page as *mut _) }) + .map(|x| x != 0) +} + crate::declare_c_vtable!( SimpleDirOperations, bindings::file_operations, diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 92f512755400bc..47c20c759e992a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -21,6 +21,8 @@ pub type Iattr = bindings::iattr; pub type Path = bindings::path; pub type Kstat = bindings::kstat; pub type Dev = bindings::dev_t; +pub type Page = bindings::page; +pub type AddressSpace = bindings::address_space; /// Permissions. /// From 2d803fceab31195ff6fa8ad209b2fe0438f130cf Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Sat, 12 Jun 2021 19:22:57 +0200 Subject: [PATCH 46/58] kernel crate: Add `dbg` macro This macro mirrors the `std::dbg` macro. To view the output, you might have to set the log level to "info" using `dmesg -n 6`. --- rust/kernel/print.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index f23b04713d9a74..77a42f6897a04b 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -411,6 +411,33 @@ macro_rules! pr_cont ( ) ); +/// Equivalent to `std::dbg`, but uses `pr_info`. +#[macro_export] +macro_rules! dbg { + // Comment from original implementation: + // NOTE: We cannot use `concat!` to make a static string as a format argument + // of `eprintln!` because `file!` could contain a `{` or + // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` + // will be malformed. + () => { + $crate::pr_info!("[{}:{}]", core::file!(), core::line!()); + }; + ($val:expr $(,)?) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => { + $crate::pr_info!("[{}:{}] {} = {:#?}", + core::file!(), core::line!(), core::stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} + /// Extension trait for the `expect` method on `Option` and `Result` that prints an error message /// with `printk` before panicking. pub trait ExpectK { From 74bdb6f6486de0b04a78da44fda11ab9baaea3d3 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Thu, 1 Jul 2021 18:33:47 +0200 Subject: [PATCH 47/58] Remove requirement SuperOperations: Default that is not required and was just pasted from FileOperations --- rust/kernel/fs/super_operations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs index d105d4bc58a4f7..b4a6c5c8a35fcf 100644 --- a/rust/kernel/fs/super_operations.rs +++ b/rust/kernel/fs/super_operations.rs @@ -539,7 +539,7 @@ macro_rules! declare_super_operations { /// File descriptors may be used from multiple threads/processes concurrently, so your type must be /// [`Sync`]. It must also be [`Send`] because [`FileOperations::release`] will be called from the /// thread that decrements that associated file's refcount to zero. -pub trait SuperOperations: Send + Sync + Sized + Default { +pub trait SuperOperations: Send + Sync + Sized { /// The methods to use to populate [`struct super_operations`]. const TO_USE: ToUse; From 42b163f407a3e21f9e64250db59a0a4ef676f282 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 23 Jun 2021 23:32:51 +0200 Subject: [PATCH 48/58] bs2ramfs: remove nightly feature declaration --- fs/bs2ramfs/bs2ramfs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index f96528cfb3b63b..b62d44ad9abdfe 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -1,5 +1,4 @@ #![no_std] -#![feature(allocator_api, global_asm)] use alloc::boxed::Box; use core::{mem, ptr}; From 8f584b2ac06127bcfe133a354168e9cbae973136 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 12:55:21 +0200 Subject: [PATCH 49/58] Make set_suoer_operations return result --- fs/bs2ramfs/bs2ramfs.rs | 2 +- rust/kernel/fs/super_block.rs | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index b62d44ad9abdfe..0bb8fdfed1a2ab 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -85,7 +85,7 @@ impl FileSystemBase for BS2Ramfs { .ok_or(Error::ENOMEM)? as *mut _ as *mut _; pr_emerg!("(rust) s_root: {:?}", sb.s_root); - sb.set_super_operations(ops); + sb.set_super_operations(ops)?; sb.s_maxbytes = MAX_LFS_FILESIZE; sb.s_blocksize = kernel::PAGE_SIZE as _; sb.s_blocksize_bits = PAGE_SHIFT as _; diff --git a/rust/kernel/fs/super_block.rs b/rust/kernel/fs/super_block.rs index 526630e620f5b7..e4552cacf67fbd 100644 --- a/rust/kernel/fs/super_block.rs +++ b/rust/kernel/fs/super_block.rs @@ -1,9 +1,13 @@ use alloc::boxed::Box; -use core::mem; -use core::ops::{Deref, DerefMut}; +use core::{ + mem, + ops::{Deref, DerefMut}, +}; -use crate::bindings; -use crate::fs::super_operations::{SuperOperations, SuperOperationsVtable}; +use crate::{ + bindings, + fs::super_operations::{SuperOperations, SuperOperationsVtable}, +}; #[repr(transparent)] pub struct SuperBlock(bindings::super_block); @@ -13,9 +17,10 @@ impl SuperBlock { self.deref_mut() as *mut _ } - pub fn set_super_operations(&mut self, ops: OPS) { + pub fn set_super_operations(&mut self, ops: OPS) -> Result { self.s_op = unsafe { SuperOperationsVtable::::build() }; - self.s_fs_info = Box::leak(Box::new(ops)) as *mut _ as *mut _; + self.s_fs_info = Box::into_raw(Box::try_new(ops)?).cast(); + Ok(()) } } From 136ed20a0643a109a313e6af6f75b2bf877ff05f Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Wed, 30 Jun 2021 19:31:04 +0200 Subject: [PATCH 50/58] Include our fs/ files in rust-project.json --- scripts/generate_rust_analyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index 2a7b22be642bbe..4eaa5440bee841 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -98,7 +98,7 @@ def append_crate(display_name, root_module, is_workspace_member, deps, cfg): # Then, the rest outside of `rust/`. # # We explicitly mention the top-level folders we want to cover. - for folder in ("samples", "drivers"): + for folder in ("samples", "drivers", "fs"): for path in (srctree / folder).rglob("*.rs"): logging.info("Checking %s", path) name = path.name.replace(".rs", "") From 33a5b864062c5ca85440f73cf15b060276c2cea0 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 13:54:20 +0200 Subject: [PATCH 51/58] Add AddressSpace wrapper Partly abridged from the fat branch Co-authored-by: Tamino Bauknecht --- fs/bs2ramfs/bs2ramfs.rs | 11 +++-- rust/kernel/file.rs | 14 ++++++- rust/kernel/fs.rs | 1 + rust/kernel/fs/address_space.rs | 47 ++++++++++++++++++++++ rust/kernel/fs/address_space_operations.rs | 9 +++-- rust/kernel/fs/inode.rs | 39 +++++++++++------- rust/kernel/fs/kiocb.rs | 9 +++-- rust/kernel/fs/libfs_functions.rs | 11 ++--- rust/kernel/fs/super_block.rs | 1 + rust/kernel/types.rs | 1 - 10 files changed, 110 insertions(+), 33 deletions(-) create mode 100644 rust/kernel/fs/address_space.rs diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 0bb8fdfed1a2ab..535ce377a488a9 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -9,6 +9,7 @@ use kernel::{ file::File, file_operations::{FileOperations, SeekFrom}, fs::{ + address_space::AddressSpace, address_space_operations::AddressSpaceOperations, dentry::Dentry, inode::{Inode, UpdateATime, UpdateCTime, UpdateMTime}, @@ -21,8 +22,9 @@ use kernel::{ }, iov_iter::IovIter, prelude::*, + print::ExpectK, str::CStr, - types::{AddressSpace, Dev, Iattr, Kstat, Page, Path, UserNamespace}, + types::{Dev, Iattr, Kstat, Page, Path, UserNamespace}, Error, Mode, }; @@ -409,9 +411,12 @@ pub fn ramfs_get_inode<'a>( inode.i_ino = Inode::next_ino() as _; inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); - inode.set_address_space_operations(Bs2RamfsAOps); + inode + .mapping_mut() + .set_address_space_operations(Bs2RamfsAOps) + .expectk("Set address space operations"); - // I think these should be functions on the AddressSpace, i.e. sth like inode.get_address_space().set_gfp_mask(...) + // TODO: these should be functions on the AddressSpace unsafe { rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); rust_helper_mapping_set_unevictable(inode.i_mapping); diff --git a/rust/kernel/file.rs b/rust/kernel/file.rs index 262a856fc4910f..b8a815d6a88365 100644 --- a/rust/kernel/file.rs +++ b/rust/kernel/file.rs @@ -5,7 +5,7 @@ //! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and //! [`include/linux/file.h`](../../../../include/linux/file.h) -use crate::{bindings, error::Error, Result}; +use crate::{bindings, error::Error, fs::inode::Inode, print::ExpectK, Result}; use core::{mem::ManuallyDrop, ops::Deref}; /// Wraps the kernel's `struct file`. @@ -44,6 +44,18 @@ impl File { // SAFETY: `File::ptr` is guaranteed to be valid by the type invariants. unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 } } + + pub fn inode(&self) -> &mut Inode { + unsafe { + self.ptr + .as_mut() + .expectk("File::ptr was null") + .f_inode + .as_mut() + .expectk("File had NULL inode") + .as_mut() + } + } } impl Drop for File { diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 6e418e7d598684..783189a24f1e24 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -1,3 +1,4 @@ +pub mod address_space; pub mod address_space_operations; pub mod dentry; pub mod inode; diff --git a/rust/kernel/fs/address_space.rs b/rust/kernel/fs/address_space.rs new file mode 100644 index 00000000000000..aead60446ee7ce --- /dev/null +++ b/rust/kernel/fs/address_space.rs @@ -0,0 +1,47 @@ +use crate::{bindings, fs::BuildVtable, Result}; +use alloc::boxed::Box; +use core::{ + mem, + ops::{Deref, DerefMut}, +}; + +#[repr(transparent)] +pub struct AddressSpace(bindings::address_space); + +impl Deref for AddressSpace { + type Target = bindings::address_space; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AddressSpace { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl AsRef for bindings::address_space { + fn as_ref(&self) -> &AddressSpace { + unsafe { mem::transmute(self) } + } +} +impl AsMut for bindings::address_space { + fn as_mut(&mut self) -> &mut AddressSpace { + unsafe { mem::transmute(self) } + } +} + +impl AddressSpace { + pub fn as_ptr_mut(&mut self) -> *mut bindings::address_space { + self.deref_mut() as *mut _ + } + + pub fn set_address_space_operations>( + &mut self, + ops: Ops, + ) -> Result { + self.a_ops = Ops::build_vtable(); + self.private_data = Box::into_raw(Box::try_new(ops)?).cast(); + Ok(()) + } +} diff --git a/rust/kernel/fs/address_space_operations.rs b/rust/kernel/fs/address_space_operations.rs index a42dc028bbd692..e305a0de62b094 100644 --- a/rust/kernel/fs/address_space_operations.rs +++ b/rust/kernel/fs/address_space_operations.rs @@ -11,8 +11,9 @@ use crate::{ error::{Error, Result}, file::{File, FileRef}, from_kernel_result, - fs::BuildVtable, - types::{AddressSpace, Page}, + fs::{address_space::AddressSpace, BuildVtable}, + print::ExpectK, + types::Page, }; /// Corresponds to the kernel's `struct adress_space_operations`. @@ -87,7 +88,7 @@ unsafe extern "C" fn write_begin_callback( let a_ops = &*((*mapping).private_data as *const T); let file = (!file.is_null()).then(|| FileRef::from_ptr(file)); from_kernel_result! { - a_ops.write_begin(file.as_deref(), &mut (*mapping), pos, len, flags, pagep, fsdata).map(|()| 0) + a_ops.write_begin(file.as_deref(), mapping.as_mut().expectk("Got null mapping").as_mut(), pos, len, flags, pagep, fsdata).map(|()| 0) } } } @@ -105,7 +106,7 @@ unsafe extern "C" fn write_end_callback( let a_ops = &*((*mapping).private_data as *const T); let file = (!file.is_null()).then(|| FileRef::from_ptr(file)); from_kernel_result! { - a_ops.write_end(file.as_deref(), &mut (*mapping), pos, len, copied, &mut (*page), fsdata).map(|x| x as i32) + a_ops.write_end(file.as_deref(), mapping.as_mut().expectk("Got null mapping").as_mut(), pos, len, copied, &mut (*page), fsdata).map(|x| x as i32) } } } diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index c06b84fce9a5ba..0790c8aca574a8 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -2,10 +2,12 @@ use alloc::boxed::Box; use core::ops::{Deref, DerefMut}; use core::{mem, ptr}; -use crate::bindings; -use crate::fs::super_block::SuperBlock; -use crate::fs::BuildVtable; -use crate::types::{Dev, Mode}; +use crate::{ + bindings, + fs::{address_space::AddressSpace, super_block::SuperBlock, BuildVtable}, + print::ExpectK, + types::{Dev, Mode}, +}; #[derive(PartialEq, Eq)] pub enum UpdateATime { @@ -43,6 +45,24 @@ impl Inode { unsafe { bindings::get_next_ino() } // FIXME: why do the bindings not return c_int here? } + pub fn mapping(&mut self) -> &AddressSpace { + unsafe { + self.i_mapping + .as_mut() + .expectk("Inode had NULL mapping") + .as_mut() + } + } + + pub fn mapping_mut(&mut self) -> &mut AddressSpace { + unsafe { + self.i_mapping + .as_mut() + .expectk("Inode had NULL mapping") + .as_mut() + } + } + pub fn init_owner( &mut self, ns: &mut bindings::user_namespace, @@ -105,17 +125,6 @@ impl Inode { // => probably shouzldn't allocate in this method anyways, revisit signature self.i_private = Box::into_raw(Box::new(ops)).cast(); } - - // I think Inode should rather have a method get_address_space, and the AddressSpace should then provide set_address_space_operations - pub fn set_address_space_operations>( - &mut self, - ops: Ops, - ) { - unsafe { - (*self.i_mapping).a_ops = Ops::build_vtable(); - (*self.i_mapping).private_data = Box::into_raw(Box::new(ops)).cast(); - } - } } impl Deref for Inode { diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs index fb17ba46b295c4..2b38587505ba83 100644 --- a/rust/kernel/fs/kiocb.rs +++ b/rust/kernel/fs/kiocb.rs @@ -1,8 +1,9 @@ -use core::mem; -use core::ops::{Deref, DerefMut}; +use core::{ + mem, + ops::{Deref, DerefMut}, +}; -use crate::bindings; -use crate::file::File; +use crate::{bindings, file::File}; #[repr(transparent)] pub struct Kiocb(bindings::kiocb); diff --git a/rust/kernel/fs/libfs_functions.rs b/rust/kernel/fs/libfs_functions.rs index caf0d7d518c205..248844ef4c3e7d 100644 --- a/rust/kernel/fs/libfs_functions.rs +++ b/rust/kernel/fs/libfs_functions.rs @@ -7,13 +7,14 @@ use crate::{ file::File, file_operations::SeekFrom, fs::{ - dentry::Dentry, from_kernel_err_ptr, inode::Inode, kiocb::Kiocb, super_block::SuperBlock, - super_operations::Kstatfs, DeclaredFileSystemType, FileSystemBase, + address_space::AddressSpace, dentry::Dentry, from_kernel_err_ptr, inode::Inode, + kiocb::Kiocb, super_block::SuperBlock, super_operations::Kstatfs, DeclaredFileSystemType, + FileSystemBase, }, iov_iter::IovIter, print::ExpectK, str::CStr, - types::{AddressSpace, Iattr, Kstat, Page, Path, UserNamespace}, + types::{Iattr, Kstat, Page, Path, UserNamespace}, Result, }; @@ -231,7 +232,7 @@ pub fn simple_write_begin( Error::parse_int(unsafe { bindings::simple_write_begin( file.map(|f| f.ptr).unwrap_or(ptr::null_mut()), - mapping as *mut _, + mapping.as_ptr_mut(), pos, len, flags, @@ -254,7 +255,7 @@ pub fn simple_write_end( Error::parse_int(unsafe { bindings::simple_write_end( file.map(|f| f.ptr).unwrap_or(ptr::null_mut()), - mapping as *mut _, + mapping.as_ptr_mut(), pos, len, copied, diff --git a/rust/kernel/fs/super_block.rs b/rust/kernel/fs/super_block.rs index e4552cacf67fbd..e2ebbc7ba35700 100644 --- a/rust/kernel/fs/super_block.rs +++ b/rust/kernel/fs/super_block.rs @@ -7,6 +7,7 @@ use core::{ use crate::{ bindings, fs::super_operations::{SuperOperations, SuperOperationsVtable}, + Result, }; #[repr(transparent)] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 47c20c759e992a..a3022b6145d87d 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -22,7 +22,6 @@ pub type Path = bindings::path; pub type Kstat = bindings::kstat; pub type Dev = bindings::dev_t; pub type Page = bindings::page; -pub type AddressSpace = bindings::address_space; /// Permissions. /// From aa991ed8f35b7b067aee01617272d3e374c534d6 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 14:00:42 +0200 Subject: [PATCH 52/58] Remove get_unmapped_area implementation Recent C implementations of ramfs don't implement it either --- fs/bs2ramfs/bs2ramfs.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 535ce377a488a9..7d5be61d888f32 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -136,8 +136,7 @@ impl FileOperations for Bs2RamfsFileOps { fsync, splice_read, splice_write, - seek, - get_unmapped_area + seek ); fn read_iter(&self, iocb: &mut Kiocb, iter: &mut IovIter) -> Result { @@ -156,20 +155,6 @@ impl FileOperations for Bs2RamfsFileOps { libfs_functions::noop_fsync(file, start, end, datasync) } - fn get_unmapped_area( - &self, - _file: &File, - _addr: u64, - _len: u64, - _pgoff: u64, - _flags: u64, - ) -> Result { - pr_emerg!( - "AKAHSDkADKHAKHD WE ARE ABOUT TO PANIC (IN MMU_GET_UNMAPPED_AREA;;;; LOOK HERE COME ON" - ); - unimplemented!() - } - fn seek(&self, file: &File, pos: SeekFrom) -> Result { libfs_functions::generic_file_llseek(file, pos) } From fc6fcc8512f8c547ca12c22ffa2422a07f9a6edd Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 14:26:25 +0200 Subject: [PATCH 53/58] Add inode.super_block_mut and use it in bs2ramfs Co-authored-by: Niklas Mohrin --- fs/bs2ramfs/bs2ramfs.rs | 24 +++++++++--------------- rust/kernel/fs/inode.rs | 24 ++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 7d5be61d888f32..bf367f5387b8f4 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -313,7 +313,7 @@ impl InodeOperations for Bs2RamfsDirInodeOps { symname: &'static CStr, ) -> Result { let inode = ramfs_get_inode( - unsafe { dir.i_sb.as_mut().unwrap().as_mut() }, + dir.super_block_mut(), Some(dir), Mode::S_IFLNK | Mode::S_IRWXUGO, 0, @@ -358,20 +358,14 @@ impl InodeOperations for Bs2RamfsDirInodeOps { mode: Mode, dev: Dev, ) -> Result { - // todo: write some kind of wrapper - ramfs_get_inode( - unsafe { dir.i_sb.as_mut().unwrap().as_mut() }, - Some(dir), - mode, - dev, - ) - .ok_or(Error::ENOSPC) - .map(|inode| { - dentry.instantiate(inode); - dentry.get(); - dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); - () - }) + ramfs_get_inode(dir.super_block_mut(), Some(dir), mode, dev) + .ok_or(Error::ENOSPC) + .map(|inode| { + dentry.instantiate(inode); + dentry.get(); + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); + () + }) } fn rename( &self, diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index 0790c8aca574a8..d1baec2729c657 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -1,6 +1,8 @@ use alloc::boxed::Box; -use core::ops::{Deref, DerefMut}; -use core::{mem, ptr}; +use core::{ + ops::{Deref, DerefMut}, + {mem, ptr}, +}; use crate::{ bindings, @@ -45,6 +47,24 @@ impl Inode { unsafe { bindings::get_next_ino() } // FIXME: why do the bindings not return c_int here? } + pub fn super_block<'a, 'b>(&'a self) -> &'b SuperBlock { + unsafe { + self.i_sb + .as_mut() + .expectk("Inode had NULL super block") + .as_mut() + } + } + + pub fn super_block_mut<'a, 'b>(&'a mut self) -> &'b mut SuperBlock { + unsafe { + self.i_sb + .as_mut() + .expectk("Inode had NULL super block") + .as_mut() + } + } + pub fn mapping(&mut self) -> &AddressSpace { unsafe { self.i_mapping From fbf95a12aadf0022bafcad1832570b508e27a83a Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 22:56:52 +0200 Subject: [PATCH 54/58] Add FileSystemFlags abstraction and rename bs2ramfs_name I really tried to write a good FileSystemFlags abstraction. But that damn const static stuff... argh... So, I guess we have to live with this :/ --- fs/bs2ramfs/bs2ramfs.rs | 7 +++---- rust/kernel/fs.rs | 6 +++--- rust/kernel/types.rs | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index bf367f5387b8f4..75418659bf202a 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -24,7 +24,7 @@ use kernel::{ prelude::*, print::ExpectK, str::CStr, - types::{Dev, Iattr, Kstat, Page, Path, UserNamespace}, + types::{Dev, FileSystemFlags, FileSystemFlagsInt, Iattr, Kstat, Page, Path, UserNamespace}, Error, Mode, }; @@ -52,9 +52,8 @@ module! { struct BS2Ramfs; impl FileSystemBase for BS2Ramfs { - const NAME: &'static CStr = kernel::c_str!("bs2ramfs_name"); - const FS_FLAGS: c_int = bindings::FS_USERNS_MOUNT as _; - const OWNER: *mut bindings::module = ptr::null_mut(); + const NAME: &'static CStr = kernel::c_str!("bs2ramfs"); + const FS_FLAGS: FileSystemFlagsInt = FileSystemFlags::FS_USERNS_MOUNT; fn mount( _fs_type: &'_ mut FileSystemType, diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 783189a24f1e24..f27f4f6c484258 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -12,7 +12,7 @@ use core::ptr; use crate::{ bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, print::ExpectK, - ret_err_ptr, str::CStr, Result, + ret_err_ptr, str::CStr, types::FileSystemFlagsInt, Result, }; pub trait BuildVtable { @@ -36,8 +36,8 @@ pub trait FileSystemBase { type MountOptions = c_void; const NAME: &'static CStr; - const FS_FLAGS: c_int; - const OWNER: *mut bindings::module; + const FS_FLAGS: FileSystemFlagsInt; + const OWNER: *mut bindings::module = ptr::null_mut(); fn mount( fs_type: &'_ mut FileSystemType, diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index a3022b6145d87d..d9dba33a72ea71 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -23,6 +23,29 @@ pub type Kstat = bindings::kstat; pub type Dev = bindings::dev_t; pub type Page = bindings::page; +pub type FileSystemFlagsInt = c_types::c_int; + +pub struct FileSystemFlags; + +impl FileSystemFlags { + /// Not a virtual file system. An actual underlying block device is required. + pub const FS_REQUIRES_DEV: c_types::c_int = bindings::FS_REQUIRES_DEV as _; + /// Mount data is binary, and cannot be handled by the standard option parser + pub const FS_BINARY_MOUNTDATA: c_types::c_int = bindings::FS_BINARY_MOUNTDATA as _; + /// Has subtype + pub const FS_HAS_SUBTYPE: c_types::c_int = bindings::FS_HAS_SUBTYPE as _; + /// Can be mounted by userns root + pub const FS_USERNS_MOUNT: c_types::c_int = bindings::FS_USERNS_MOUNT as _; + /// Disable fanotify permission events + pub const FS_DISALLOW_NOTIFY_PERM: c_types::c_int = bindings::FS_DISALLOW_NOTIFY_PERM as _; + /// FS has been updated to handle vfs idmappings + pub const FS_ALLOW_IDMAP: c_types::c_int = bindings::FS_ALLOW_IDMAP as _; + /// Remove once all fs converted + pub const FS_THP_SUPPORT: c_types::c_int = bindings::FS_THP_SUPPORT as _; + /// FS will handle d_move() during rename() internally + pub const FS_RENAME_DOES_D_MOVE: c_types::c_int = bindings::FS_RENAME_DOES_D_MOVE as _; +} + /// Permissions. /// /// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h) From ae5e0ab71bfc5e20f899dfe674ae9b7a2d147eb9 Mon Sep 17 00:00:00 2001 From: Benedikt Weber Date: Thu, 8 Jul 2021 23:08:17 +0200 Subject: [PATCH 55/58] Remove emergency prints --- fs/bs2ramfs/bs2ramfs.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 75418659bf202a..19ab4bc70e9669 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -74,8 +74,6 @@ impl FileSystemBase for BS2Ramfs { _data: Option<&mut Self::MountOptions>, _silent: c_int, ) -> Result { - pr_emerg!("Reached ramfs_fill_super_impl"); - sb.s_magic = BS2RAMFS_MAGIC; let ops = Bs2RamfsSuperOps::default(); @@ -84,14 +82,12 @@ impl FileSystemBase for BS2Ramfs { sb.s_root = ramfs_get_inode(sb, None, Mode::S_IFDIR | ops.mount_opts.mode, 0) .and_then(Dentry::make_root) .ok_or(Error::ENOMEM)? as *mut _ as *mut _; - pr_emerg!("(rust) s_root: {:?}", sb.s_root); sb.set_super_operations(ops)?; sb.s_maxbytes = MAX_LFS_FILESIZE; sb.s_blocksize = kernel::PAGE_SIZE as _; sb.s_blocksize_bits = PAGE_SHIFT as _; sb.s_time_gran = 1; - pr_emerg!("SB members set"); Ok(()) } @@ -100,7 +96,7 @@ kernel::declare_fs_type!(BS2Ramfs, BS2RAMFS_FS_TYPE); impl KernelModule for BS2Ramfs { fn init() -> Result { - pr_emerg!("bs2 ramfs in action"); + pr_info!("bs2 ramfs in action"); libfs_functions::register_filesystem::().map(move |_| Self) } } @@ -198,7 +194,7 @@ impl SuperOperations for Bs2RamfsSuperOps { } fn show_options(&self, _s: &mut SeqFile, _root: &mut Dentry) -> Result { - pr_emerg!("ramfs show options, doing nothing"); + // TODO: Do something Ok(()) } } @@ -287,12 +283,10 @@ impl InodeOperations for Bs2RamfsDirInodeOps { mode: Mode, _excl: bool, ) -> Result { - pr_emerg!("enter create"); self.mknod(mnt_userns, dir, dentry, mode | Mode::S_IFREG, 0) } fn lookup(&self, dir: &mut Inode, dentry: &mut Dentry, flags: c_uint) -> Result<*mut Dentry> { - pr_emerg!("enter lookup"); libfs_functions::simple_lookup(dir, dentry, flags) // niklas: This returns 0, but it does so on main too, so it's not the problem } @@ -337,9 +331,7 @@ impl InodeOperations for Bs2RamfsDirInodeOps { dentry: &mut Dentry, mode: Mode, ) -> Result { - pr_emerg!("enter mkdir"); if let Err(_) = self.mknod(mnt_userns, dir, dentry, mode | Mode::S_IFDIR, 0) { - pr_emerg!("mkdir: inc_nlink"); dir.inc_nlink(); } Ok(()) From 385e58fe298ff9a1fea02fc2ebcbabfd789d61db Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Fri, 9 Jul 2021 14:01:31 +0200 Subject: [PATCH 56/58] Use impl_flag_methods for FileSystemFlags We already have a macro for flag types in ec615990a409358c6adde319f3790b53758daed4 We could also try to make this as one trait that gives you free impls of BitAnd and BitOr etc., and maybe add a derive(BitFlag) or so (we would need one method that returns self.0 on these types). We could then also have an associated type with the trait, so that we can also get rid of ModeInt. I don't know how much we loose on the "const" side of things with a trait though. --- fs/bs2ramfs/bs2ramfs.rs | 4 ++-- rust/kernel/fs.rs | 6 ++--- rust/kernel/fs/inode.rs | 3 ++- rust/kernel/types.rs | 53 +++++++++++++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 19ab4bc70e9669..9f11638627d3ad 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -24,7 +24,7 @@ use kernel::{ prelude::*, print::ExpectK, str::CStr, - types::{Dev, FileSystemFlags, FileSystemFlagsInt, Iattr, Kstat, Page, Path, UserNamespace}, + types::{Dev, FileSystemFlags, Iattr, Kstat, Page, Path, UserNamespace}, Error, Mode, }; @@ -53,7 +53,7 @@ struct BS2Ramfs; impl FileSystemBase for BS2Ramfs { const NAME: &'static CStr = kernel::c_str!("bs2ramfs"); - const FS_FLAGS: FileSystemFlagsInt = FileSystemFlags::FS_USERNS_MOUNT; + const FS_FLAGS: FileSystemFlags = FileSystemFlags::FS_USERNS_MOUNT; fn mount( _fs_type: &'_ mut FileSystemType, diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index f27f4f6c484258..e9d8dd550cae6d 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -12,7 +12,7 @@ use core::ptr; use crate::{ bindings, c_types::*, error::from_kernel_err_ptr, fs::super_block::SuperBlock, print::ExpectK, - ret_err_ptr, str::CStr, types::FileSystemFlagsInt, Result, + ret_err_ptr, str::CStr, types::FileSystemFlags, Result, }; pub trait BuildVtable { @@ -36,7 +36,7 @@ pub trait FileSystemBase { type MountOptions = c_void; const NAME: &'static CStr; - const FS_FLAGS: FileSystemFlagsInt; + const FS_FLAGS: FileSystemFlags; const OWNER: *mut bindings::module = ptr::null_mut(); fn mount( @@ -64,7 +64,7 @@ macro_rules! declare_fs_type { ($T:ty, $S:ident) => { static mut $S: $crate::bindings::file_system_type = $crate::bindings::file_system_type { name: <$T as $crate::fs::FileSystemBase>::NAME.as_char_ptr() as *const _, - fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS, + fs_flags: <$T as $crate::fs::FileSystemBase>::FS_FLAGS.into_int(), owner: <$T as $crate::fs::FileSystemBase>::OWNER, mount: Some($crate::fs::mount_callback::<$T>), kill_sb: Some($crate::fs::kill_superblock_callback::<$T>), diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs index d1baec2729c657..3198c133b63d2b 100644 --- a/rust/kernel/fs/inode.rs +++ b/rust/kernel/fs/inode.rs @@ -1,7 +1,8 @@ use alloc::boxed::Box; use core::{ + mem, ops::{Deref, DerefMut}, - {mem, ptr}, + ptr, }; use crate::{ diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index d9dba33a72ea71..c7d0e6b1f82909 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -23,29 +23,62 @@ pub type Kstat = bindings::kstat; pub type Dev = bindings::dev_t; pub type Page = bindings::page; -pub type FileSystemFlagsInt = c_types::c_int; +macro_rules! impl_flag_methods { + ($T:ty, $V:ty) => { + impl $T { + pub const fn from_int(val: $V) -> Self { + Self(val) + } + pub const fn into_int(self) -> $V { + self.0 + } + pub const fn is_empty(self) -> bool { + self.0 == 0 + } + pub const fn has(self, other: Self) -> bool { + self.0 & other.0 != 0 + } + pub const fn with(self, other: Self) -> Self { + Self(self.0 | other.0) + } + pub const fn without(self, other: Self) -> Self { + Self(self.0 & !other.0) + } + } + }; +} -pub struct FileSystemFlags; +pub struct FileSystemFlags(c_types::c_int); +#[rustfmt::skip] impl FileSystemFlags { /// Not a virtual file system. An actual underlying block device is required. - pub const FS_REQUIRES_DEV: c_types::c_int = bindings::FS_REQUIRES_DEV as _; + pub const FS_REQUIRES_DEV: Self = Self::from_int(bindings::FS_REQUIRES_DEV as _); + /// Mount data is binary, and cannot be handled by the standard option parser - pub const FS_BINARY_MOUNTDATA: c_types::c_int = bindings::FS_BINARY_MOUNTDATA as _; + pub const FS_BINARY_MOUNTDATA: Self = Self::from_int(bindings::FS_BINARY_MOUNTDATA as _); + /// Has subtype - pub const FS_HAS_SUBTYPE: c_types::c_int = bindings::FS_HAS_SUBTYPE as _; + pub const FS_HAS_SUBTYPE: Self = Self::from_int(bindings::FS_HAS_SUBTYPE as _); + /// Can be mounted by userns root - pub const FS_USERNS_MOUNT: c_types::c_int = bindings::FS_USERNS_MOUNT as _; + pub const FS_USERNS_MOUNT: Self = Self::from_int(bindings::FS_USERNS_MOUNT as _); + /// Disable fanotify permission events - pub const FS_DISALLOW_NOTIFY_PERM: c_types::c_int = bindings::FS_DISALLOW_NOTIFY_PERM as _; + pub const FS_DISALLOW_NOTIFY_PERM: Self = Self::from_int(bindings::FS_DISALLOW_NOTIFY_PERM as _); + /// FS has been updated to handle vfs idmappings - pub const FS_ALLOW_IDMAP: c_types::c_int = bindings::FS_ALLOW_IDMAP as _; + pub const FS_ALLOW_IDMAP: Self = Self::from_int(bindings::FS_ALLOW_IDMAP as _); + /// Remove once all fs converted - pub const FS_THP_SUPPORT: c_types::c_int = bindings::FS_THP_SUPPORT as _; + pub const FS_THP_SUPPORT: Self = Self::from_int(bindings::FS_THP_SUPPORT as _); + /// FS will handle d_move() during rename() internally - pub const FS_RENAME_DOES_D_MOVE: c_types::c_int = bindings::FS_RENAME_DOES_D_MOVE as _; + pub const FS_RENAME_DOES_D_MOVE: Self = Self::from_int(bindings::FS_RENAME_DOES_D_MOVE as _); } +impl_flag_methods!(FileSystemFlags, c_types::c_int); + /// Permissions. /// /// C header: [`include/uapi/linux/stat.h`](../../../../include/uapi/linux/stat.h) From d87c6fd7d81843b2258373b3fda1a983ba237e42 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Fri, 9 Jul 2021 14:51:46 +0200 Subject: [PATCH 57/58] clippy things I found --- b | 2 +- fs/bs2ramfs/bs2ramfs.rs | 93 +++++++++++----------- rust/kernel/error.rs | 1 + rust/kernel/file_operations.rs | 1 + rust/kernel/fs/address_space_operations.rs | 1 + rust/kernel/fs/inode_operations.rs | 1 + rust/kernel/fs/super_operations.rs | 1 + rust/kernel/lib.rs | 6 +- rust/kernel/types.rs | 2 +- scp_all | 6 +- 10 files changed, 61 insertions(+), 53 deletions(-) diff --git a/b b/b index ba1f72a374a103..2f49be46bbb24c 100755 --- a/b +++ b/b @@ -5,4 +5,4 @@ REPO_DIR=$(dirname $0) MOD_DIR=$(realpath $REPO_DIR/_mod_inst) BUILD_DIR=$(realpath $REPO_DIR/bs2build/) -RUSTUP_TOOLCHAIN="nightly-2021-05-29" make O="$BUILD_DIR" CC=clang LLVM=1 ARCH=x86_64 INSTALL_MOD_PATH="$MOD_DIR" $@ +RUSTUP_TOOLCHAIN="nightly-2021-05-29" make LLVM=1 ARCH=x86_64 INSTALL_MOD_PATH="$MOD_DIR" CLIPPY=1 $@ diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 9f11638627d3ad..41add2586c154d 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -1,4 +1,6 @@ #![no_std] +#![deny(clippy::all)] +#![warn(clippy::pedantic)] use alloc::boxed::Box; use core::{mem, ptr}; @@ -30,7 +32,7 @@ use kernel::{ const PAGE_SHIFT: u32 = 12; // x86 (maybe) const MAX_LFS_FILESIZE: c_longlong = c_longlong::MAX; -const BS2RAMFS_MAGIC: u64 = 0x858458f6; // ~~one less than~~ ramfs, should not clash with anything (maybe) +const BS2RAMFS_MAGIC: u64 = 0x858458f6; extern "C" { fn rust_helper_mapping_set_unevictable(mapping: *mut bindings::address_space); @@ -287,7 +289,7 @@ impl InodeOperations for Bs2RamfsDirInodeOps { } fn lookup(&self, dir: &mut Inode, dentry: &mut Dentry, flags: c_uint) -> Result<*mut Dentry> { - libfs_functions::simple_lookup(dir, dentry, flags) // niklas: This returns 0, but it does so on main too, so it's not the problem + libfs_functions::simple_lookup(dir, dentry, flags) } fn link(&self, old_dentry: &mut Dentry, dir: &mut Inode, dentry: &mut Dentry) -> Result { @@ -331,7 +333,10 @@ impl InodeOperations for Bs2RamfsDirInodeOps { dentry: &mut Dentry, mode: Mode, ) -> Result { - if let Err(_) = self.mknod(mnt_userns, dir, dentry, mode | Mode::S_IFDIR, 0) { + if self + .mknod(mnt_userns, dir, dentry, mode | Mode::S_IFDIR, 0) + .is_err() + { dir.inc_nlink(); } Ok(()) @@ -349,15 +354,14 @@ impl InodeOperations for Bs2RamfsDirInodeOps { mode: Mode, dev: Dev, ) -> Result { - ramfs_get_inode(dir.super_block_mut(), Some(dir), mode, dev) - .ok_or(Error::ENOSPC) - .map(|inode| { - dentry.instantiate(inode); - dentry.get(); - dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); - () - }) + let inode = + ramfs_get_inode(dir.super_block_mut(), Some(dir), mode, dev).ok_or(Error::ENOSPC)?; + dentry.instantiate(inode); + dentry.get(); + dir.update_acm_time(UpdateATime::No, UpdateCTime::Yes, UpdateMTime::Yes); + Ok(()) } + fn rename( &self, mnt_userns: &mut UserNamespace, @@ -377,41 +381,40 @@ pub fn ramfs_get_inode<'a>( mode: Mode, dev: bindings::dev_t, ) -> Option<&'a mut Inode> { - Inode::new(sb).map(|inode| { - inode.i_ino = Inode::next_ino() as _; - inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); - - inode - .mapping_mut() - .set_address_space_operations(Bs2RamfsAOps) - .expectk("Set address space operations"); - - // TODO: these should be functions on the AddressSpace - unsafe { - rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); - rust_helper_mapping_set_unevictable(inode.i_mapping); - } + let inode = Inode::new(sb)?; + inode.i_ino = Inode::next_ino() as _; + inode.init_owner(unsafe { &mut bindings::init_user_ns }, dir, mode); + + inode + .mapping_mut() + .set_address_space_operations(Bs2RamfsAOps) + .expectk("Set address space operations"); + + // TODO: these should be functions on the AddressSpace + unsafe { + rust_helper_mapping_set_gfp_mask(inode.i_mapping, RUST_HELPER_GFP_HIGHUSER); + rust_helper_mapping_set_unevictable(inode.i_mapping); + } - inode.update_acm_time(UpdateATime::Yes, UpdateCTime::Yes, UpdateMTime::Yes); - match mode & Mode::S_IFMT { - Mode::S_IFREG => { - inode.set_inode_operations(Bs2RamfsFileInodeOps); - inode.set_file_operations::(); - } - Mode::S_IFDIR => { - inode.set_inode_operations(Bs2RamfsDirInodeOps); - inode.set_file_operations::(); - inode.inc_nlink(); - } - Mode::S_IFLNK => { - inode.set_inode_operations(PageSymlinkInodeOperations); - inode.nohighmem(); - } - _ => { - inode.init_special(mode, dev); - } + inode.update_acm_time(UpdateATime::Yes, UpdateCTime::Yes, UpdateMTime::Yes); + match mode & Mode::S_IFMT { + Mode::S_IFREG => { + inode.set_inode_operations(Bs2RamfsFileInodeOps); + inode.set_file_operations::(); + } + Mode::S_IFDIR => { + inode.set_inode_operations(Bs2RamfsDirInodeOps); + inode.set_file_operations::(); + inode.inc_nlink(); + } + Mode::S_IFLNK => { + inode.set_inode_operations(PageSymlinkInodeOperations); + inode.nohighmem(); } + _ => { + inode.init_special(mode, dev); + } + } - inode - }) + Some(inode) } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 8caf60a5e3c027..fb2f79a37f0d1e 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -335,6 +335,7 @@ where #[macro_export] macro_rules! from_kernel_result { ($($tt:tt)*) => {{ + #[allow(clippy::redundant_closure_call)] $crate::error::from_kernel_result_helper((|| { $($tt)* })()) diff --git a/rust/kernel/file_operations.rs b/rust/kernel/file_operations.rs index 63a3e71ea750e8..2571dd8b0caf01 100644 --- a/rust/kernel/file_operations.rs +++ b/rust/kernel/file_operations.rs @@ -477,6 +477,7 @@ macro_rules! declare_file_operations { const TO_USE: $crate::file_operations::ToUse = $crate::file_operations::USE_NONE; }; ($($i:ident),+) => { + #[allow(clippy::needless_update)] const TO_USE: kernel::file_operations::ToUse = $crate::file_operations::ToUse { $($i: true),+ , diff --git a/rust/kernel/fs/address_space_operations.rs b/rust/kernel/fs/address_space_operations.rs index e305a0de62b094..79809e136c6d39 100644 --- a/rust/kernel/fs/address_space_operations.rs +++ b/rust/kernel/fs/address_space_operations.rs @@ -209,6 +209,7 @@ macro_rules! declare_address_space_operations { const TO_USE: $crate::fs::address_space_operations::ToUse = $crate::fs::address_space_operations::USE_NONE; }; ($($i:ident),+) => { + #[allow(clippy::needless_update)] const TO_USE: kernel::fs::address_space_operations::ToUse = $crate::fs::address_space_operations::ToUse { $($i: true),+ , diff --git a/rust/kernel/fs/inode_operations.rs b/rust/kernel/fs/inode_operations.rs index 8e190462ac141a..8217da23ffd1c4 100644 --- a/rust/kernel/fs/inode_operations.rs +++ b/rust/kernel/fs/inode_operations.rs @@ -475,6 +475,7 @@ macro_rules! declare_inode_operations { const TO_USE: $crate::fs::inode_operations::ToUse = $crate::fs::inode_operations::USE_NONE; }; ($($i:ident),+) => { + #[allow(clippy::needless_update)] const TO_USE: kernel::fs::inode_operations::ToUse = $crate::fs::inode_operations::ToUse { $($i: true),+ , diff --git a/rust/kernel/fs/super_operations.rs b/rust/kernel/fs/super_operations.rs index b4a6c5c8a35fcf..802de0b3bca9da 100644 --- a/rust/kernel/fs/super_operations.rs +++ b/rust/kernel/fs/super_operations.rs @@ -524,6 +524,7 @@ macro_rules! declare_super_operations { const TO_USE: $crate::fs::super_operations::ToUse = $crate::fs::super_operations::USE_NONE; }; ($($i:ident),+) => { + #[allow(clippy::needless_update)] const TO_USE: kernel::fs::super_operations::ToUse = $crate::fs::super_operations::ToUse { $($i: true),+ , diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 2813bd2793193d..7c68b8d7846604 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -23,10 +23,10 @@ const_unreachable_unchecked, try_reserve )] -#![deny(clippy::complexity)] -#![deny(clippy::correctness)] +#![warn(clippy::complexity)] +#![warn(clippy::correctness)] #![deny(clippy::perf)] -#![deny(clippy::style)] +#![warn(clippy::style)] #![deny(rust_2018_idioms)] // Ensure conditional compilation based on the kernel configuration works; diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index c7d0e6b1f82909..942041180367f5 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -32,7 +32,7 @@ macro_rules! impl_flag_methods { pub const fn into_int(self) -> $V { self.0 } - pub const fn is_empty(self) -> bool { + pub const fn is_empty(&self) -> bool { self.0 == 0 } pub const fn has(self, other: Self) -> bool { diff --git a/scp_all b/scp_all index 2f30b646446f00..126cfc458e173e 100755 --- a/scp_all +++ b/scp_all @@ -8,6 +8,6 @@ REPO_DIR=`dirname $0` $REPO_DIR/b -j12 $REPO_DIR/b modules_install rm $REPO_DIR/_mod_inst/lib/modules/*/{build,source} -scp -P 2222 $REPO_DIR/bs2build/arch/x86_64/boot/bzImage root@127.0.0.1:/boot/vmlinuz-rust -scp -r -P 2222 $REPO_DIR/_mod_inst/lib/* root@127.0.0.1:/lib/ -# ssh -p 2222 root@127.0.0.1 "systemctl reboot --boot-loader-entry=linux-rust.conf" +scp -P 2222 $REPO_DIR/arch/x86_64/boot/bzImage root@127.0.0.1:/boot/vmlinuz-rust +scp -r -P 2222 $REPO_DIR/_mod_inst/lib/* root@127.0.0.1:/lib/ +echo "reboot" | ssh -p 2222 root@127.0.0.1 From d5c94d35fe90afd0bb760cfc38cb92de0b1e9974 Mon Sep 17 00:00:00 2001 From: Niklas Mohrin Date: Tue, 13 Jul 2021 12:57:54 +0200 Subject: [PATCH 58/58] fix build as builtin --- fs/bs2ramfs/bs2ramfs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/bs2ramfs/bs2ramfs.rs b/fs/bs2ramfs/bs2ramfs.rs index 41add2586c154d..4b511103d18619 100644 --- a/fs/bs2ramfs/bs2ramfs.rs +++ b/fs/bs2ramfs/bs2ramfs.rs @@ -1,4 +1,5 @@ #![no_std] +#![feature(global_asm)] #![deny(clippy::all)] #![warn(clippy::pedantic)]