#include #include #include #include #include #include static struct kobject *example_kobj; static struct percpu_ref global_ref; static void global_ref_release(struct percpu_ref *) { printk("%s %d\n", __func__, __LINE__); } static ssize_t is_percpu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned long __percpu *percpu_count; return sysfs_emit(buf, "%d\n", __ref_is_percpu(&global_ref, &percpu_count)); } static struct kobj_attribute is_percpu_attribute = __ATTR_RO(is_percpu); static ssize_t is_dying_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", percpu_ref_is_dying(&global_ref)); } static struct kobj_attribute is_dying_attribute = __ATTR_RO(is_dying); static ssize_t is_zero_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", percpu_ref_is_zero(&global_ref)); } static struct kobj_attribute is_zero_attribute = __ATTR_RO(is_zero); static ssize_t is_atomic_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned long percpu_ptr = READ_ONCE(global_ref.percpu_count_ptr); return sysfs_emit(buf, "%d\n", percpu_ptr & __PERCPU_REF_ATOMIC); } static struct kobj_attribute is_atomic_attribute = __ATTR_RO(is_atomic); static ssize_t force_atomic_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", global_ref.data->force_atomic); } static struct kobj_attribute force_atomic_attribute = __ATTR_RO(force_atomic); static ssize_t kill_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { percpu_ref_kill(&global_ref); return count; } static struct kobj_attribute kill_attribute = __ATTR_WO(kill); static ssize_t resurrect_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { percpu_ref_resurrect(&global_ref); return count; } static struct kobj_attribute resurrect_attribute = __ATTR_WO(resurrect); static ssize_t switch_to_percpu_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { percpu_ref_switch_to_percpu(&global_ref); return count; } static struct kobj_attribute switch_to_percpu_attribute = __ATTR_WO(switch_to_percpu); static struct attribute *attrs[] = { &is_dying_attribute.attr, &is_zero_attribute.attr, &is_percpu_attribute.attr, &is_atomic_attribute.attr, &force_atomic_attribute.attr, &kill_attribute.attr, &resurrect_attribute.attr, &switch_to_percpu_attribute.attr, NULL, }; static struct attribute_group attr_group = { .attrs = attrs, }; static int __init example_init(void) { int retval; retval = percpu_ref_init(&global_ref, global_ref_release, PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); example_kobj = kobject_create_and_add("kobject_example", kernel_kobj); if (!example_kobj) return -ENOMEM; retval = sysfs_create_group(example_kobj, &attr_group); if (retval) kobject_put(example_kobj); return retval; } static void __exit example_exit(void) { kobject_put(example_kobj); } module_init(example_init); module_exit(example_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Greg Kroah-Hartman ");