mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-28 12:53:14 +01:00
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:
5 files changed
+148
-7
No files matched your search
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user