projects/linux·commit d4d9eb22

Merge tag 'configfs-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/leitao/linux

d4d9eb22 · Linus Torvalds <[email protected]> · 2026-10-20 16:25:43 -10:00

Pull configfs updates from Breno Leitao:

 - Attribute structures can now be const (Thomas Weißschuh)

 - The first selftests for the configfs userspace interface, plus a
   sample subsystem that accepts symlinks to test against. They include
   a race of symlink(2) against rmdir of the target, which exercises the
   use-after-free fixed in v7.3-rc3.

 - Rust bindings, merged from Andreas Hindborg's signed tag: fix the
   data offset calculation in subsystem callbacks (marked for stable),
   add the missing Send and Sync bounds, and correct a safety comment.

* tag 'configfs-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/leitao/linux:
  samples: configfs: constify the configfs_attribute structures
  configfs: Allow the registration of const struct configfs_attribute
  configfs: Constify configfs_bin_attribute
  configfs: Treat attribute structures as const internally
  configfs: Constify is_visible/is_visible_bin in configfs_group_operations
  rust: configfs: remove mutability from some field initializers
  selftests/configfs: race symlink against rmdir of the target
  selftests/configfs: cover symlink and unlink
  samples/configfs: add a subsystem that accepts symlinks
  selftests/configfs: add tests for the userspace interface
  rust: configfs: fix data offset calculation for subsystem callbacks
  rust: configfs: require thread-safe callback data
  rust: configfs: fix release safety documentation
Commit
d4d9eb226e4c2af8ab390bb470477fa68072fa2a
Parents
32543b09 · 6c1fa55e

Merge commit. Changes below are compared with the first parent: 32543b09.

Changes

16 files changed · +771 −107

Only the first 600 diff lines are shown. Download the complete patch.

MAINTAINERS

View file
diff --git a/MAINTAINERS b/MAINTAINERS
index 7895e77..63a8878 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6603,6 +6603,7 @@ S: Supported
F: fs/configfs/
F: include/linux/configfs.h
F: samples/configfs/
+F: tools/testing/selftests/filesystems/configfs/
CONFIGFS [RUST]
M: Andreas Hindborg <[email protected]>

drivers/acpi/acpi_configfs.c

View file
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c
index 12ffec7..6071699 100644
--- a/drivers/acpi/acpi_configfs.c
+++ b/drivers/acpi/acpi_configfs.c
@@ -91,7 +91,7 @@ static ssize_t acpi_table_aml_read(struct config_item *cfg,
CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE);
-static struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
+static const struct configfs_bin_attribute *const acpi_table_bin_attrs[] = {
&acpi_table_attr_aml,
NULL,
};

drivers/gpu/drm/xe/xe_configfs.c

View file
diff --git a/drivers/gpu/drm/xe/xe_configfs.c b/drivers/gpu/drm/xe/xe_configfs.c
index 052cce9..842c180 100644
--- a/drivers/gpu/drm/xe/xe_configfs.c
+++ b/drivers/gpu/drm/xe/xe_configfs.c
@@ -886,7 +886,7 @@ static struct configfs_item_operations xe_config_device_ops = {
};
static bool xe_config_device_is_visible(struct config_item *item,
- struct configfs_attribute *attr, int n)
+ const struct configfs_attribute *attr, int n)
{
struct xe_config_group_device *dev = to_xe_config_group_device(item);
@@ -981,7 +981,7 @@ static struct configfs_attribute *xe_config_sriov_attrs[] = {
};
static bool xe_config_sriov_is_visible(struct config_item *item,
- struct configfs_attribute *attr, int n)
+ const struct configfs_attribute *attr, int n)
{
struct xe_config_group_device *dev = to_xe_config_group_device(item->ci_parent);

drivers/virt/coco/guest/report.c

View file
diff --git a/drivers/virt/coco/guest/report.c b/drivers/virt/coco/guest/report.c
index b254a14..ad400fb 100644
--- a/drivers/virt/coco/guest/report.c
+++ b/drivers/virt/coco/guest/report.c
@@ -356,7 +356,7 @@ static struct configfs_attribute *tsm_report_attrs[] = {
NULL,
};
-static struct configfs_bin_attribute *tsm_report_bin_attrs[] = {
+static const struct configfs_bin_attribute *const tsm_report_bin_attrs[] = {
[TSM_REPORT_INBLOB] = &tsm_report_attr_inblob,
[TSM_REPORT_OUTBLOB] = &tsm_report_attr_outblob,
[TSM_REPORT_AUXBLOB] = &tsm_report_attr_auxblob,
@@ -381,7 +381,7 @@ static struct configfs_item_operations tsm_report_item_ops = {
};
static bool tsm_report_is_visible(struct config_item *item,
- struct configfs_attribute *attr, int n)
+ const struct configfs_attribute *attr, int n)
{
guard(rwsem_read)(&tsm_rwsem);
if (!provider.ops)
@@ -394,7 +394,7 @@ static bool tsm_report_is_visible(struct config_item *item,
}
static bool tsm_report_is_bin_visible(struct config_item *item,
- struct configfs_bin_attribute *attr, int n)
+ const struct configfs_bin_attribute *attr, int n)
{
guard(rwsem_read)(&tsm_rwsem);
if (!provider.ops)

fs/configfs/configfs_internal.h

View file
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index 860f1b6..5f627e5 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -104,17 +104,17 @@ static inline struct config_item * to_item(struct dentry * dentry)
return ((struct config_item *) sd->s_element);
}
-static inline struct configfs_attribute * to_attr(struct dentry * dentry)
+static inline const struct configfs_attribute * to_attr(struct dentry * dentry)
{
struct configfs_dirent * sd = dentry->d_fsdata;
- return ((struct configfs_attribute *) sd->s_element);
+ return ((const struct configfs_attribute *) sd->s_element);
}
-static inline struct configfs_bin_attribute *to_bin_attr(struct dentry *dentry)
+static inline const struct configfs_bin_attribute *to_bin_attr(struct dentry *dentry)
{
- struct configfs_attribute *attr = to_attr(dentry);
+ const struct configfs_attribute *attr = to_attr(dentry);
- return container_of(attr, struct configfs_bin_attribute, cb_attr);
+ return container_of_const(attr, struct configfs_bin_attribute, cb_attr);
}
static inline struct config_item *configfs_get_config_item(struct dentry *dentry)

fs/configfs/dir.c

View file
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index f85b945..0c80fee 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -470,7 +470,7 @@ static struct dentry * configfs_lookup(struct inode *dir,
*/
if ((sd->s_type & CONFIGFS_NOT_PINNED) &&
!strcmp(configfs_get_name(sd), dentry->d_name.name)) {
- struct configfs_attribute *attr = sd->s_element;
+ const struct configfs_attribute *attr = sd->s_element;
umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
dentry->d_fsdata = configfs_get(sd);
@@ -631,8 +631,8 @@ static int populate_attrs(struct config_item *item)
{
const struct config_item_type *t = item->ci_type;
const struct configfs_group_operations *ops;
- struct configfs_attribute *attr;
- struct configfs_bin_attribute *bin_attr;
+ const struct configfs_attribute *attr;
+ const struct configfs_bin_attribute *bin_attr;
int error = 0;
int i;
@@ -641,8 +641,8 @@ static int populate_attrs(struct config_item *item)
ops = t->ct_group_ops;
- if (t->ct_attrs) {
- for (i = 0; (attr = t->ct_attrs[i]) != NULL; i++) {
+ if (t->ct_attrs_const) {
+ for (i = 0; (attr = t->ct_attrs_const[i]) != NULL; i++) {
if (ops && ops->is_visible && !ops->is_visible(item, attr, i))
continue;

fs/configfs/file.c

View file
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index a48cece..6460b00 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -41,8 +41,8 @@ struct configfs_buffer {
struct config_item *item;
struct module *owner;
union {
- struct configfs_attribute *attr;
- struct configfs_bin_attribute *bin_attr;
+ const struct configfs_attribute *attr;
+ const struct configfs_bin_attribute *bin_attr;
};
};
@@ -291,7 +291,7 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
{
struct dentry *dentry = file->f_path.dentry;
struct configfs_fragment *frag = to_frag(file);
- struct configfs_attribute *attr;
+ const struct configfs_attribute *attr;
struct configfs_buffer *buffer;
int error;

fs/configfs/inode.c

View file
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 6ba125d..c92a052 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -178,7 +178,7 @@ struct inode *configfs_create(struct dentry *dentry, umode_t mode)
*/
const unsigned char * configfs_get_name(struct configfs_dirent *sd)
{
- struct configfs_attribute *attr;
+ const struct configfs_attribute *attr;
BUG_ON(!sd || !sd->s_element);

include/linux/configfs.h

View file
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index ef65c75..5bead91 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -66,8 +66,11 @@ struct config_item_type {
struct module *ct_owner;
const struct configfs_item_operations *ct_item_ops;
const struct configfs_group_operations *ct_group_ops;
- struct configfs_attribute **ct_attrs;
- struct configfs_bin_attribute **ct_bin_attrs;
+ union {
+ struct configfs_attribute **ct_attrs;
+ const struct configfs_attribute *const *ct_attrs_const;
+ };
+ const struct configfs_bin_attribute *const *ct_bin_attrs;
};
/**
@@ -160,41 +163,41 @@ struct configfs_bin_attribute {
ssize_t (*write)(struct config_item *, const void *, size_t);
};
-#define CONFIGFS_BIN_ATTR(_pfx, _name, _priv, _maxsz) \
-static struct configfs_bin_attribute _pfx##attr_##_name = { \
- .cb_attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = S_IRUGO | S_IWUSR, \
- .ca_owner = THIS_MODULE, \
- }, \
- .cb_private = _priv, \
- .cb_max_size = _maxsz, \
- .read = _pfx##_name##_read, \
- .write = _pfx##_name##_write, \
+#define CONFIGFS_BIN_ATTR(_pfx, _name, _priv, _maxsz) \
+static const struct configfs_bin_attribute _pfx##attr_##_name = { \
+ .cb_attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IRUGO | S_IWUSR, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .cb_private = _priv, \
+ .cb_max_size = _maxsz, \
+ .read = _pfx##_name##_read, \
+ .write = _pfx##_name##_write, \
}
-#define CONFIGFS_BIN_ATTR_RO(_pfx, _name, _priv, _maxsz) \
-static struct configfs_bin_attribute _pfx##attr_##_name = { \
- .cb_attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = S_IRUGO, \
- .ca_owner = THIS_MODULE, \
- }, \
- .cb_private = _priv, \
- .cb_max_size = _maxsz, \
- .read = _pfx##_name##_read, \
+#define CONFIGFS_BIN_ATTR_RO(_pfx, _name, _priv, _maxsz) \
+static const struct configfs_bin_attribute _pfx##attr_##_name = { \
+ .cb_attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IRUGO, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .cb_private = _priv, \
+ .cb_max_size = _maxsz, \
+ .read = _pfx##_name##_read, \
}
-#define CONFIGFS_BIN_ATTR_WO(_pfx, _name, _priv, _maxsz) \
-static struct configfs_bin_attribute _pfx##attr_##_name = { \
- .cb_attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = S_IWUSR, \
- .ca_owner = THIS_MODULE, \
- }, \
- .cb_private = _priv, \
- .cb_max_size = _maxsz, \
- .write = _pfx##_name##_write, \
+#define CONFIGFS_BIN_ATTR_WO(_pfx, _name, _priv, _maxsz) \
+static const struct configfs_bin_attribute _pfx##attr_##_name = { \
+ .cb_attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IWUSR, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .cb_private = _priv, \
+ .cb_max_size = _maxsz, \
+ .write = _pfx##_name##_write, \
}
/*
@@ -220,8 +223,8 @@ struct configfs_group_operations {
struct config_group *(*make_group)(struct config_group *group, const char *name);
void (*disconnect_notify)(struct config_group *group, struct config_item *item);
void (*drop_item)(struct config_group *group, struct config_item *item);
- bool (*is_visible)(struct config_item *item, struct configfs_attribute *attr, int n);
- bool (*is_bin_visible)(struct config_item *item, struct configfs_bin_attribute *attr,
+ bool (*is_visible)(struct config_item *item, const struct configfs_attribute *attr, int n);
+ bool (*is_bin_visible)(struct config_item *item, const struct configfs_bin_attribute *attr,
int n);
};

rust/kernel/configfs.rs

View file
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index cd082b8..dbed728 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -135,8 +135,9 @@ pub struct Subsystem<Data> {
// SAFETY: We do not provide any operations on `Subsystem`.
unsafe impl<Data> Sync for Subsystem<Data> {}
-// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
-unsafe impl<Data> Send for Subsystem<Data> {}
+// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads
+// if its data can be transferred as well.
+unsafe impl<Data: Send> Send for Subsystem<Data> {}
impl<Data> Subsystem<Data> {
/// Create an initializer for a [`Subsystem`].
@@ -249,6 +250,13 @@ pub struct Group<Data> {
data: Data,
}
+// SAFETY: We do not provide any operations on `Group`.
+unsafe impl<Data> Sync for Group<Data> {}
+
+// SAFETY: Ownership of `Group` can safely be transferred to other threads if
+// its data can be transferred as well.
+unsafe impl<Data: Send> Send for Group<Data> {}
+
impl<Data> Group<Data> {
/// Create an initializer for a new group.
///
@@ -297,26 +305,39 @@ unsafe impl<Data> HasGroup<Data> for Group<Data> {
///
/// `this` must be a valid pointer.
///
-/// If `this` does not represent the root group of a configfs subsystem,
-/// `this` must be a pointer to a `bindings::config_group` embedded in a
-/// `Group<Parent>`.
+/// If `this` is the `su_group` field of a `bindings::configfs_subsystem`, that
+/// `configfs_subsystem` must be embedded in a `Subsystem<Parent>`.
///
-/// Otherwise, `this` must be a pointer to a `bindings::config_group` that
-/// is embedded in a `bindings::configfs_subsystem` that is embedded in a
-/// `Subsystem<Parent>`.
+/// Otherwise, `this` must be a pointer to a `bindings::config_group` embedded
+/// in a `Group<Parent>`.
unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
// SAFETY: `this` is a valid pointer.
- let is_root = unsafe { (*this).cg_subsys.is_null() };
+ let subsys = unsafe { (*this).cg_subsys };
+
+ // `link_group()` in `fs/configfs/dir.c` assigns `cg_subsys` for every
+ // `config_group` attached anywhere in a registered subsystem, including
+ // the subsystem's own `su_group` (which gets a pointer to itself). The
+ // only `config_group` with a NULL `cg_subsys` is the configfs root, and
+ // userspace cannot trigger callbacks on it. The group is therefore the
+ // subsystem's `su_group` iff it equals `&cg_subsys->su_group`.
+ let is_root = !subsys.is_null()
+ && core::ptr::eq(
+ this.cast_const(),
+ // SAFETY: For every `config_group` the configfs core dispatches a
+ // callback on, `cg_subsys` was set by `link_group()` at registration time
+ // and points to a valid `configfs_subsystem` that outlives the callback.
+ unsafe { &raw const (*subsys).su_group },
+ );
- if !is_root {
- // SAFETY: By C API contact,`this` was returned from a call to
- // `make_group`. The pointer is known to be embedded within a
- // `Group<Parent>`.
- unsafe { &(*Group::<Parent>::container_of(this)).data }
- } else {
- // SAFETY: By C API contract, `this` is a pointer to the
- // `bindings::config_group` field within a `Subsystem<Parent>`.
+ if is_root {
+ // SAFETY: By the above, `this` is the `su_group` field of a
+ // `configfs_subsystem` that, by function safety requirements, is
+ // embedded in a `Subsystem<Parent>`.
unsafe { &(*Subsystem::container_of(this)).data }
+ } else {
+ // SAFETY: By function safety requirements, `this` is a
+ // `config_group` embedded in a `Group<Parent>`.
+ unsafe { &(*Group::<Parent>::container_of(this)).data }
}
}
@@ -325,7 +346,9 @@ struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
impl<Parent, Child> GroupOperationsVTable<Parent, Child>
where
Parent: GroupOperations<Child = Child>,
- Child: 'static,
+ // We transfer `Arc<Group<Data>>` across a thread boundary in `make_group`
+ // and `drop_item`.
+ Arc<Group<Child>>: Send,
{
/// # Safety
///
@@ -344,8 +367,9 @@ where
this: *mut bindings::config_group,
name: *const kernel::ffi::c_char,
) -> *mut bindings::config_group {
- // SAFETY: By function safety requirements of this function, this call
- // is safe.
+ // SAFETY: By function safety requirements, `this` points to a configfs
+ // group containing `Parent`. The `GroupOperations` bound guarantees
+ // that `Parent: Sync`, so it is safe to share it with this thread.
let parent_data = unsafe { get_group_data(this) };
let group_init = match Parent::make_group(
@@ -390,8 +414,9 @@ where
this: *mut bindings::config_group,
item: *mut bindings::config_item,
) {
- // SAFETY: By function safety requirements of this function, this call
- // is safe.
+ // SAFETY: By function safety requirements, `this` points to a configfs
+ // group containing `Parent`. The `GroupOperations` bound guarantees
+ // that `Parent: Sync`, so it is safe to share it with this thread.
let parent_data = unsafe { get_group_data(this) };
// SAFETY: By function safety requirements, `item` is embedded in a
@@ -403,7 +428,9 @@ where
if Parent::HAS_DROP_ITEM {
// SAFETY: We called `into_raw` to produce `r_child_group_ptr` in
- // `make_group`.
+ // `make_group`. This function may be executing on a different
+ // thread than `into_raw`. As `Arc<Group<Child>>: Send` this
+ // ownership transfer is safe.
let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };
Parent::drop_item(parent_data, arc.as_arc_borrow());
@@ -434,11 +461,13 @@ struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
impl<Data> ItemOperationsVTable<Group<Data>, Data>
where
Data: 'static,
+ // We transfer `Arc<Group<Data>>` across a thread boundary in `release`.
+ Arc<Group<Data>>: Send,
{
/// # Safety
///
- /// `this` must be a pointer to a `bindings::config_group` embedded in a
- /// `Group<Parent>`.
+ /// `this` must be a pointer to the `cg_item` field of a `bindings::config_group` embedded in a
+ /// valid `Group<Data>`.
///
/// This function will destroy the pointee of `this`. The pointee of `this`
/// must not be accessed after the function returns.
@@ -450,8 +479,9 @@ where
// embedded within a `Group<Data>`.
let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };
- // SAFETY: We called `into_raw` on `r_group_ptr` in
- // `make_group`.
+ // SAFETY: We called `into_raw` on `r_group_ptr` in `make_group`. This
+ // function may be running on a different thread than the thread that
+ // called `into_raw`. As `Arc<Group<Data>>: Send`, this is safe.
let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };
drop(pin_self);
}
@@ -483,12 +513,12 @@ impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
///
/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].
#[vtable]
-pub trait GroupOperations {
+pub trait GroupOperations: Sync {
/// The child data object type.
///
/// This group will create subgroups (subdirectories) backed by this kind of
/// object.
- type Child: 'static;
+ type Child: 'static + Send;
/// Creates a new subgroup.
///
@@ -555,8 +585,10 @@ where
// `config_group`.
unsafe { container_of!(item, bindings::config_group, cg_item) };
- // SAFETY: The function safety requirements for this function satisfy
- // the conditions for this call.
+ // SAFETY: By function safety requirements, `c_group` points to a
+ // configfs group containing `Data`. The `AttributeOperations` bound
+ // guarantees that `Data: Sync`, so it is safe to share it with this
+ // thread.
let data: &Data = unsafe { get_group_data(c_group) };
// SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
@@ -589,8 +621,10 @@ where
// `config_group`.
unsafe { container_of!(item, bindings::config_group, cg_item) };
- // SAFETY: The function safety requirements for this function satisfy
- // the conditions for this call.
+ // SAFETY: By function safety requirements, `c_group` points to a
+ // configfs group containing `Data`. The `AttributeOperations` bound
+ // guarantees that `Data: Sync`, so it is safe to share it with this
+ // thread.
let data: &Data = unsafe { get_group_data(c_group) };
let ret = O::store(
@@ -643,7 +677,7 @@ where
pub trait AttributeOperations<const ID: u64 = 0> {
/// The type of the object that contains the field that is backing the
/// attribute for this operation.
- type Data;
+ type Data: Sync;
/// Renders the value of an attribute.
///
@@ -749,15 +783,18 @@ macro_rules! impl_item_type {
) -> Self
where
Data: GroupOperations<Child = Child>,
- Child: 'static,
+ Arc<Group<Child>>: Send,
+ Arc<Group<Data>>: Send,
{
Self {
item_type: Opaque::new(bindings::config_item_type {
ct_owner: owner.as_ptr(),
- ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
- ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
- ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
- ct_bin_attrs: core::ptr::null_mut(),
+ ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr(),
+ ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr(),
+ __bindgen_anon_1: bindings::config_item_type__bindgen_ty_1 {
+ ct_attrs_const: core::ptr::from_ref(attributes).cast(),
+ },
+ ct_bin_attrs: core::ptr::null(),
}),
_p: PhantomData,
}
@@ -767,14 +804,19 @@ macro_rules! impl_item_type {
pub const fn new<const N: usize>(
owner: &'static ThisModule,
attributes: &'static AttributeList<N, Data>,
- ) -> Self {
+ ) -> Self
+ where
+ Arc<Group<Data>>: Send,
+ {
Self {
item_type: Opaque::new(bindings::config_item_type {
ct_owner: owner.as_ptr(),
- ct_group_ops: core::ptr::null_mut(),
- ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
- ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
- ct_bin_attrs: core::ptr::null_mut(),
+ ct_group_ops: core::ptr::null(),
+ ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr(),
+ __bindgen_anon_1: bindings::config_item_type__bindgen_ty_1 {
+ ct_attrs_const: core::ptr::from_ref(attributes).cast(),
+ },
+ ct_bin_attrs: core::ptr::null(),
}),
_p: PhantomData,
}

samples/configfs/configfs_sample.c

View file
diff --git a/samples/configfs/configfs_sample.c b/samples/configfs/configfs_sample.c
index c1b108e..6e3a8e0 100644
--- a/samples/configfs/configfs_sample.c
+++ b/samples/configfs/configfs_sample.c
@@ -84,7 +84,7 @@ CONFIGFS_ATTR_RO(childless_, showme);
CONFIGFS_ATTR(childless_, storeme);
CONFIGFS_ATTR_RO(childless_, description);
-static struct configfs_attribute *childless_attrs[] = {
+static const struct configfs_attribute *const childless_attrs[] = {
&childless_attr_showme,
&childless_attr_storeme,
&childless_attr_description,
@@ -92,7 +92,7 @@ static struct configfs_attribute *childless_attrs[] = {
};
static const struct config_item_type childless_type = {
- .ct_attrs = childless_attrs,
+ .ct_attrs_const = childless_attrs,
.ct_owner = THIS_MODULE,
};
@@ -148,7 +148,7 @@ static ssize_t simple_child_storeme_store(struct config_item *item,
CONFIGFS_ATTR(simple_child_, storeme);
-static struct configfs_attribute *simple_child_attrs[] = {
+static const struct configfs_attribute *const simple_child_attrs[] = {
&simple_child_attr_storeme,
NULL,
};
@@ -164,7 +164,7 @@ static const struct configfs_item_operations simple_child_item_ops = {
static const struct config_item_type simple_child_type = {
.ct_item_ops = &simple_child_item_ops,
- .ct_attrs = simple_child_attrs,
+ .ct_attrs_const = simple_child_attrs,
.ct_owner = THIS_MODULE,
};
@@ -205,7 +205,7 @@ static ssize_t simple_children_description_show(struct config_item *item,
CONFIGFS_ATTR_RO(simple_children_, description);
-static struct configfs_attribute *simple_children_attrs[] = {
+static const struct configfs_attribute *const simple_children_attrs[] = {
&simple_children_attr_description,
NULL,
};
@@ -230,7 +230,7 @@ static const struct configfs_group_operations simple_children_group_ops = {
static const struct config_item_type simple_children_type = {
.ct_item_ops = &simple_children_item_ops,
.ct_group_ops = &simple_children_group_ops,
- .ct_attrs = simple_children_attrs,
+ .ct_attrs_const = simple_children_attrs,
.ct_owner = THIS_MODULE,
};
@@ -283,7 +283,7 @@ static ssize_t group_children_description_show(struct config_item *item,
CONFIGFS_ATTR_RO(group_children_, description);
-static struct configfs_attribute *group_children_attrs[] = {

This diff is incomplete. Download the complete patch.

tools/testing/selftests/Makefile

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/filesystems/configfs/.gitignore

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/filesystems/configfs/Makefile

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/filesystems/configfs/config

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/filesystems/configfs/configfs_test.c

View file

This diff is incomplete. Download the complete patch.