erofs: introduce xattrs replacement to C

This patch introduces erofs_getxattr_rust and erofs_listxattr_rust to C
and can replace the original xattr logic entirely.

Note that the original acl implementation is tweaked with a lifted
function called erofs_getxattr_nobuf, so that difference of the calling
convention of Rust side code can be bridged.

Signed-off-by: Yiyang Wu <[email protected]>
This commit is contained in:
Yiyang Wu committed 2024-10-29 19:01:20 +08:00
1 parent d454d6670d
commit dc6a838bb9
5 files changed
+148 -7

No files matched your search

+3
View File
@@ -10,3 +10,6 @@ erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o
erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o dir_rs.o data_rs.o rust_helpers.o
ifeq ($(CONFIG_EROFS_FS_XATTR),y)
erofs-$(CONFIG_EROFS_FS_RUST) += xattr_rs.o
endif
+8
View File
@@ -28,4 +28,12 @@ extern int erofs_readdir_rust(struct file *file, struct dir_context *ctx);
struct erofs_map_blocks;
extern int erofs_map_blocks_rust(struct inode *inode,
struct erofs_map_blocks *map);
extern int erofs_getxattr_rust(struct inode *inode, unsigned int flags,
const char *name, void *buffer, size_t size);
extern ssize_t erofs_listxattr_rust(struct dentry *dentry, char *buffer,
size_t buffer_size);
#ifdef CONFIG_EROFS_FS_POSIX_ACL
extern int erofs_getxattr_nobuf_rust(struct inode *inode, int prefix,
const char *name, char **value);
#endif
#endif
+24 -7
View File
@@ -8,6 +8,7 @@
#include <linux/xxhash.h>
#include "xattr.h"
#ifndef CONFIG_EROFS_FS_RUST
struct erofs_xattr_iter {
struct super_block *sb;
struct erofs_buf buf;
@@ -122,6 +123,7 @@ out_unlock:
clear_and_wake_up_bit(EROFS_I_BL_XATTR_BIT, &vi->flags);
return ret;
}
#endif
static bool erofs_xattr_user_list(struct dentry *dentry)
{
@@ -175,6 +177,7 @@ const struct xattr_handler * const erofs_xattr_handlers[] = {
NULL,
};
#ifndef CONFIG_EROFS_FS_RUST
static int erofs_xattr_copy_to_buffer(struct erofs_xattr_iter *it,
unsigned int len)
{
@@ -509,8 +512,28 @@ int erofs_xattr_prefixes_init(struct super_block *sb)
erofs_xattr_prefixes_cleanup(sb);
return ret;
}
#endif
#ifdef CONFIG_EROFS_FS_POSIX_ACL
#ifndef CONFIG_EROFS_FS_RUST
static int erofs_getxattr_nobuf(struct inode *inode, int prefix,
const char *name, char **value)
{
int rc;
char *buf = NULL;
rc = erofs_getxattr(inode, prefix, name, NULL, 0);
if (rc > 0) {
buf = kmalloc(rc, GFP_KERNEL);
if (!value)
return ENOMEM;
rc = erofs_getxattr(inode, prefix, name, buf, rc);
}
*value = buf;
return rc;
}
#else
#define erofs_getxattr_nobuf erofs_getxattr_nobuf_rust
#endif
struct posix_acl *erofs_get_acl(struct inode *inode, int type, bool rcu)
{
struct posix_acl *acl;
@@ -531,13 +554,7 @@ struct posix_acl *erofs_get_acl(struct inode *inode, int type, bool rcu)
return ERR_PTR(-EINVAL);
}
rc = erofs_getxattr(inode, prefix, "", NULL, 0);
if (rc > 0) {
value = kmalloc(rc, GFP_KERNEL);
if (!value)
return ERR_PTR(-ENOMEM);
rc = erofs_getxattr(inode, prefix, "", value, rc);
}
rc = erofs_getxattr_nobuf(inode, prefix, "", &value);
if (rc == -ENOATTR)
acl = NULL;
+7
View File
@@ -46,10 +46,17 @@ static inline const char *erofs_xattr_prefix(unsigned int idx,
extern const struct xattr_handler * const erofs_xattr_handlers[];
#ifdef CONFIG_EROFS_FS_RUST
#define erofs_getxattr erofs_getxattr_rust
#define erofs_listxattr erofs_listxattr_rust
static inline int erofs_xattr_prefixes_init(struct super_block *sb) { return 0; }
static inline void erofs_xattr_prefixes_cleanup(struct super_block *sb) {}
#else
int erofs_xattr_prefixes_init(struct super_block *sb);
void erofs_xattr_prefixes_cleanup(struct super_block *sb);
int erofs_getxattr(struct inode *, int, const char *, void *, size_t);
ssize_t erofs_listxattr(struct dentry *, char *, size_t);
#endif
#else
static inline int erofs_xattr_prefixes_init(struct super_block *sb) { return 0; }
static inline void erofs_xattr_prefixes_cleanup(struct super_block *sb) {}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
//! EROFS Rust Kernel Module Helpers Implementation
//! This is only for experimental purpose. Feedback is always welcome.
#[allow(dead_code)]
#[allow(missing_docs)]
pub(crate) mod rust;
use core::ffi::*;
use core::ptr::NonNull;
use kernel::bindings::{dentry, inode};
use kernel::container_of;
use rust::{erofs_sys::xattrs::*, kinode::*, ksuperblock::*};
/// Used as a replacement for erofs_getattr.
#[no_mangle]
pub unsafe extern "C" fn erofs_getxattr_rust(
k_inode: NonNull<inode>,
index: c_uint,
name: NonNull<u8>,
buffer: NonNull<u8>,
size: usize,
) -> c_int {
// SAFETY: super_block and superblockinfo is always initialized in k_inode.
let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() });
// SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called
let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) };
// SAFETY: buffer is always initialized in the caller and name is null terminated C string.
unsafe {
match sbi.filesystem.get_xattr(
erofs_inode,
index,
core::ffi::CStr::from_ptr(name.as_ptr().cast()).to_bytes(),
&mut Some(core::slice::from_raw_parts_mut(
buffer.as_ptr().cast(),
size,
)),
) {
Ok(value) => match value {
XAttrValue::Buffer(x) => x as c_int,
_ => unreachable!(),
},
Err(e) => i32::from(e) as c_int,
}
}
}
/// Used as a replacement for erofs_getattr_nobuf.
#[no_mangle]
pub unsafe extern "C" fn erofs_getxattr_nobuf_rust(
k_inode: NonNull<inode>,
index: u32,
name: NonNull<u8>,
mut value: NonNull<*mut u8>,
) -> c_int {
// SAFETY: super_block and superblockinfo is always initialized in k_inode.
let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() });
// SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called
let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) };
// SAFETY: buffer is always initialized in the caller and name is null terminated C string.
unsafe {
match sbi.filesystem.get_xattr(
erofs_inode,
index,
core::ffi::CStr::from_ptr(name.as_ptr().cast()).to_bytes(),
&mut None,
) {
Ok(xattr_value) => match xattr_value {
XAttrValue::Vec(v) => {
let rc = v.len() as c_int;
*value.as_mut() = v.leak().as_mut_ptr().cast();
rc
}
_ => unreachable!(),
},
Err(e) => i32::from(e) as c_int,
}
}
}
/// Used as a replacement for erofs_getattr.
#[no_mangle]
pub unsafe extern "C" fn erofs_listxattr_rust(
dentry: NonNull<dentry>,
buffer: NonNull<u8>,
size: usize,
) -> c_long {
// SAFETY: dentry is always initialized in the caller.
let k_inode = unsafe { dentry.as_ref().d_inode };
// SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called.
let erofs_inode = unsafe { &*container_of!(k_inode, KernelInode, k_inode) };
// SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called.
let sbi = erofs_sbi(unsafe { NonNull::new((*k_inode).i_sb).unwrap() });
match sbi.filesystem.list_xattrs(
erofs_inode,
// SAFETY: buffer is always initialized in the caller.
unsafe { core::slice::from_raw_parts_mut(buffer.as_ptr().cast(), size) },
) {
Ok(value) => value as c_long,
Err(e) => i32::from(e) as c_long,
}
}